Source code for easy_vector.vector

import math

try:
    import numpy as np
except:
    np = False

[docs]def add_angle(angle, angle2): angle += angle2 if angle < 0: angle += 360 elif angle > 360: angle -= 360 return
[docs]def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
[docs]class Vector(object):
[docs] @staticmethod def fromLA(length, angle): x = length * math.cos(angle * math.pi / 180) y = length * math.sin(angle * math.pi / 180) return Vector(x, y)
polar = fromLA def __init__(self, *args): # first arg may be an iterable (list, tuple, etc...) if len(args) == 1 and hasattr(args[0], "__iter__"): self.coords = list(args[0]) else: # convert `args` tuple to list self.coords = list(args) if len(self.coords) > 0: self.x = self.coords[0] if len(self.coords) > 1: self.y = self.coords[1] if len(self.coords) > 2: self.z = self.coords[2] def __iter__(self): return iter(self.coords) def __len__(self): return len(self.coords) def __getitem__(self, index): return self.coords[index] def __setitem__(self, index, value): self.coords[index] = value def __eq__(self, other): return all(isclose(a,b) for a,b in zip(self, other)) def __neg__(self): return self * -1 def __add__(self, other): return Vector(a + b for a, b in zip(self, other)) def __radd__(self, other): return self.__add__(self, other) def __sub__(self, other): # add the negative of `other` return self + (-other) #def __rsub__(self, other): # # SomeNotVector - Vector IS NOT POSSIBLE # return NotImplemented def __mul__(self, other): # vector * scalar if isinstance(other, (int, float)): return Vector(a * other for a in self) # vector * vector elif isinstance(other, self.__class__): return Vector(a * b for a, b in zip(self, other)) # vector * iterable (not vector) elif hasattr(other, "__iter__"): return self * Vector(other) else: return NotImplemented def __rmul__(self, other): return self.__mul__(other) def __truediv__(self, other): # vector / scalar if isinstance(other, (int, float)): return Vector(a / float(other) for a in self) # vector / vector elif isinstance(other, self.__class__): return Vector(a / b for a, b in zip(self, other)) # vector / iterable (not vector) elif hasattr(other, "__iter__"): return self / Vector(other) else: return NotImplemented def __rtruediv__(self, other): # scalar / vector if isinstance(other, (int, float)): return Vector(float(other) / a for a in self) # vector / vector case is always handled by __truediv__ # iterable (not vector) / vector elif hasattr(other, "__iter__"): return Vector(other) / self else: return NotImplemented __div__ = __truediv__ def __pow__(self, power): return Vector(a ** power for a in self) # ##################################### # THESE ALREADY WORK AND ARE NOT NEEDED # ##################################### # def __list__(self): # pass # # def __tuple__(self): # pass @property def nparray(self): return np.array(self.coords) if np else NotImplemented @property def length(self): length = 0 for c in self.coords: length += c**2 return math.sqrt(length) @property def angle(self, allow_negative=True, quadrants=True): if len(self.coords) == 2: angle = math.atan(float(self.y) / self.x) * 180 / math.pi if not allow_negative: if angle < 0: angle += 360 # if quadrants: # if self.x < 0: # if self.y < 0: # Quadrant III # if angle < 0 or angle > 180: # add_angle(angle, 180) # else: # Quadrant II # if angle < 0 or angle > 180: # add_angle(angle, 180) # else: # if self.y < 0: # Quadrant IV # if angle # else: # Quadrant I return angle # else: # if angle < 0: # if self.x < 0 and self.y > 0: @property def normal(self): return self / self.length # String representation def _repr_la(self): return "{0:.3f} @ {1:.3f} degrees".format(self.length, self.angle) def _repr_cmp(self): return "Vector[{0}]".format(",".join("{0:.3f}".format(c) for c in self)) def __repr__(self): return self._repr_cmp()
[docs]def dot(v1, v2): return sum(v1*v2)
[docs]def angle(v1, v2): return math.acos(dot(v1,v2) / (v1.length * v2.length)) * 180 / math.pi