Skip to content

Vector mathematics

Import Vector and the functions below from gem.vector. Source, conventions, evidence, ownership/extremes.

Vector(size, data=None) is the class for Vector2/3/4: these are dimensions, not distinct class names. .size is the declared dimension and .vector is component storage. No wrapper indexing or iteration protocol is implemented: use v.vector[index] and for component in v.vector. There is no Vector ctypes export; use common conversion helpers.

Unless stated otherwise, size is a nonnegative integer and raw vecA/vecB are indexable component sequences with at least size entries. Wrapper operands use matching well-formed dimensions. Basic kernels allocate fresh lists and preserve inputs; they do not validate every shape/type. Arithmetic mismatches can index-fail or ignore extra storage rather than uniformly raising ValueError. These are prerequisites, not an expanded validation contract.

Class and methods

Exact source declaration Parameters, result and behavior
Vector Dimensioned component wrapper; instantiate with the constructor below.
Vector.__init__(self, size, data=None) size declares dimension; omitted data creates zero storage, supplied component storage is retained by reference without length validation. Initialization returns None; see fields above.
Vector.__repr__(self) Return a string containing the declared size and storage; no mutation.
Vector.__add__(self, other) other: Vector or int/float (bool inherits int). Component +; return a fresh Vector. Unsupported types return NotImplemented; no reflected scalar operator.
Vector.__iadd__(self, other) other: Vector or int/float (bool inherits int). Component +; replace receiver storage and return self. Unsupported types return NotImplemented; no reflected scalar operator.
Vector.__sub__(self, other) other: Vector or int/float (bool inherits int). Component -; return a fresh Vector. Unsupported types return NotImplemented; no reflected scalar operator.
Vector.__isub__(self, other) other: Vector or int/float (bool inherits int). Component -; replace receiver storage and return self. Unsupported types return NotImplemented; no reflected scalar operator.
Vector.__mul__(self, scalar) scalar: int/float; component multiplication; fresh Vector. Unsupported types return NotImplemented; scalar-left multiplication is absent.
Vector.__imul__(self, scalar) scalar: int/float; component multiplication; replace storage, return self. Unsupported types return NotImplemented; scalar-left multiplication is absent.
Vector.__div__(self, scalar) scalar: int/float; component /; fresh Vector. Unsupported operands return NotImplemented; division by exact zero raises ZeroDivisionError.
Vector.__truediv__(self, scalar) scalar: int/float; component /; fresh Vector. Unsupported operands return NotImplemented; division by exact zero raises ZeroDivisionError.
Vector.__idiv__(self, scalar) scalar: int/float; component /; replace storage, return self. Unsupported operands return NotImplemented; division by exact zero raises ZeroDivisionError.
Vector.__itruediv__(self, scalar) scalar: int/float; component /; replace storage, return self. Unsupported operands return NotImplemented; division by exact zero raises ZeroDivisionError.
Vector.__eq__(self, vecB) vecB: Vector. Return exact equality bool including declared dimensions; two empty Vectors are equal. Unsupported types return NotImplemented. No tolerance; same-size comparison reads each declared component.
Vector.__ne__(self, vecB) vecB: Vector. Return exact inequality bool including declared dimensions; two empty Vectors are equal. Unsupported types return NotImplemented. No tolerance; same-size comparison reads each declared component.
Vector.__neg__(self) Unary minus; return a fresh component-negated Vector.
Vector.clone(self) Copy the component sequence by slicing into a new Vector (ordinary numeric components are independent).
Vector.one(self) Replace storage with ones; return self.
Vector.zero(self) Replace storage with zeros; return self.
Vector.negate(self) Return a fresh component-negated Vector, equivalent to unary minus.
Vector.maxV(self, vecB) vecB: matching Vector; fresh componentwise maximum Vector. Inputs preserved; comparison-based NaN behavior is historical.
Vector.maxS(self) Return the largest component by comparisons; empty storage raises IndexError.
Vector.minV(self, vecB) vecB: matching Vector; fresh componentwise minimum Vector. Inputs preserved; comparison-based NaN behavior is historical.
Vector.minS(self) Return the smallest component by comparisons; empty storage raises IndexError.
Vector.magnitude(self) Return the stable numeric length; no mutation.
Vector.clamp(self, size, value, minS, maxS) Explicit size,value,minS,maxS raw component lists are passed to module clamp; receiver values are not implicit. Return a fresh Vector; receiver and lists preserved.
Vector.i_clamp(self, size, value, minS, maxS) Explicit size,value,minS,maxS raw component lists are passed to module clamp; receiver values are not implicit. Replace only receiver storage, return self; original caller lists preserved. Receiver .size is not updated if explicit size differs.
Vector.i_normalize(self) Replace storage with stable normalized components; exact zero becomes zero; return self.
Vector.normalize(self) Return a fresh normalized Vector; exact zero returns a fresh zero Vector.
Vector.dot(self, vecB) vecB: Vector; numeric sum of products, preserving inputs; unsupported type returns NotImplemented. No stable extreme-product summation guarantee.
Vector.isInSameDirection(self, otherVec) otherVec: Vector; return dot(otherVec) > 0, a bool sign test, not collinearity. Zero dot yields False; unsupported type returns NotImplemented.
Vector.isInOppositeDirection(self, otherVec) otherVec: Vector; return dot(otherVec) < 0, a bool sign test, not collinearity. Zero dot yields False; unsupported type returns NotImplemented.
Vector.barycentric(self, a, b, c) a,b,c: Vector triangle vertices; receiver is point p. Return fresh [u,v,w], sum 1, from the dot-product Gram system. Exact zero denominator raises ZeroDivisionError; outside-triangle weights may be negative. No clamping or mutation.
Vector.transform(self, position, matrix) position: raw coordinates; matrix: nested square rows; use receiver size, not its stored position. Fresh Vector; receiver preserved. See transform rules.
Vector.i_transform(self, position, matrix) position: raw coordinates; matrix: nested square rows; use receiver size, not its stored position. Replace receiver storage, return self; raw inputs preserved. See transform rules.
Vector.xy(self) Return fresh Vector2 with components X, Y in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.yz(self) Return fresh Vector2 with components Y, Z in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.xz(self) Return fresh Vector2 with components X, Z in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.xw(self) Return fresh Vector2 with components X, W in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.yw(self) Return fresh Vector2 with components Y, W in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.zw(self) Return fresh Vector2 with components Z, W in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.xyw(self) Return fresh Vector3 with components X, Y, W in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.yzw(self) Return fresh Vector3 with components Y, Z, W in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.xzw(self) Return fresh Vector3 with components X, Z, W in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.xyz(self) Return fresh Vector3 with components X, Y, Z in that order; receiver must contain every referenced component, otherwise IndexError. No mutation.
Vector.right(self) Return a fresh fixed Vector3 [1,0,0] regardless of receiver dimension. front differs from Quaternion.getForward (+Z).
Vector.left(self) Return a fresh fixed Vector3 [-1,0,0] regardless of receiver dimension. front differs from Quaternion.getForward (+Z).
Vector.front(self) Return a fresh fixed Vector3 [0,0,-1] regardless of receiver dimension. front differs from Quaternion.getForward (+Z).
Vector.back(self) Return a fresh fixed Vector3 [0,0,1] regardless of receiver dimension. front differs from Quaternion.getForward (+Z).
Vector.up(self) Return a fresh fixed Vector3 [0,1,0] regardless of receiver dimension. front differs from Quaternion.getForward (+Z).
Vector.down(self) Return a fresh fixed Vector3 [0,-1,0] regardless of receiver dimension. front differs from Quaternion.getForward (+Z).

