Module piecad.lin_math
This is a small package of linear algebra functions for 2D and 3D vectors.
It is used internally in Piecad because Numpy is actually rather slow for small vector operations.
Consider the Numpy "cross" function, it is about 65 times slower than the simple ones below.
Additionally Numpy wraps data with types like np.float64 which has overhead and can cause problems
in normal python code.
In short, Numpy is a bad fit for this Computation Geometry package.
This linear algebra package is unusual in that it does not work from a class, but rather is a series of "static" methods designed to operate on plain tuples representing vectors. This is because Python is much more efficent at making a plain tuple than a class. Also accessing elements of a tuple is faster than accessing elements of a python list or a class attribute. Tuples are also more memory efficient.
This is an ADVANCED package intended for users who are familiar with linear algebra and its use in Computational Geometry. For speed reasons none of its functions perform any type checking on their inputs.
Classes
class Geom-
Expand source code
class Geom: """ Namespace holding geometric functions and utilities. """ @staticmethod def coplanar(vl: list[tuple[float, float, float]]) -> bool: """ Checks if a list of vectors are coplanar. """ from . import Const if len(vl) < 4: return True v0, v1, v2 = vl[0], vl[1], vl[2] normal = Vec3.cross(Vec3.sub(v1, v0), Vec3.sub(v2, v0)) for v in vl[3:]: if abs(Vec3.dot(normal, Vec3.sub(v, v0))) > Const.epsilon: return False return TrueNamespace holding geometric functions and utilities.
Static methods
def coplanar(vl: list[tuple[float, float, float]]) ‑> bool-
Expand source code
@staticmethod def coplanar(vl: list[tuple[float, float, float]]) -> bool: """ Checks if a list of vectors are coplanar. """ from . import Const if len(vl) < 4: return True v0, v1, v2 = vl[0], vl[1], vl[2] normal = Vec3.cross(Vec3.sub(v1, v0), Vec3.sub(v2, v0)) for v in vl[3:]: if abs(Vec3.dot(normal, Vec3.sub(v, v0))) > Const.epsilon: return False return TrueChecks if a list of vectors are coplanar.
class Mat3-
Expand source code
class Mat3: @staticmethod def determinant(m: list[tuple[float, float, float]]) -> float: """ Calculates the determinant of a 3x3 matrix. """ return ( m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]) )Static methods
def determinant(m: list[tuple[float, float, float]]) ‑> float-
Expand source code
@staticmethod def determinant(m: list[tuple[float, float, float]]) -> float: """ Calculates the determinant of a 3x3 matrix. """ return ( m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]) )Calculates the determinant of a 3x3 matrix.
class Vec2-
Expand source code
class Vec2: """ Namespace holding functions that operate on plain 2-tuples. """ @staticmethod def abs(v1: tuple[float, float]) -> tuple[float, float]: """ Returns the absolute value of the vector v1. """ return (math.fabs(v1[0]), math.fabs(v1[1])) @staticmethod def add(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 added to vector v2) """ return (v1[0] + v2[0], v1[1] + v2[1]) @staticmethod def mul(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 multiplied by vector v2. """ return (v1[0] * v2[0], v1[1] * v2[1]) @staticmethod def neg(v1: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is the negation of vector v1. """ return (-v1[0], -v1[1]) @staticmethod def pos(v1: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is the positive of vector v1 (same as vector v1). """ return v1 @staticmethod def sub(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 subtracted by vector v2. """ return (v1[0] - v2[0], v1[1] - v2[1]) @staticmethod def div(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 divided by vector v2. """ return (v1[0] / v2[0], v1[1] / v2[1]) @staticmethod def cross( v1: tuple[float, float], v2: tuple[float, float] ) -> tuple[float, float, float]: """ Returns the cross product of vector v1 with vector v2. """ return (0, 0, v1[0] * v2[1] - v1[1] * v2[0]) @staticmethod def distance(v1: tuple[float, float], v2: tuple[float, float]) -> float: """ Returns the distance between vector v1 and vector v2. """ x = v2[0] - v1[0] y = v2[1] - v1[1] return math.sqrt(x * x + y * y) @staticmethod def dot(v1: tuple[float, float], v2: tuple[float, float]) -> float: """ Returns the dot product of vector v1 with vector v2. """ return v1[0] * v2[0] + v1[1] * v2[1] @staticmethod def length(v1: tuple[float, float]) -> float: """ Returns the length of vector v1. """ return math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]) @staticmethod def normalize(v1: tuple[float, float]) -> tuple[float, float]: """ Returns a normalized (unit length) vector in the same direction as vector v1. If the vector has zero length, returns a zero vector. """ length = math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]) if length > 0: return (v1[0] / length, v1[1] / length) return (0, 0) @staticmethod def squaredDistance(v1: tuple[float, float], v2: tuple[float, float]) -> float: x = v2[0] - v1[0] y = v2[1] - v1[1] return x * x + y * y @staticmethod def squaredLength(v1: tuple[float, float]) -> float: return v1[0] * v1[0] + v1[1] * v1[1]Namespace holding functions that operate on plain 2-tuples.
Static methods
def abs(v1: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def abs(v1: tuple[float, float]) -> tuple[float, float]: """ Returns the absolute value of the vector v1. """ return (math.fabs(v1[0]), math.fabs(v1[1]))Returns the absolute value of the vector v1.
def add(v1: tuple[float, float], v2: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def add(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 added to vector v2) """ return (v1[0] + v2[0], v1[1] + v2[1])Returns a vector that is vector v1 added to vector v2)
def cross(v1: tuple[float, float], v2: tuple[float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def cross( v1: tuple[float, float], v2: tuple[float, float] ) -> tuple[float, float, float]: """ Returns the cross product of vector v1 with vector v2. """ return (0, 0, v1[0] * v2[1] - v1[1] * v2[0])Returns the cross product of vector v1 with vector v2.
def distance(v1: tuple[float, float], v2: tuple[float, float]) ‑> float-
Expand source code
@staticmethod def distance(v1: tuple[float, float], v2: tuple[float, float]) -> float: """ Returns the distance between vector v1 and vector v2. """ x = v2[0] - v1[0] y = v2[1] - v1[1] return math.sqrt(x * x + y * y)Returns the distance between vector v1 and vector v2.
def div(v1: tuple[float, float], v2: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def div(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 divided by vector v2. """ return (v1[0] / v2[0], v1[1] / v2[1])Returns a vector that is vector v1 divided by vector v2.
def dot(v1: tuple[float, float], v2: tuple[float, float]) ‑> float-
Expand source code
@staticmethod def dot(v1: tuple[float, float], v2: tuple[float, float]) -> float: """ Returns the dot product of vector v1 with vector v2. """ return v1[0] * v2[0] + v1[1] * v2[1]Returns the dot product of vector v1 with vector v2.
def length(v1: tuple[float, float]) ‑> float-
Expand source code
@staticmethod def length(v1: tuple[float, float]) -> float: """ Returns the length of vector v1. """ return math.sqrt(v1[0] * v1[0] + v1[1] * v1[1])Returns the length of vector v1.
def mul(v1: tuple[float, float], v2: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def mul(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 multiplied by vector v2. """ return (v1[0] * v2[0], v1[1] * v2[1])Returns a vector that is vector v1 multiplied by vector v2.
def neg(v1: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def neg(v1: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is the negation of vector v1. """ return (-v1[0], -v1[1])Returns a vector that is the negation of vector v1.
def normalize(v1: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def normalize(v1: tuple[float, float]) -> tuple[float, float]: """ Returns a normalized (unit length) vector in the same direction as vector v1. If the vector has zero length, returns a zero vector. """ length = math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]) if length > 0: return (v1[0] / length, v1[1] / length) return (0, 0)Returns a normalized (unit length) vector in the same direction as vector v1. If the vector has zero length, returns a zero vector.
def pos(v1: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def pos(v1: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is the positive of vector v1 (same as vector v1). """ return v1Returns a vector that is the positive of vector v1 (same as vector v1).
def squaredDistance(v1: tuple[float, float], v2: tuple[float, float]) ‑> float-
Expand source code
@staticmethod def squaredDistance(v1: tuple[float, float], v2: tuple[float, float]) -> float: x = v2[0] - v1[0] y = v2[1] - v1[1] return x * x + y * y def squaredLength(v1: tuple[float, float]) ‑> float-
Expand source code
@staticmethod def squaredLength(v1: tuple[float, float]) -> float: return v1[0] * v1[0] + v1[1] * v1[1] def sub(v1: tuple[float, float], v2: tuple[float, float]) ‑> tuple[float, float]-
Expand source code
@staticmethod def sub(v1: tuple[float, float], v2: tuple[float, float]) -> tuple[float, float]: """ Returns a vector that is vector v1 subtracted by vector v2. """ return (v1[0] - v2[0], v1[1] - v2[1])Returns a vector that is vector v1 subtracted by vector v2.
class Vec3-
Expand source code
class Vec3: """ Namespace holding functions that operate on plain 3-tuples. """ @staticmethod def abs(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Returns a vector that is the absolute value of the given vector. """ return (math.fabs(v1[0]), math.fabs(v1[1]), math.fabs(v1[2])) @staticmethod def add( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Returns a vector that is vector v1 added to vector v2) """ return (v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]) @staticmethod def mul( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Returns a vector that is vector v1 multiplied by vector v2. """ return (v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]) @staticmethod def neg(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Returns a vector that is the negation of vector v1. """ return (-v1[0], -v1[1], -v1[2]) @staticmethod def pos(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Returns a vector that is the positive of vector v1 (same as vector v1). """ return v1 @staticmethod def sub( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Subtracts vector v2 from vector v1. """ return (v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]) @staticmethod def div( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Returns a vector that is vector v1 divided by vector v2. """ return (v1[0] / v2[0], v1[1] / v2[1], v1[2] / v2[2]) @staticmethod def cross( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Computes the cross product of vector v1 with vector v2. """ ax = v1[0] ay = v1[1] az = v1[2] bx = v2[0] by = v2[1] bz = v2[2] return (ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx) @staticmethod def distance( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> float: """ Calculates the Euclidian distance between vector v1 and v2 vector. """ x = v2[0] - v1[0] y = v2[1] - v1[1] z = v2[2] - v1[2] return (x * x + y * y + z * z) ** 0.5 @staticmethod def dot(v1: tuple[float, float, float], v2: tuple[float, float, float]) -> float: """ Calculates the dot product of vector v1 with vector v2. """ return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] @staticmethod def length(v1: tuple[float, float, float]) -> float: """ Calculates the length (magnitude) of the vector. """ return (v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]) ** 0.5 @staticmethod def normalize(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Normalizes the vector (makes it have a length of 1). """ x = v1[0] y = v1[1] z = v1[2] len = x * x + y * y + z * z if len > 0: len = 1 / (len**0.5) return (x * len, y * len, z * len) @staticmethod def squaredDistance( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> float: """ Calculates the squared Euclidian distance between v1 vector and v2 vector. """ x = v2[0] - v1[0] y = v2[1] - v1[1] z = v2[2] - v1[2] return x * x + y * y + z * z @staticmethod def squaredLength(v1: tuple[float, float, float]) -> float: """ Calculates the squared length of the vector. """ x = v1[0] y = v1[1] z = v1[2] return x * x + y * y + z * zNamespace holding functions that operate on plain 3-tuples.
Static methods
def abs(v1: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def abs(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Returns a vector that is the absolute value of the given vector. """ return (math.fabs(v1[0]), math.fabs(v1[1]), math.fabs(v1[2]))Returns a vector that is the absolute value of the given vector.
def add(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def add( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Returns a vector that is vector v1 added to vector v2) """ return (v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2])Returns a vector that is vector v1 added to vector v2)
def cross(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def cross( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Computes the cross product of vector v1 with vector v2. """ ax = v1[0] ay = v1[1] az = v1[2] bx = v2[0] by = v2[1] bz = v2[2] return (ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx)Computes the cross product of vector v1 with vector v2.
def distance(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> float-
Expand source code
@staticmethod def distance( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> float: """ Calculates the Euclidian distance between vector v1 and v2 vector. """ x = v2[0] - v1[0] y = v2[1] - v1[1] z = v2[2] - v1[2] return (x * x + y * y + z * z) ** 0.5Calculates the Euclidian distance between vector v1 and v2 vector.
def div(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def div( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Returns a vector that is vector v1 divided by vector v2. """ return (v1[0] / v2[0], v1[1] / v2[1], v1[2] / v2[2])Returns a vector that is vector v1 divided by vector v2.
def dot(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> float-
Expand source code
@staticmethod def dot(v1: tuple[float, float, float], v2: tuple[float, float, float]) -> float: """ Calculates the dot product of vector v1 with vector v2. """ return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]Calculates the dot product of vector v1 with vector v2.
def length(v1: tuple[float, float, float]) ‑> float-
Expand source code
@staticmethod def length(v1: tuple[float, float, float]) -> float: """ Calculates the length (magnitude) of the vector. """ return (v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]) ** 0.5Calculates the length (magnitude) of the vector.
def mul(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def mul( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Returns a vector that is vector v1 multiplied by vector v2. """ return (v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2])Returns a vector that is vector v1 multiplied by vector v2.
def neg(v1: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def neg(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Returns a vector that is the negation of vector v1. """ return (-v1[0], -v1[1], -v1[2])Returns a vector that is the negation of vector v1.
def normalize(v1: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def normalize(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Normalizes the vector (makes it have a length of 1). """ x = v1[0] y = v1[1] z = v1[2] len = x * x + y * y + z * z if len > 0: len = 1 / (len**0.5) return (x * len, y * len, z * len)Normalizes the vector (makes it have a length of 1).
def pos(v1: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def pos(v1: tuple[float, float, float]) -> tuple[float, float, float]: """ Returns a vector that is the positive of vector v1 (same as vector v1). """ return v1Returns a vector that is the positive of vector v1 (same as vector v1).
def squaredDistance(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> float-
Expand source code
@staticmethod def squaredDistance( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> float: """ Calculates the squared Euclidian distance between v1 vector and v2 vector. """ x = v2[0] - v1[0] y = v2[1] - v1[1] z = v2[2] - v1[2] return x * x + y * y + z * zCalculates the squared Euclidian distance between v1 vector and v2 vector.
def squaredLength(v1: tuple[float, float, float]) ‑> float-
Expand source code
@staticmethod def squaredLength(v1: tuple[float, float, float]) -> float: """ Calculates the squared length of the vector. """ x = v1[0] y = v1[1] z = v1[2] return x * x + y * y + z * zCalculates the squared length of the vector.
def sub(v1: tuple[float, float, float], v2: tuple[float, float, float]) ‑> tuple[float, float, float]-
Expand source code
@staticmethod def sub( v1: tuple[float, float, float], v2: tuple[float, float, float] ) -> tuple[float, float, float]: """ Subtracts vector v2 from vector v1. """ return (v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2])Subtracts vector v2 from vector v1.