import math class R2Vector: eps = 1e-14 def __init__(self, x = 0.0, y = 0.0): if type(x) == list or type(x) == tuple: self.x = x[0] self.y = x[1] elif type(x) == R2Vector: self.x = x.x self.y = x.y else: self.x = float(x) self.y = float(y) def __str__(self): return "(" + str(self.x) + ", " + str(self.y) + ")" def __repr__(self): return "R2Vector(" + str(self.x) + ", " + str(self.y) + ")" def copy(self): '''Shallow copy of a vector''' return R2Vector(self.x, self.y) def __add__(self, v): '''Sum of vectors''' # w = u + v return R2Vector(self.x + v.x, self.y + v.y) def __iadd__(self, v): '''In-place sum of vectors''' # u += v self.x += v.x self.y += v.y return self def __sub__(self, v): '''Subtract vectors''' # w = u - v return R2Vector(self.x - v.x, self.y - v.y) def __isub__(self, v): '''In-place subtraction of vectors''' # u -= v self.x -= v.x self.y -= v.y return self def __neg__(self): '''Change a sign of vector''' # v = -u return R2Vector(-self.x, -self.y) def __mul__(self, v): # self*v '''Dot-product of vectors or multiply a vector by a number''' if type(v) == R2Vector: return self.x*v.x + self.y*v.y else: c = float(v) return R2Vector(self.x*c, self.y*c) def __rmul__(self, v): # v*self '''Reverse multiplication''' if type(v) == R2Vector: return v.x*self.x + v.y*self.y else: c = float(v) return R2Vector(c*self.x, c*self.y) def __imul__(self, c): # v *= c a = float(c) self.x *= a self.y *= a return self def __getitem__(self, idx): if idx == 0: return self.x elif idx == 1: return self.y else: raise IndexError("Vector index out of range") def __setitem__(self, idx, value): if idx == 0: self.x = value elif idx == 1: self.y = value else: raise IndexError("Vector index out of range") def norm(self): return (x*x + y*y)**0.5 def length(self): return self.norm() def normal(self): return R2Vector(-self.y, self.x) def normalized(self): l = self.norm() if l <= 0.0: return self.copy() else: return self*(1.0/l) def normalize(self): l = self.norm() if l > 0.0: self.x /= l self.y /= l return self def angle(self, v): '''Signed angle between two vectors''' n = self.normal() x = v*self y = v*n return math.atan2(y, x) def signedArea(self, v): '''Signed area of parallelogram spanned on two vectors''' return self.x*v.y - self.y*v.x; def area(self, v): '''Area of parallelogram spanned on two vectors''' return abs(self.signedArea(v)) @staticmethod def angleBetweenVectors(u, v): return u.angle(v) @staticmethod def areaOfParallelogram(u, v): return u.area(v)