Source code for vulk.math.vector

'''Vector module

This module contains all Vector classes definition.
Vector are a key of graphic computing.
'''
import numpy as np
from numpy import linalg


[docs]class Vector(): '''Base class for Vector *Exemple:* ``` v1 += 10 # Add 10 to all components v1 += [10, 9, 8] # Add a different value to each component dot_product = v1 @ v2 # Dot product use the matmul operator ``` **Note: Vector is just a wrapper around a numpy array. You can get directly the numpy array if you need more power** ''' def __init__(self, values): ''' *Parameters:* - `values`: `list` of `float` ''' self._values = np.fromiter(values, dtype=np.float32, count=len(values)) def __iter__(self): return iter(self._values) def __len__(self): return len(self._values) def __add__(self, value): self._values += value return self def __iadd__(self, value): return self.__add__(value) def __sub__(self, value): self._values -= value return self def __isub__(self, value): return self.__sub__(value) def __mul__(self, value): self._values *= value return self def __imul__(self, value): return self.__mul__(value) def __matmul__(self, value): return self._values @ value def __imatmul__(self, value): return self.__matmul__(value) def __truediv__(self, value): self._values /= value return self def __itruediv__(self, value): return self.__truediv__(value) def __str__(self): return str(self._values) def __eq__(self, other): return all(self._values == other.values) def __copy__(self): return self.__class__(self._values) @property def values(self): return self._values @values.setter def values(self, values): self._values[:] = values @property def size(self): ''' Return the size of vector ''' return linalg.norm(self._values)
[docs] def nor(self): '''Normalize the vector and return it for chaining''' return self * (1 / self.size)
[docs] def crs(self, vector): '''Return the cross product between the two vectors *Parameters:* - `vector`: `Vector` of the same size ''' return self.crs2(vector.values)
[docs] def crs2(self, values): '''Set this vector to the cross product with `values` *Parameters:* - `values`: `list` of 3 float ''' self._values[:] = np.cross(self._values, values) return self
[docs] def sub(self, vector): ''' Substract vector from this vector *Parameters:* - `vector`: `Vector3` ''' return self.sub2(vector.values)
[docs] def sub2(self, values): ''' Substract values from this vector *Parameters:* - `values`: `list` of `float` ''' self._values -= values return self
[docs] def add(self, vector): ''' Add vector to this vector *Parameters:* - `vector`: `Vector3` ''' return self.add2(vector.values)
[docs] def add2(self, values): ''' Add values to this vector *Parameters:* - `values`: `list` of `float` ''' self._values += values return self
[docs]class XMixin(): '''Mixin adding `x` property to class''' @property def x(self): return self._values[0] @x.setter def x(self, value): self._values[0] = value
[docs]class YMixin(): '''Mixin adding `y` property to class''' @property def y(self): return self._values[1] @y.setter def y(self, value): self._values[1] = value
[docs]class ZMixin(): '''Mixin adding `z` property to class''' @property def z(self): return self._values[2] @z.setter def z(self, value): self._values[2] = value
[docs]class WMixin(): '''Mixin adding `w` property to class''' @property def w(self): return self._values[3] @w.setter def w(self, value): self._values[3] = value
[docs]class Vector2(Vector, XMixin, YMixin): '''Vector2 class represents a Vector in 2D space. It has two components `x` and `y`. ''' X = None Y = None Zero = None def __init__(self, values=None): ''' *Parameters:* - `values`: `list` of 2 `float` ''' if not values: super().__init__([0, 0]) elif len(values) == 2: super().__init__(values) else: raise ValueError("Vector2 needs 2 components")
[docs]class Vector3(Vector, XMixin, YMixin, ZMixin): '''Vector3 class represents a Vector in 3D space. It has three components `x`, `y` and `z`. ''' X = None Y = None Z = None Zero = None def __init__(self, values=None): ''' *Parameters:* - `values`: `list` of 3 `float` ''' if not values: super().__init__([0, 0, 0]) elif len(values) == 3: super().__init__(values) else: raise ValueError("Vector3 needs 3 components") # tmp properties used during computation self.tmp_v4 = Vector4()
[docs] def mul(self, vector): '''Multiply this vector by `vector`. *Parameters:* - `vector`: `Vector3` ''' # TODO: To test and valid self._values *= vector.values
[docs] def mul2(self, matrix): '''Multiply this vector by a `Matrix4` *Parameters:* - `matrix`: `Matrix4` ''' self.tmp_v4.set2(self).mul2(matrix) self._values[:] = self.tmp_v4.values[0:3] return self
[docs] def prj(self, matrix): ''' Project this vector to the `matrix` parameter. It's just a multiplication followed by a division by w. *Parameters:* - `matrix`: `Matrix4` ''' self.tmp_v4.set2(self).mul2(matrix).norw() self._values[:] = self.tmp_v4.values[0:3]
[docs] def set(self, x, y, z): '''Set values of this vector *Parameters:* - `x`, `y`, `z`: `float` ''' self._values[0] = x self._values[1] = y self._values[2] = z
[docs] def set2(self, vector): '''Set values of this vector *Parameters:* - `vector`: `Vector3` ''' self.set(vector.x, vector.y, vector.z)
[docs]class Vector4(Vector, XMixin, YMixin, ZMixin, WMixin): '''Vector4 class represents a Vector in 3D space. It has four components `x`, `y`, `z`, `w`. ''' def __init__(self, values=None): ''' *Parameters:* - `values`: `list` of 4 `float` ''' if not values: super().__init__([0, 0, 0, 0]) elif len(values) == 4: super().__init__(values) else: raise ValueError("Vector4 needs 4 components") # tmp properties used during computation self.tmp = np.zeros(4, dtype=np.float32)
[docs] def set(self, vector): '''Set this `Vector4` to `vector`. *Parameters:* - `vector`: `Vector4` ''' self._values[:] = vector.values return self
[docs] def set2(self, vector): '''Set this `Vector4` to `vector` and set `w` to 1. *Parameters:* - `vector`: `Vector3` ''' self._values[0:3] = vector.values self._values[3] = 1. return self
[docs] def mul(self, vector): '''Multiply this vector by `vector`. *Parameters:* - `vector`: `Vector4` ''' # TODO: To test and valid self._values *= vector.values return self
[docs] def mul2(self, matrix): '''Multiply this vector by a `Matrix4` *Parameters:* - `matrix`: `Matrix4` ''' # load matrix in column order (default is row order) # reshape returns a view (I hope!) mv = np.reshape(matrix.values, (4, 4), order='F') np.dot(mv, self._values, out=self.tmp) self._values[:] = self.tmp return self
[docs] def norw(self): ''' W normalization of this vector. All components are divided by w, w must not be 0. ''' self._values[0:3] /= self.w
# Vector2 constants Vector2.X = Vector2([1, 0]) Vector2.Y = Vector2([0, 1]) Vector2.Zero = Vector2([0, 0]) # Vector3 constants Vector3.X = Vector3([1, 0, 0]) Vector3.Y = Vector3([0, 1, 0]) Vector3.Z = Vector3([0, 0, 1]) Vector3.Zero = Vector3([0, 0, 0])