Module generativepy.math
Functions
def isclose(a, b, rel_tol=1e-09, abs_tol=1e-12)
-
Check if two values a and b are equal to within a given tolerance
Args
a
- number - First value
b
- number - Second value
rel_tol
- number - Tolerance as a fraction of the absolute value of a or b (whichever is largest)
abs_tol
- number - Tolerance as an absolute value
Returns
True if the numbers are close, false otherwise.
Classes
class Matrix (xx, xy, xt, yx, yy, yt)
-
Class to represent a 2D transform matrix:
| xx xy xt | | yx yy yt |
Expand source code
class Matrix(): """ Class to represent a 2D transform matrix: ``` | xx xy xt | | yx yy yt | ``` """ @staticmethod def unit(): """ Create a unit matrix Returns: The unit matrix. """ return Matrix(1, 0, 0, 0, 1, 0) @staticmethod def scale(scale_x, scale_y=None): """ Create a scaling matrix Args: scale_x: Scale factor in x direction scale_y: Scale factor in y direction, defaults to scale_x Returns: New matrix """ if scale_y is None: scale_y = scale_x return Matrix(scale_x, 0, 0, 0, scale_y, 0) @staticmethod def translate(x, y): """ Create a translation matrix Args: x: Translation in x direction y: Translation in y direction Returns: New matrix """ return Matrix(1, 0, x, 0, 1, y) @staticmethod def rotate(angle): """ Create a rotation matrix Args: angle: Angle in radians, measured counterclockwise from positive x direction Returns: New matrix """ c = math.cos(angle) s = math.sin(angle) return Matrix(c, -s, 0, s, c, 0) @staticmethod def multiply(p, q): """ Multiply two matrices Args: a: First matrix b: Second matrix Returns: New matrix """ a = p[0] * q[0] + p[1] * q[3] b = p[0] * q[1] + p[1] * q[4] c = p[0] * q[2] + p[1] * q[5] + p[2] d = p[3] * q[0] + p[4] * q[3] e = p[3] * q[1] + p[4] * q[4] f = p[3] * q[2] + p[4] * q[5] + p[5] return Matrix(a, b, c, d, e, f) def __init__(self, xx, xy, xt, yx, yy, yt): self.matrix = (xx, xy, xt, yx, yy, yt) def __iter__(self): return iter(self.matrix) def __len__(self): return len(self.matrix) def __getitem__(self, index): return self.matrix[index] 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 Matrix(*[a + b for a, b in zip(self, other)]) def __sub__(self, other): # add the negative of `other` return self + (-other) def __mul__(self, other): # matrix * scalar if isinstance(other, (int, float)): return Matrix(*[other * a for a in self]) if isinstance(other, Matrix): return Matrix.multiply(self, other) return NotImplemented def __rmul__(self, other): return self.__mul__(other) def __truediv__(self, other): # matrix / scalar if isinstance(other, (int, float)): return Matrix(*[a / other for a in self]) else: return NotImplemented def __floordiv__(self, other): # matrix // scalar if isinstance(other, (int, float)): return Matrix(*[a // other for a in self]) else: return NotImplemented def __repr__(self): return "Matrix({0}, {1}, {2}, {3}, {4}, {5})".format(*self.matrix) def __str__(self): return repr(self)
Static methods
def multiply(p, q)
-
Multiply two matrices
Args
a
- First matrix
b
- Second matrix
Returns
New matrix
def rotate(angle)
-
Create a rotation matrix
Args
angle
- Angle in radians, measured counterclockwise from positive x direction
Returns
New matrix
def scale(scale_x, scale_y=None)
-
Create a scaling matrix
Args
scale_x
- Scale factor in x direction
scale_y
- Scale factor in y direction, defaults to scale_x
Returns
New matrix
def translate(x, y)
-
Create a translation matrix
Args
x
- Translation in x direction
y
- Translation in y direction
Returns
New matrix
def unit()
-
Create a unit matrix
Returns
The unit matrix.
class Vector (*args)
-
Class to represent a 2-vector including most of its common operations This is based on easy_vector https://github.com/DariusMontez/easy_vector The main changes are to make the object immutable, and measuring angles in radians rather than degrees
Can either accept 2 number, or a tuple containing 2 numerical elements.
Args
args
- various - see above
Returns
Self
Expand source code
class Vector(): """ Class to represent a 2-vector including most of its common operations This is based on easy_vector https://github.com/DariusMontez/easy_vector The main changes are to make the object immutable, and measuring angles in radians rather than degrees """ @staticmethod def polar(length, angle): """ Create a vector based on a length and angle Args: length: Length of vector angle: Angle in radians, measured counterclockwise from positive x direction Returns: New vector """ x = length * math.cos(angle) y = length * math.sin(angle) return Vector(x, y) @staticmethod def matrix_premultiply(m, v): """ Multiply a matrix (first) and a vector (second) Args: m: matrix v: vector Returns: New vector """ a = m[0] * v[0] + m[1] * v[1] + m[2] b = m[3] * v[0] + m[4] * v[1] + m[5] return Vector(a, b) def __init__(self, *args): """ Can either accept 2 number, or a tuple containing 2 numerical elements. Args: args: various - see above Returns: Self """ if len(args) == 1 and hasattr(args[0], "__iter__") and len(args[0]) == 2: self.coords = tuple(args[0]) elif len(args) == 2 and isinstance(args[0], (int, float)) and isinstance(args[1], (int, float)): self.coords = tuple(args) else: raise ValueError("Vector requires a sequence of length 2, or 2 numbers") def transform(self, m): """ Transform this vector by a matrix. The vector is pre-multiplied by the matrix Args: m: matrix Returns: New transformed vector """ return m * self def scale(self, scale_x, scale_y=None): """ Scale this vector by a factor. Args: scale_x: scale factor in x direction. scale_y: scale factor in y direction. If this is None, scale by scale_x in both directions. Returns: New scaled vector """ return Matrix.scale(scale_x, scale_y) * self def translate(self, x, y): """ Translate this vector by (x, y), Args: x: translation amount in x direction. y: translation amount in y direction. Returns: New translated vector """ return Matrix.translate(x, y) * self def rotate(self, angle): """ Rotate this vector by (x, y), Args: x: rotation amount in x direction. y: rotation amount in y direction. Returns: New rotated vector """ return Matrix.rotate(angle) * self def lerp(self, other, factor): """ Interpolate between this vector and other. The `factor` parameter works like this: * 0 - result is self * 1 - result is other * 0 to 1 - result between self and other * > 1 - result extensds beyond other * < 0 - result extends backwards before other Args: other: Vector - the other vector factor: number - The interpolation amount. Returns: New rotated vector """ return Vector((1 - factor) * self.x + factor * other.x, (1 - factor) * self.y + factor * other.y) def __iter__(self): return iter(self.coords) def __len__(self): return len(self.coords) def __getitem__(self, index): return self.coords[index] def __eq__(self, other): return isclose(self.x, other.x) and isclose(self.y, other.y) def __neg__(self): return self * -1 def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __sub__(self, other): # add the negative of `other` return self + (-other) def __mul__(self, other): # vector * scalar if isinstance(other, (int, float)): return Vector(other * self.x, other * self.y) return NotImplemented def __rmul__(self, other): if isinstance(other, (int, float)): return self.__mul__(other) if isinstance(other, Matrix): return Vector.matrix_premultiply(other, self) return NotImplemented def __truediv__(self, other): # vector / scalar if isinstance(other, (int, float)): return Vector(self.x / other, self.y / other) else: return NotImplemented def __floordiv__(self, other): # vector / scalar if isinstance(other, (int, float)): return Vector(self.x // other, self.y // other) else: return NotImplemented @property def x(self): """ Read-only property returns x component of vector. """ return self.coords[0] @property def y(self): """ Read-only property returns y component of vector. """ return self.coords[1] @property def length(self): """ Read-only property returns length of vector. """ return math.sqrt(self.x ** 2 + self.y ** 2) @property def angle(self): """ Read-only property returns angle of vector. """ angle = math.atan2(self.y, self.x) return angle @property def unit(self): """ Read-only property returns a unit vector with the same angle as this vector """ return self / self.length # String representation def __repr__(self): return "Vector({0}, {1})".format(self.x, self.y) def __str__(self): return repr(self)
Static methods
def matrix_premultiply(m, v)
-
Multiply a matrix (first) and a vector (second)
Args
m
- matrix
v
- vector
Returns
New vector
def polar(length, angle)
-
Create a vector based on a length and angle
Args
length
- Length of vector
angle
- Angle in radians, measured counterclockwise from positive x direction
Returns
New vector
Instance variables
prop angle
-
Read-only property returns angle of vector.
Expand source code
@property def angle(self): """ Read-only property returns angle of vector. """ angle = math.atan2(self.y, self.x) return angle
prop length
-
Read-only property returns length of vector.
Expand source code
@property def length(self): """ Read-only property returns length of vector. """ return math.sqrt(self.x ** 2 + self.y ** 2)
prop unit
-
Read-only property returns a unit vector with the same angle as this vector
Expand source code
@property def unit(self): """ Read-only property returns a unit vector with the same angle as this vector """ return self / self.length
prop x
-
Read-only property returns x component of vector.
Expand source code
@property def x(self): """ Read-only property returns x component of vector. """ return self.coords[0]
prop y
-
Read-only property returns y component of vector.
Expand source code
@property def y(self): """ Read-only property returns y component of vector. """ return self.coords[1]
Methods
def lerp(self, other, factor)
-
Interpolate between this vector and other.
The
factor
parameter works like this:- 0 - result is self
- 1 - result is other
- 0 to 1 - result between self and other
-
1 - result extensds beyond other
- < 0 - result extends backwards before other
Args
other
- Vector - the other vector
factor
- number - The interpolation amount.
Returns
New rotated vector
def rotate(self, angle)
-
Rotate this vector by (x, y),
Args
x
- rotation amount in x direction.
y
- rotation amount in y direction.
Returns
New rotated vector
def scale(self, scale_x, scale_y=None)
-
Scale this vector by a factor.
Args
scale_x
- scale factor in x direction.
scale_y
- scale factor in y direction. If this is None, scale by scale_x in both directions.
Returns
New scaled vector
def transform(self, m)
-
Transform this vector by a matrix. The vector is pre-multiplied by the matrix
Args
m
- matrix
Returns
New transformed vector
def translate(self, x, y)
-
Translate this vector by (x, y),
Args
x
- translation amount in x direction.
y
- translation amount in y direction.
Returns
New translated vector
class Vector3 (*args)
-
Class to represent a 3-vector including most of its common operations
Can either accept 3 numbers, or a tuple containing 3 numerical elements.
Args
args
- various - see above
Returns
Self
Expand source code
class Vector3: """ Class to represent a 3-vector including most of its common operations """ def __init__(self, *args): """ Can either accept 3 numbers, or a tuple containing 3 numerical elements. Args: args: various - see above Returns: Self """ if len(args) == 1 and hasattr(args[0], "__iter__") and len(args[0]) == 3: self.coords = tuple(args[0]) elif ( len(args) == 3 and isinstance(args[0], (int, float)) and isinstance(args[1], (int, float)) and isinstance(args[2], (int, float)) ): self.coords = tuple(args) else: raise ValueError("Vector3 requires a sequence of length 3, or 3 numbers") def lerp(self, other, factor): """ Interpolate between this vector and other. The `factor` parameter works like this: * 0 - result is self * 1 - result is other * 0 to 1 - result between self and other * > 1 - result extensds beyond other * < 0 - result extends backwards before other Args: other: Vector3 - the other vector factor: number - The interpolation amount. Returns: New rotated vector """ return Vector3( (1 - factor) * self.x + factor * other.x, (1 - factor) * self.y + factor * other.y, (1 - factor) * self.z + factor * other.z, ) def __iter__(self): return iter(self.coords) def __len__(self): return len(self.coords) def __getitem__(self, index): return self.coords[index] def __eq__(self, other): return isclose(self.x, other.x) and isclose(self.y, other.y) def __neg__(self): return self * -1 def __add__(self, other): return Vector3(self.x + other.x, self.y + other.y, self.z + other.z) def __sub__(self, other): # add the negative of `other` return self + (-other) def __mul__(self, other): # vector * scalar if isinstance(other, (int, float)): return Vector3(other * self.x, other * self.y, other * self.z) return NotImplemented def __rmul__(self, other): if isinstance(other, (int, float)): return self.__mul__(other) return NotImplemented def __truediv__(self, other): # vector / scalar if isinstance(other, (int, float)): return Vector3(self.x / other, self.y / other, self.z / other) else: return NotImplemented def __floordiv__(self, other): # vector / scalar if isinstance(other, (int, float)): return Vector3(self.x // other, self.y // other, self.z // other) else: return NotImplemented @property def x(self): """ Read-only property returns x component of vector. """ return self.coords[0] @property def y(self): """ Read-only property returns y component of vector. """ return self.coords[1] @property def z(self): """ Read-only property returns z component of vector. """ return self.coords[2] # String representation def __repr__(self): return "Vector3({0}, {1}, {2})".format(self.x, self.y, self.z) def __str__(self): return repr(self)
Instance variables
prop x
-
Read-only property returns x component of vector.
Expand source code
@property def x(self): """ Read-only property returns x component of vector. """ return self.coords[0]
prop y
-
Read-only property returns y component of vector.
Expand source code
@property def y(self): """ Read-only property returns y component of vector. """ return self.coords[1]
prop z
-
Read-only property returns z component of vector.
Expand source code
@property def z(self): """ Read-only property returns z component of vector. """ return self.coords[2]
Methods
def lerp(self, other, factor)
-
Interpolate between this vector and other.
The
factor
parameter works like this:- 0 - result is self
- 1 - result is other
- 0 to 1 - result between self and other
-
1 - result extensds beyond other
- < 0 - result extends backwards before other
Args
other
- Vector3 - the other vector
factor
- number - The interpolation amount.
Returns
New rotated vector