simvx.core.math.types¶
Lightweight math types – Vec2, Vec3, Quat.
Vec2/Vec3 subclass np.ndarray for zero-copy interop with NumPy and GPU pipelines: v = Vec2(1, 2) np.dot(v, v) # works – it IS a numpy array v.normalized() # returns Vec2, not ndarray
Quat uses slots for memory efficiency (different semantics than vectors). All angles are in radians.
Module Contents¶
Classes¶
Functions¶
Data¶
API¶
- simvx.core.math.types.log¶
‘getLogger(…)’
- simvx.core.math.types.__all__¶
[‘Vec2’, ‘Vec3’, ‘Quat’, ‘Curve2D’, ‘Curve3D’, ‘normalize’, ‘length’, ‘dot’, ‘cross’, ‘mix’, ‘clamp’…
- class simvx.core.math.types.Vec2(shape, dtype=float, buffer=None, offset=0, strides=None, order=None)[source]¶
Bases:
numpy.ndarray2D vector (np.ndarray subclass, shape (2,), float32).
Components are stored as the nearest float32, and that is the guarantee. It is what lets a vector be handed to the GPU without a copy or a conversion, which is the whole reason these are ndarray subclasses rather than a pair of Python floats. The consequence is that a float64 value does not survive a store unchanged, and the nearest float32 may lie on either side of it: after
v.x = 0.1,v.x <= 0.1is not guaranteed.So an exact boundary does not survive a round trip. Code enforcing a spatial bound must compare with a tolerance, or clamp to a value inside the bound (
limit * (1 - 1e-6)), rather than expectclampfollowed by<=to hold. There is deliberately no round-trip-safeclamp_tohelper: a helper would have to pick a tolerance on the caller’s behalf, and the caller is the only one who knows what the bound means.Initialization
- normalized() simvx.core.math.types.Vec2[source]¶
Return a unit-length copy, or zero vector if length is near zero.
- direction_to(other) simvx.core.math.types.Vec2[source]¶
Return the normalized direction toward another vector.
- move_toward(target, delta: float) simvx.core.math.types.Vec2[source]¶
Move toward target by at most delta distance.
- lerp(other, t: float) simvx.core.math.types.Vec2[source]¶
Linear interpolation between self and other.
- snapped(step: float) simvx.core.math.types.Vec2[source]¶
Round each component to the nearest multiple of step.
- clamped(min_v, max_v) simvx.core.math.types.Vec2[source]¶
Return this vector with each component clamped between the matching components of
min_vandmax_v(component-wise).
- rotated(angle: float) simvx.core.math.types.Vec2[source]¶
Return this vector rotated by angle (radians).
- reflect(normal) simvx.core.math.types.Vec2[source]¶
Return this vector reflected off a surface with the given normal.
- bounce(normal) simvx.core.math.types.Vec2[source]¶
Return the bounce vector (negated reflect).
- slide(normal) simvx.core.math.types.Vec2[source]¶
Return this vector slid along a plane defined by normal.
- abs() simvx.core.math.types.Vec2[source]¶
Return vector with absolute values of each component.
- classmethod from_angle(radians: float) simvx.core.math.types.Vec2[source]¶
Return a unit vector pointing in the given direction (radians from +X axis).
- __abs__()¶
- __add__(value)¶
- __and__(value)¶
- __array__(dtype=None)¶
- __array_wrap__(obj)¶
- __contains__(key)¶
- __copy__()¶
- __deepcopy__(memo)¶
- __divmod__(value)¶
- __float__()¶
- __floordiv__()¶
- __ge__(value)¶
- __getitem__(key)¶
- __gt__(value)¶
- __iadd__(value)¶
- __iand__(value)¶
- __ifloordiv__(value)¶
- __ilshift__(value)¶
- __imod__(value)¶
- __imul__(value)¶
- __int__()¶
- __invert__()¶
- __ior__(value)¶
- __ipow__(value)¶
- __irshift__(value)¶
- __isub__(value)¶
- __itruediv__(value)¶
- __ixor__(value)¶
- __le__(value)¶
- __len__()¶
- __lshift__(value)¶
- __lt__(value)¶
- __matmul__(value)¶
- __mul__(value)¶
- __neg__()¶
- __or__(value)¶
- __pos__()¶
- __pow__()¶
- __rshift__()¶
- __setitem__(key, value)¶
- __str__()¶
- __sub__(value)¶
- __truediv__(value)¶
- __xor__(value)¶
- all(axis=None, out=None, keepdims=False)¶
- any(axis=None, out=None, keepdims=False)¶
- argmax(axis=None, out=None)¶
- argmin(axis=None, out=None)¶
- argpartition(kth, axis=-1, kind='introselect', order=None)¶
- argsort(axis=-1, kind='quicksort', order=None)¶
- astype(dtype, order='K', casting='unsafe', subok=True, copy=True)¶
- byteswap(inplace=False)¶
- choose(choices, out=None, mode='raise')¶
- clip(min=None, max=None, out=None)¶
- compress(condition, axis=None, out=None)¶
- conj()¶
- conjugate()¶
- copy(order='C')¶
- cumprod(axis=None, dtype=None, out=None)¶
- cumsum(axis=None, dtype=None, out=None)¶
- diagonal(offset=0, axis1=0, axis2=1)¶
- dump(file)¶
- dumps()¶
- fill(value)¶
- flatten(order='C')¶
- getfield(dtype, offset=0)¶
- item(*args)¶
- itemset(*args)¶
- max(axis=None, out=None)¶
- mean(axis=None, dtype=None, out=None, keepdims=False)¶
- min(axis=None, out=None, keepdims=False)¶
- newbyteorder(new_order='S')¶
- nonzero()¶
- partition(kth, axis=-1, kind='introselect', order=None)¶
- prod(axis=None, dtype=None, out=None, keepdims=False)¶
- ptp(axis=None, out=None)¶
- put(indices, values, mode='raise')¶
- ravel(order='C')¶
- repeat(repeats, axis=None)¶
- reshape(shape, order='C')¶
- resize(new_shape, refcheck=True)¶
- round(decimals=0, out=None)¶
- searchsorted(v, side='left', sorter=None)¶
- setfield(val, dtype, offset=0)¶
- setflags(write=None, align=None, uic=None)¶
- sort(axis=-1, kind='quicksort', order=None)¶
- squeeze(axis=None)¶
- std(axis=None, dtype=None, out=None, ddof=0, keepdims=False)¶
- sum(axis=None, dtype=None, out=None, keepdims=False)¶
- swapaxes(axis1, axis2)¶
- take(indices, axis=None, out=None, mode='raise')¶
- tobytes(order='C')¶
- tofile(fid, sep='', format='%s')¶
- tolist()¶
- tostring(order='C')¶
- trace(offset=0, axis1=0, axis2=1, dtype=None, out=None)¶
- transpose(*axes)¶
- var(axis=None, dtype=None, out=None, ddof=0, keepdims=False)¶
- view(dtype=None, type=None)¶
- classmethod __class_getitem__(value)¶
- simvx.core.math.types.builtins_abs¶
None
- class simvx.core.math.types.Vec3(shape, dtype=float, buffer=None, offset=0, strides=None, order=None)[source]¶
Bases:
numpy.ndarray3D vector (np.ndarray subclass, shape (3,), float32).
Components are stored as the nearest float32, on the same terms as
- Class:
Vec2: it is what makes a vector zero-copy at the GPU boundary, and it means an exact bound does not survive a store.clamp(x, r)followed byposition.x <= ris not guaranteed. Compare with a tolerance, or clamp to a value inside the bound. See :class:Vec2for the full statement and for why there is noclamped_lengthhelper.
Initialization
- normalized() simvx.core.math.types.Vec3[source]¶
Return a unit-length copy, or zero vector if length is near zero.
- cross(other) simvx.core.math.types.Vec3[source]¶
Return the cross product with another vector.
- direction_to(other) simvx.core.math.types.Vec3[source]¶
Return the normalized direction toward another vector.
- move_toward(target, delta: float) simvx.core.math.types.Vec3[source]¶
Move toward target by at most delta distance.
- lerp(other, t: float) simvx.core.math.types.Vec3[source]¶
Linear interpolation between self and other.
- snapped(step: float) simvx.core.math.types.Vec3[source]¶
Round each component to the nearest multiple of step.
- clamped(min_v, max_v) simvx.core.math.types.Vec3[source]¶
Return this vector with each component clamped between the matching components of
min_vandmax_v(component-wise).
- __abs__()¶
- __add__(value)¶
- __and__(value)¶
- __array__(dtype=None)¶
- __array_wrap__(obj)¶
- __contains__(key)¶
- __copy__()¶
- __deepcopy__(memo)¶
- __divmod__(value)¶
- __float__()¶
- __floordiv__()¶
- __ge__(value)¶
- __getitem__(key)¶
- __gt__(value)¶
- __iadd__(value)¶
- __iand__(value)¶
- __ifloordiv__(value)¶
- __ilshift__(value)¶
- __imod__(value)¶
- __imul__(value)¶
- __int__()¶
- __invert__()¶
- __ior__(value)¶
- __ipow__(value)¶
- __irshift__(value)¶
- __isub__(value)¶
- __itruediv__(value)¶
- __ixor__(value)¶
- __le__(value)¶
- __len__()¶
- __lshift__(value)¶
- __lt__(value)¶
- __matmul__(value)¶
- __mul__(value)¶
- __neg__()¶
- __or__(value)¶
- __pos__()¶
- __pow__()¶
- __rshift__()¶
- __setitem__(key, value)¶
- __str__()¶
- __sub__(value)¶
- __truediv__(value)¶
- __xor__(value)¶
- all(axis=None, out=None, keepdims=False)¶
- any(axis=None, out=None, keepdims=False)¶
- argmax(axis=None, out=None)¶
- argmin(axis=None, out=None)¶
- argpartition(kth, axis=-1, kind='introselect', order=None)¶
- argsort(axis=-1, kind='quicksort', order=None)¶
- astype(dtype, order='K', casting='unsafe', subok=True, copy=True)¶
- byteswap(inplace=False)¶
- choose(choices, out=None, mode='raise')¶
- clip(min=None, max=None, out=None)¶
- compress(condition, axis=None, out=None)¶
- conj()¶
- conjugate()¶
- copy(order='C')¶
- cumprod(axis=None, dtype=None, out=None)¶
- cumsum(axis=None, dtype=None, out=None)¶
- diagonal(offset=0, axis1=0, axis2=1)¶
- dump(file)¶
- dumps()¶
- fill(value)¶
- flatten(order='C')¶
- getfield(dtype, offset=0)¶
- item(*args)¶
- itemset(*args)¶
- max(axis=None, out=None)¶
- mean(axis=None, dtype=None, out=None, keepdims=False)¶
- min(axis=None, out=None, keepdims=False)¶
- newbyteorder(new_order='S')¶
- nonzero()¶
- partition(kth, axis=-1, kind='introselect', order=None)¶
- prod(axis=None, dtype=None, out=None, keepdims=False)¶
- ptp(axis=None, out=None)¶
- put(indices, values, mode='raise')¶
- ravel(order='C')¶
- repeat(repeats, axis=None)¶
- reshape(shape, order='C')¶
- resize(new_shape, refcheck=True)¶
- round(decimals=0, out=None)¶
- searchsorted(v, side='left', sorter=None)¶
- setfield(val, dtype, offset=0)¶
- setflags(write=None, align=None, uic=None)¶
- sort(axis=-1, kind='quicksort', order=None)¶
- squeeze(axis=None)¶
- std(axis=None, dtype=None, out=None, ddof=0, keepdims=False)¶
- sum(axis=None, dtype=None, out=None, keepdims=False)¶
- swapaxes(axis1, axis2)¶
- take(indices, axis=None, out=None, mode='raise')¶
- tobytes(order='C')¶
- tofile(fid, sep='', format='%s')¶
- tolist()¶
- tostring(order='C')¶
- trace(offset=0, axis1=0, axis2=1, dtype=None, out=None)¶
- transpose(*axes)¶
- var(axis=None, dtype=None, out=None, ddof=0, keepdims=False)¶
- view(dtype=None, type=None)¶
- classmethod __class_getitem__(value)¶
- class simvx.core.math.types.Quat(w=1.0, x=0.0, y=0.0, z=0.0)[source]¶
Quaternion (w, x, y, z) – identity by default.
Rotation convention: YXZ intrinsic, applied as yaw about Y, then pitch about X, then roll about Z. This puts the two orientations Euler angles cannot name at straight up and straight down, where a camera controller already clamps, rather than at a compass heading.
All angle inputs/outputs in radians.
Initialization
- __slots__¶
(‘w’, ‘x’, ‘y’, ‘z’)
- classmethod from_euler(pitch: float = 0.0, yaw: float = 0.0, roll: float = 0.0) simvx.core.math.types.Quat[source]¶
Create quaternion from Euler angles in radians (YXZ intrinsic order).
Args: pitch: Rotation around X axis (radians) yaw: Rotation around Y axis (radians) roll: Rotation around Z axis (radians)
- classmethod from_axis_angle(axis: simvx.core.math.types.Vec3 | tuple, angle: float) simvx.core.math.types.Quat[source]¶
Create quaternion from axis-angle rotation.
Args: axis: Rotation axis (will be normalized) angle: Rotation angle in radians
- classmethod look_at(direction: simvx.core.math.types.Vec3 | tuple, up: simvx.core.math.types.Vec3 | tuple = None) simvx.core.math.types.Quat[source]¶
Create quaternion looking in given direction (right-handed).
This builds a whole frame from
up, so it also decides the roll. To turn one direction onto another by the smallest angle, leaving the roll alone, use :meth:shortest_arc.Args: direction: Forward direction (will be normalized) up: Up vector (default: Y-up)
- classmethod shortest_arc(from_direction: simvx.core.math.types.Vec3 | tuple, to_direction: simvx.core.math.types.Vec3 | tuple) simvx.core.math.types.Quat[source]¶
Rotation that turns one direction onto another by the smallest angle.
Reach for this when what matters is the pairing of two directions and not the roll around them: swinging a turret from the way its barrel already points to the way it should point, orienting a projectile along its velocity, or laying a decal by turning :attr:
Vec3.UPonto a surface normal. Only the directions are used; the lengths of both arguments are ignored.- Meth:
look_atalso returns a rotation that points a given way, but a different one. It builds a frame from a world up vector and so fixes the roll as well, which flips by half a turn as the direction passes that up vector, where the arc turns smoothly through. Uselook_atfor a camera or anything that must stay upright; use this to turn one vector onto another.
Two exactly opposite directions have no shortest arc, since every perpendicular axis turns one onto the other. A half turn about a perpendicular derived from the input is returned, so repeated calls on the same pair agree. A zero-length direction names no rotation at all: identity is returned and the cause is logged once.
Args: from_direction: Direction to rotate from (will be normalized) to_direction: Direction to rotate onto (will be normalized)
- inverse() simvx.core.math.types.Quat[source]¶
Return conjugate (inverse for unit quaternion).
- euler_angles() simvx.core.math.types.Vec3[source]¶
Euler angles (pitch, yaw, roll) in radians, the inverse of :meth:
from_euler.Straight up and straight down are the two orientations an Euler triple cannot name: there, yaw and roll turn about the same world axis and only their sum is determined. Both are reported as roll zero and the whole turn as yaw, which is the reading that recomposes to the orientation asked about and the one an inspector should show, since a camera looking down has a heading and no roll.
- slerp(other: simvx.core.math.types.Quat, t: float) simvx.core.math.types.Quat[source]¶
Spherical linear interpolation between self and other.
- rotate(axis: simvx.core.math.types.Vec3 | tuple, angle: float) simvx.core.math.types.Quat[source]¶
Apply additional rotation around axis (radians).
- class simvx.core.math.types.Curve2D(bake_interval: float = 5.0)[source]¶
2D curve with cubic Bezier interpolation.
Each point has an optional in-handle and out-handle for smooth curves. Handles are relative offsets from the point position.
Initialization
- __slots__¶
(‘_points’, ‘_baked_points’, ‘_baked_length’, ‘_bake_dirty’, ‘_bake_interval’)
- add_point(position: simvx.core.math.types.Vec2 | tuple, handle_in: simvx.core.math.types.Vec2 | tuple = None, handle_out: simvx.core.math.types.Vec2 | tuple = None, index: int = -1)[source]¶
Add a point to the curve. Handles are relative offsets from position.
- get_point_position(index: int) simvx.core.math.types.Vec2[source]¶
- set_point_position(index: int, position: simvx.core.math.types.Vec2 | tuple)[source]¶
- get_point_in(index: int) simvx.core.math.types.Vec2[source]¶
- get_point_out(index: int) simvx.core.math.types.Vec2[source]¶
- sample(t: float) simvx.core.math.types.Vec2[source]¶
Sample the curve at parameter t (0.0 to 1.0). Returns position via cubic Bezier.
- sample_baked(offset: float) simvx.core.math.types.Vec2[source]¶
Sample by distance along the baked curve (0 to baked_length).
- sample_baked_with_rotation(offset: float) tuple[simvx.core.math.types.Vec2, float][source]¶
Sample position and rotation angle (radians) at distance along curve.
- get_baked_points() list[simvx.core.math.types.Vec2][source]¶
Return list of baked (pre-tessellated) points.
- class simvx.core.math.types.Curve3D(bake_interval: float = 0.2)[source]¶
3D curve with cubic Bezier interpolation.
Each point has an optional in-handle and out-handle for smooth curves. Handles are relative offsets from the point position.
Initialization
- __slots__¶
(‘_points’, ‘_baked_points’, ‘_baked_length’, ‘_bake_dirty’, ‘_bake_interval’, ‘_tilts’)
- add_point(position: simvx.core.math.types.Vec3 | tuple, handle_in: simvx.core.math.types.Vec3 | tuple = None, handle_out: simvx.core.math.types.Vec3 | tuple = None, index: int = -1, tilt: float = 0.0)[source]¶
Add a point to the curve. Handles are relative offsets from position.
- get_point_position(index: int) simvx.core.math.types.Vec3[source]¶
- set_point_position(index: int, position: simvx.core.math.types.Vec3 | tuple)[source]¶
- get_point_in(index: int) simvx.core.math.types.Vec3[source]¶
- get_point_out(index: int) simvx.core.math.types.Vec3[source]¶
- sample(t: float) simvx.core.math.types.Vec3[source]¶
Sample the curve at parameter t (0.0 to 1.0). Returns position via cubic Bezier.
- sample_baked(offset: float) simvx.core.math.types.Vec3[source]¶
Sample by distance along the baked curve (0 to baked_length).
- sample_baked_with_rotation(offset: float, up: simvx.core.math.types.Vec3 = None) tuple[simvx.core.math.types.Vec3, simvx.core.math.types.Vec3][source]¶
Sample position and forward direction at distance along curve.
Returns (position, forward_direction) where forward is a unit Vec3.
- get_baked_points() list[simvx.core.math.types.Vec3][source]¶
- simvx.core.math.types.normalize(v: simvx.core.math.types.Vec2 | simvx.core.math.types.Vec3) simvx.core.math.types.Vec2 | simvx.core.math.types.Vec3[source]¶
Return normalized copy of vector.
- simvx.core.math.types.length(v: simvx.core.math.types.Vec2 | simvx.core.math.types.Vec3) float[source]¶
Return length of vector.
- simvx.core.math.types.dot(a: simvx.core.math.types.Vec2 | simvx.core.math.types.Vec3, b: simvx.core.math.types.Vec2 | simvx.core.math.types.Vec3) float[source]¶
Dot product of two vectors.
- simvx.core.math.types.cross(a: simvx.core.math.types.Vec3, b: simvx.core.math.types.Vec3) simvx.core.math.types.Vec3[source]¶
Cross product of two Vec3.
- simvx.core.math.types.mix(a, b, t: float)[source]¶
Linear interpolation between a and b.
Works with scalars, Vec2, Vec3, and Quat (uses slerp for Quat).
- simvx.core.math.types.clamp(v: float, lo: float, hi: float) float[source]¶
Clamp a scalar value between lo and hi.
- simvx.core.math.types.slerp(a: simvx.core.math.types.Quat, b: simvx.core.math.types.Quat, t: float) simvx.core.math.types.Quat[source]¶
Spherical linear interpolation between two quaternions.