Raw kernels and geometry helpers

Exact source declaration Parameters, result and behavior
zero_vector(size) Fresh zero-filled list; size controls length. Sizes 2/3/4 copy the historical reference buffers.
one_vector(size) Fresh one-filled list; sizes 2/3/4 copy the historical reference buffers.
lerp(vecA, vecB, time) vecA,vecB: matching Vectors; numeric time is unclamped. Return fresh a+(b-a)*time Vector.
cross(vecA, vecB) vecA,vecB: Vector3; fresh Vector3 a×b, right-handed X×Y=Z; inputs preserved.
reflect(incidentVec, normal) incidentVec,normal: matching Vectors, normal unit prerequisite; fresh i−2(i·n)n; no automatic normalization.
refract(IOR, incidentVec, normal) IOR: n1/n2; matching unit incidentVec,normal, normal opposes incidence. k=1−IOR²(1−(n·i)²); fresh IORi−(IOR(n·i)+sqrt(k))*n, or zero Vector when k<0. No input normalization/flipping.
toAngle(vector) Raw 2D vector sequence; atan2(y,x) radians, a scalar; no mutation.
lperp(vector) Raw 2D vector; fresh Vector2 [-y,x], a +90° rotation.
rperp(vector) Raw 2D vector; fresh Vector2 [y,-x], a −90° rotation.
vec_add(size, vecA, vecB) Fresh list vecA[i]+vecB[i].
s_vec_add(size, vecA, scalar) Fresh list vecA[i]+scalar.
vec_sub(size, vecA, vecB) Fresh list vecA[i]−vecB[i].
s_vec_sub(size, vecA, scalar) Fresh list vecA[i]−scalar.
vec_mul(size, vecA, scalar) Fresh list vecA[i]*scalar.
vec_div(size, vecA, scalar) Fresh list vecA[i]/scalar; exact zero divisor raises ZeroDivisionError.
vec_neg(size, vecA) Fresh list −vecA[i].
dot(size, vecA, vecB) Numeric sum vecA[i]*vecB[i]; no mutation or extreme-scale product guarantee.
magnitude(size, vecA) Stable finite-input length using scaled chained hypot. Empty/zero length is 0.0; representational overflow may return infinity; nonfinite paths retain square-sum arithmetic.
normalize(size, vecA) Fresh stable normalized list using scaled hypot; exact zero returns zeros. Nonfinite paths retain legacy arithmetic without a new error policy.
maxV(size, vecA, vecB) Fresh componentwise maxima of raw vecA and vecB.
minV(size, vecA, vecB) Fresh componentwise minima of raw vecA and vecB.
maxS(size, vecA) Largest component scalar; seeds from vecA[0], so empty input raises IndexError.
minS(size, vecA) Smallest component scalar; seeds from vecA[0], so empty input raises IndexError.
clamp(size, value, minS, maxS) Raw value,minS,maxS lists and explicit size. Copy value, cap above maxS then below minS per component, return Vector(size). Preserve all lists; no validation of ordered bounds. Extra value storage survives the slice.

