from math import *
from functools import wraps
################################################################################
def autocast(method): # Optional method decorator
@wraps(method)
def wrapper(self, obj):
try:
return method(self, self.__class__(*obj))
except TypeError:
return method(self, obj)
return wrapper
################################################################################
def Polar2(magnitude, degrees):
x = magnitude * sin(radians(degrees))
y = magnitude * cos(radians(degrees))
return Vector2(x, y)
################################################################################
class Vector2:
__slots__ = 'x', 'y'
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Vector2({!r}, {!r})'.format(self.x, self.y)
def polar_repr(self):
x, y = self.x, self.y
magnitude = hypot(x, y)
angle = degrees(atan2(x, y)) % 360
return 'Polar2({!r}, {!r})'.format(magnitude, angle)
# Rich Comparison Methods
def __lt__(self, obj):
if isinstance(obj, Vector2):
x1, y1, x2, y2 = self.x, self.y, obj.x, obj.y
return x1 * x1 + y1 * y1 < x2 * x2 + y2 * y2
return hypot(self.x, self.y) < obj
def __le__(self, obj):
if isinstance(obj, Vector2):
x1, y1, x2, y2 = self.x, self.y, obj.x, obj.y
return x1 * x1 + y1 * y1 <= x2 * x2 + y2 * y2
return hypot(self.x, self.y) <= obj
def __eq__(self, obj):
if isinstance(obj, Vector2):
return self.x == obj.x and self.y == obj.y
return hypot(self.x, self.y) == obj
def __ne__(self, obj):
if isinstance(obj, Vector2):
return self.x != obj.x or self.y != obj.y
return hypot(self.x, self.y) != obj
def __gt__(self, obj):
if isinstance(obj, Vector2):
x1, y1, x2, y2 = self.x, self.y, obj.x, obj.y
return x1 * x1 + y1 * y1 > x2 * x2 + y2 * y2
return hypot(self.x, self.y) > obj
def __ge__(self, obj):
if isinstance(obj, Vector2):
x1, y1, x2, y2 = self.x, self.y, obj.x, obj.y
return x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2
return hypot(self.x, self.y) >= obj
# Boolean Operation
def __bool__(self):
return self.x != 0 or self.y != 0
# Container Methods
def __len__(self):
return 2
def __getitem__(self, index):
return (self.x, self.y)[index]
def __setitem__(self, index, value):
temp = [self.x, self.y]
temp[index] = value
self.x, self.y = temp
def __iter__(self):
yield self.x
yield self.y
def __reversed__(self):
yield self.y
yield self.x
def __contains__(self, obj):
return obj in (self.x, self.y)
# Binary Arithmetic Operations
def __add__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x + obj.x, self.y + obj.y)
return Vector2(self.x + obj, self.y + obj)
def __sub__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x - obj.x, self.y - obj.y)
return Vector2(self.x - obj, self.y - obj)
def __mul__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x * obj.x, self.y * obj.y)
return Vector2(self.x * obj, self.y * obj)
def __truediv__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x / obj.x, self.y / obj.y)
return Vector2(self.x / obj, self.y / obj)
def __floordiv__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x // obj.x, self.y // obj.y)
return Vector2(self.x // obj, self.y // obj)
def __mod__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x % obj.x, self.y % obj.y)
return Vector2(self.x % obj, self.y % obj)
def __divmod__(self, obj):
if isinstance(obj, Vector2):
return (Vector2(self.x // obj.x, self.y // obj.y),
Vector2(self.x % obj.x, self.y % obj.y))
return (Vector2(self.x // obj, self.y // obj),
Vector2(self.x % obj, self.y % obj))
def __pow__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x ** obj.x, self.y ** obj.y)
return Vector2(self.x ** obj, self.y ** obj)
def __lshift__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x << obj.x, self.y << obj.y)
return Vector2(self.x << obj, self.y << obj)
def __rshift__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x >> obj.x, self.y >> obj.y)
return Vector2(self.x >> obj, self.y >> obj)
def __and__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x & obj.x, self.y & obj.y)
return Vector2(self.x & obj, self.y & obj)
def __xor__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x ^ obj.x, self.y ^ obj.y)
return Vector2(self.x ^ obj, self.y ^ obj)
def __or__(self, obj):
if isinstance(obj, Vector2):
return Vector2(self.x | obj.x, self.y | obj.y)
return Vector2(self.x | obj, self.y | obj)
# Binary Arithmetic Operations (with reflected operands)
def __radd__(self, obj):
return Vector2(obj + self.x, obj + self.y)
def __rsub__(self, obj):
return Vector2(obj - self.x, obj - self.y)
def __rmul__(self, obj):
return Vector2(obj * self.x, obj * self.y)
def __rtruediv__(self, obj):
return Vector2(obj / self.x, obj / self.y)
def __rfloordiv__(self, obj):
return Vector2(obj // self.x, obj // self.y)
def __rmod__(self, obj):
return Vector2(obj % self.x, obj % self.y)
def __rdivmod__(self, obj):
return (Vector2(obj // self.x, obj // self.y),
Vector2(obj % self.x, obj % self.y))
def __rpow__(self, obj):
return Vector2(obj ** self.x, obj ** self.y)
def __rlshift__(self, obj):
return Vector2(obj << self.x, obj << self.y)
def __rrshift__(self, obj):
return Vector2(obj >> self.x, obj >> self.y)
def __rand__(self, obj):
return Vector2(obj & self.x, obj & self.y)
def __rxor__(self, obj):
return Vector2(obj ^ self.x, obj ^ self.y)
def __ror__(self, obj):
return Vector2(obj | self.x, obj | self.y)
# Augmented Arithmetic Assignments
def __iadd__(self, obj):
if isinstance(obj, Vector2):
self.x += obj.x
self.y += obj.y
else:
self.x += obj
self.y += obj
return self
def __isub__(self, obj):
if isinstance(obj, Vector2):
self.x -= obj.x
self.y -= obj.y
else:
self.x -= obj
self.y -= obj
return self
def __imul__(self, obj):
if isinstance(obj, Vector2):
self.x *= obj.x
self.y *= obj.y
else:
self.x *= obj
self.y *= obj
return self
def __itruediv__(self, obj):
if isinstance(obj, Vector2):
self.x /= obj.x
self.y /= obj.y
else:
self.x /= obj
self.y /= obj
return self
def __ifloordiv__(self, obj):
if isinstance(obj, Vector2):
self.x //= obj.x
self.y //= obj.y
else:
self.x //= obj
self.y //= obj
return self
def __imod__(self, obj):
if isinstance(obj, Vector2):
self.x %= obj.x
self.y %= obj.y
else:
self.x %= obj
self.y %= obj
return self
def __ipow__(self, obj):
if isinstance(obj, Vector2):
self.x **= obj.x
self.y **= obj.y
else:
self.x **= obj
self.y **= obj
return self
def __ilshift__(self, obj):
if isinstance(obj, Vector2):
self.x <<= obj.x
self.y <<= obj.y
else:
self.x <<= obj
self.y <<= obj
return self
def __irshift__(self, obj):
if isinstance(obj, Vector2):
self.x >>= obj.x
self.y >>= obj.y
else:
self.x >>= obj
self.y >>= obj
return self
def __iand__(self, obj):
if isinstance(obj, Vector2):
self.x &= obj.x
self.y &= obj.y
else:
self.x &= obj
self.y &= obj
return self
def __ixor__(self, obj):
if isinstance(obj, Vector2):
self.x ^= obj.x
self.y ^= obj.y
else:
self.x ^= obj
self.y ^= obj
return self
def __ior__(self, obj):
if isinstance(obj, Vector2):
self.x |= obj.x
self.y |= obj.y
else:
self.x |= obj
self.y |= obj
return self
# Unary Arithmetic Operations
def __pos__(self):
return Vector2(+self.x, +self.y)
def __neg__(self):
return Vector2(-self.x, -self.y)
def __invert__(self):
return Vector2(~self.x, ~self.y)
def __abs__(self):
return Vector2(abs(self.x), abs(self.y))
# Virtual "magnitude" Attribute
def __fg_ma(self):
return hypot(self.x, self.y)
def __fs_ma(self, value):
x, y = self.x, self.y
temp = value / hypot(x, y)
self.x, self.y = x * temp, y * temp
magnitude = property(__fg_ma, __fs_ma, doc='Virtual "magnitude" Attribute')
# Virtual "direction" Attribute
def __fg_di(self):
return atan2(self.y, self.x)
def __fs_di(self, value):
temp = hypot(self.x, self.y)
self.x, self.y = cos(value) * temp, sin(value) * temp
direction = property(__fg_di, __fs_di, doc='Virtual "direction" Attribute')
# Virtual "degrees" Attribute
def __fg_de(self):
return degrees(atan2(self.x, self.y)) % 360
def __fs_de(self, value):
temp = hypot(self.x, self.y)
self.x, self.y = sin(radians(value)) * temp, cos(radians(value)) * temp
degrees = property(__fg_de, __fs_de, doc='Virtual "degrees" Attribute')
# Virtual "xy" Attribute
def __fg_xy(self):
return self.x, self.y
def __fs_xy(self, value):
self.x, self.y = value
xy = property(__fg_xy, __fs_xy, doc='Virtual "xy" Attribute')
# Virtual "yx" Attribute
def __fg_yx(self):
return self.y, self.x
def __fs_yx(self, value):
self.y, self.x = value
yx = property(__fg_yx, __fs_yx, doc='Virtual "yx" Attribute')
# Unit Vector Operations
def unit_vector(self):
x, y = self.x, self.y
temp = hypot(x, y)
return Vector2(x / temp, y / temp)
def normalize(self):
x, y = self.x, self.y
temp = hypot(x, y)
self.x, self.y = x / temp, y / temp
return self
# Vector Multiplication Operations
def dot_product(self, vec):
return self.x * vec.x + self.y * vec.y
def cross_product(self, vec):
return self.x * vec.y - self.y * vec.x
# Geometric And Physical Reflections
def reflect(self, vec):
x1, y1, x2, y2 = self.x, self.y, vec.x, vec.y
temp = 2 * (x1 * x2 + y1 * y2) / (x2 * x2 + y2 * y2)
return Vector2(x2 * temp - x1, y2 * temp - y1)
def bounce(self, vec):
x1, y1, x2, y2 = self.x, self.y, +vec.y, -vec.x
temp = 2 * (x1 * x2 + y1 * y2) / (x2 * x2 + y2 * y2)
return Vector2(x2 * temp - x1, y2 * temp - y1)
# Standard Vector Operations
def project(self, vec):
x, y = vec.x, vec.y
temp = (self.x * x + self.y * y) / (x * x + y * y)
return Vector2(x * temp, y * temp)
def rotate(self, vec):
x1, y1, x2, y2 = self.x, self.y, vec.x, vec.y
return Vector2(x1 * x2 + y1 * y2, y1 * x2 - x1 * y2)
def interpolate(self, vec, bias):
a = 1 - bias
return Vector2(self.x * a + vec.x * bias, self.y * a + vec.y * bias)
# Other Useful Methods
def near(self, vec, dist):
x, y = self.x, self.y
return x * x + y * y <= dist * dist
def perpendicular(self):
return Vector2(+self.y, -self.x)
def subset(self, vec1, vec2):
x1, x2 = vec1.x, vec2.x
if x1 <= x2:
if x1 <= self.x <= x2:
y1, y2 = vec1.y, vec2.y
if y1 <= y2:
return y1 <= self.y <= y2
return y2 <= self.y <= y1
else:
if x2 <= self.x <= x1:
y1, y2 = vec1.y, vec2.y
if y1 <= y2:
return y1 <= self.y <= y2
return y2 <= self.y <= y1
return False
# Synonymous Definitions
copy = __pos__
inverse = __neg__
unit = unit_vector
dot = dot_product
cross = cross_product
lerp = interpolate
perp = perpendicular