1from numbers import Number 2import math 3import operator 4import warnings 5 6 7__all__ = ["Vector"] 8 9 10class Vector(tuple): 11 12 """A math-like vector. 13 14 Represents an n-dimensional numeric vector. ``Vector`` objects support 15 vector addition and subtraction, scalar multiplication and division, 16 negation, rounding, and comparison tests. 17 """ 18 19 __slots__ = () 20 21 def __new__(cls, values, keep=False): 22 if keep is not False: 23 warnings.warn( 24 "the 'keep' argument has been deprecated", 25 DeprecationWarning, 26 ) 27 if type(values) == Vector: 28 # No need to create a new object 29 return values 30 return super().__new__(cls, values) 31 32 def __repr__(self): 33 return f"{self.__class__.__name__}({super().__repr__()})" 34 35 def _vectorOp(self, other, op): 36 if isinstance(other, Vector): 37 assert len(self) == len(other) 38 return self.__class__(op(a, b) for a, b in zip(self, other)) 39 if isinstance(other, Number): 40 return self.__class__(op(v, other) for v in self) 41 raise NotImplementedError() 42 43 def _scalarOp(self, other, op): 44 if isinstance(other, Number): 45 return self.__class__(op(v, other) for v in self) 46 raise NotImplementedError() 47 48 def _unaryOp(self, op): 49 return self.__class__(op(v) for v in self) 50 51 def __add__(self, other): 52 return self._vectorOp(other, operator.add) 53 54 __radd__ = __add__ 55 56 def __sub__(self, other): 57 return self._vectorOp(other, operator.sub) 58 59 def __rsub__(self, other): 60 return self._vectorOp(other, _operator_rsub) 61 62 def __mul__(self, other): 63 return self._scalarOp(other, operator.mul) 64 65 __rmul__ = __mul__ 66 67 def __truediv__(self, other): 68 return self._scalarOp(other, operator.truediv) 69 70 def __rtruediv__(self, other): 71 return self._scalarOp(other, _operator_rtruediv) 72 73 def __pos__(self): 74 return self._unaryOp(operator.pos) 75 76 def __neg__(self): 77 return self._unaryOp(operator.neg) 78 79 def __round__(self, *, round=round): 80 return self._unaryOp(round) 81 82 def __eq__(self, other): 83 if isinstance(other, list): 84 # bw compat Vector([1, 2, 3]) == [1, 2, 3] 85 other = tuple(other) 86 return super().__eq__(other) 87 88 def __ne__(self, other): 89 return not self.__eq__(other) 90 91 def __bool__(self): 92 return any(self) 93 94 __nonzero__ = __bool__ 95 96 def __abs__(self): 97 return math.sqrt(sum(x * x for x in self)) 98 99 def length(self): 100 """Return the length of the vector. Equivalent to abs(vector).""" 101 return abs(self) 102 103 def normalized(self): 104 """Return the normalized vector of the vector.""" 105 return self / abs(self) 106 107 def dot(self, other): 108 """Performs vector dot product, returning the sum of 109 ``a[0] * b[0], a[1] * b[1], ...``""" 110 assert len(self) == len(other) 111 return sum(a * b for a, b in zip(self, other)) 112 113 # Deprecated methods/properties 114 115 def toInt(self): 116 warnings.warn( 117 "the 'toInt' method has been deprecated, use round(vector) instead", 118 DeprecationWarning, 119 ) 120 return self.__round__() 121 122 @property 123 def values(self): 124 warnings.warn( 125 "the 'values' attribute has been deprecated, use " 126 "the vector object itself instead", 127 DeprecationWarning, 128 ) 129 return list(self) 130 131 @values.setter 132 def values(self, values): 133 raise AttributeError( 134 "can't set attribute, the 'values' attribute has been deprecated", 135 ) 136 137 138def _operator_rsub(a, b): 139 return operator.sub(b, a) 140 141 142def _operator_rtruediv(a, b): 143 return operator.truediv(b, a) 144