Exposed reference buffers

gem.vector.REFRENCE_VECTOR_2, REFRENCE_VECTOR_3, REFRENCE_VECTOR_4 are mutable lists of respectively 2/3/4 zeros. IREFRENCE_VECTOR_2, IREFRENCE_VECTOR_3, IREFRENCE_VECTOR_4 contain ones. Spellings are historical. They are implementation reference buffers, not immutable mathematical constants; mutating them changes subsequent zero/one defaults. Do not edit them in applications. There are no other intended public vector constants.

Ownership and stable norms

Returning operations preserve caller buffers. In-place operations replace the receiver list, so a separate wrapper sharing the old list is not updated. Finite lengths/normalization avoid unnecessary intermediate overflow/underflow; this does not stabilize dot, cross or barycentric products. No general NaN/Infinity policy or mismatched-dimension error policy is established.

from gem.vector import Vector, cross, refract

values = [3.0, 4.0, 0.0]
v = Vector(3, values)
unit = v.normalize()
assert v.vector is values and values == [3.0, 4.0, 0.0]
assert unit.vector is not values and unit.vector == [0.6, 0.8, 0.0]
assert v.i_clamp(3, values, [0, 0, 0], [2, 2, 2]) is v
assert v.vector == [2, 2, 0.0] and values == [3.0, 4.0, 0.0]
assert Vector(0) == Vector(0) and Vector(2) != Vector(3)
assert Vector(2).__eq__(object()) is NotImplemented
assert cross(Vector(3, [1, 0, 0]), Vector(3, [0, 1, 0])).vector == [0, 0, 1]
assert refract(1.0 / 1.5, Vector(3, [0, -1, 0]), Vector(3, [0, 1, 0])).vector == [0.0, -1.0, 0.0]
assert Vector(3).normalize().vector == [0.0, 0.0, 0.0]

Barycentric weights describe affine coordinates, not an intersection test:

from gem.vector import Vector

p = Vector(2, [0.5, 0.5])
weights = p.barycentric(Vector(2, [0, 0]), Vector(2, [2, 0]), Vector(2, [0, 2]))
assert weights == [0.5, 0.25, 0.25]

See transforms, utilities/viewport, decisions and API index.

See the graphics gallery example for an executable visualization.