*experimental*and some APIs might get changed without preserving full backwards compatibility.

# module

mathMath library

In the C++ API, math types are commonly used via `typedef`

s in the
root namespace, only library-level generic code uses things like
Math::Vector<size, T>. Since Python doesn’t have
templates or generics, there are no generic variants in the magnum.math
module, all the concrete types are in the root module with the same names
as in the C++ variant.

All math structures are instantiated for the most common sizes and types and so they all share a very similar API. As in C++, main differences are between floating-point types and integral types (one having normalization and projection while the other having bitwise operations) and extra convenience methods added for vectors of particular size.

As shown above, all math types are constructible from a (nested) tuple of
matching type, matching the convenience of C++11 uniform initializers. As
another example, a function accepting a Quaternion will accept a
`((x, y, z), w)`

tuple as well, but not `(x, y, z, w)`

, as that is
not convertible to a pair of a three-component vector and a scalar.

## Magnum math vs Python math

## Float vs double overloads

Since Python doesn’t really differentiate between 32bit and 64bit doubles,
all *scalar* functions taking or returning a floating-point type (such as
the Deg / Rad types, math.pi or
math.sin) use the `double`

variant of the
underlying C++ API — the extra arithmetic cost is negligible to the
Python-to-C++ function call overhead.

On the other hand, matrix and vector types are exposed in both the float and double variants.

## Implicit conversions; NumPy compatibility

All vector classes are implicitly convertible from a tuple of correct size and type as well as from/to type implementing the buffer protocol, and these can be also converted back to lists using list comprehensions. This makes them fully compatible with numpy.ndarray, so the following expressions are completely valid:

>>> Matrix4.translation(np.array([1.5, 0.7, 3.3])) Matrix(1, 0, 0, 1.5, 0, 1, 0, 0.7, 0, 0, 1, 3.3, 0, 0, 0, 1)

>>> m = Matrix4.scaling((0.5, 0.5, 1.0)) >>> np.array(m.diagonal()) array([0.5, 0.5, 1. , 1. ], dtype=float32)

For matrices it’s a bit more complicated, since Magnum is using
column-major layout while numpy defaults to row-major (but can do
column-major as well). To ensure proper conversions, the buffer protocol
implementation for matrix types handles the layout conversion as well.
While the matrix are implicitly convertible from/to types implementing a
buffer protocol, they *are not* implicitly convertible from/to plain tuples
like vectors are.

To simplify the implementation, Magnum matrices are convertible only from
32-bit and 64-bit floating-point types (`'f'`

and `'d'`

numpy
`dtype`

). In the other direction, unless overriden using `dtype`

or
`order`

, the created numpy array matches Magnum data type and layout:

>>> a = Matrix3(np.array( ... [[1.0, 2.0, 3.0], ... [4.0, 5.0, 6.0], ... [7.0, 8.0, 9.0]])) >>> a[0] # first column Vector(1, 4, 7)

>>> b = np.array(Matrix3.rotation(Deg(45.0))) >>> b.strides[0] # column-major storage 4 >>> b[0] # first column, 32-bit floats array([ 0.70710677, -0.70710677, 0. ], dtype=float32)

>>> c = np.array(Matrix3.rotation(Deg(45.0)), order='C', dtype='d') >>> c.strides[0] # row-major storage (overriden) 24 >>> c[0] # first column, 64-bit floats (overriden) array([ 0.70710677, -0.70710677, 0. ])

## Major differences to the C++ API

All vector and matrix classes implement

`len()`

, which is used instead of e.g. Math::Vector::Size. Works on both classes and instances.`Math::gather()`

and`Math::scatter()`

operations are implemented as real swizzles:>>> a = Vector4(1.5, 0.3, -1.0, 1.0) >>> b = Vector4(7.2, 2.3, 1.1, 0.0) >>> a.wxy = b.xwz >>> a Vector(0, 1.1, -1, 7.2)

`mat[a][b] = c`

on matrices doesn’t do the expected thing, use`mat[a, b] = c`

instead`Math::BoolVector::set()`

doesn’t exist, use`[]`

insteadWhile both boolean and bitwise operations on

`Math::BoolVector`

behave the same to ensure consistency in generic code, this is not possible to do in Python. Here the boolean operations behave like if`any()`

was applied before doing the operation.

### Static constructors and instance method / property overloads

While not common in Python, the Matrix4.scaling() / Matrix4.rotation()
methods mimic the C++ equivalent — calling `Matrix4.scaling(vec)`

will return a scaling matrix, while `mat.scaling()`

returns the 3x3
scaling part of the matrix. With Matrix4.translation, it’s a bit more
involved — calling `Matrix4.translation(vec)`

will return a
translation matrix, while `mat.translation`

is a read-write property
accessing the fourth column of the matrix. Similarly for the Matrix3
class.

## Functions

- def acos(arg0: float, /) -> Rad
- Arc cosine
- def angle(normalized_a: Vector2, normalized_b: Vector2) -> Rad
- Angle between normalized vectors
- def angle(normalized_a: Vector3, normalized_b: Vector3) -> Rad
- Angle between normalized vectors
- def angle(normalized_a: Vector4, normalized_b: Vector4) -> Rad
- Angle between normalized vectors
- def angle(normalized_a: Vector2d, normalized_b: Vector2d) -> Rad
- Angle between normalized vectors
- def angle(normalized_a: Vector3d, normalized_b: Vector3d) -> Rad
- Angle between normalized vectors
- def angle(normalized_a: Vector4d, normalized_b: Vector4d) -> Rad
- Angle between normalized vectors
- def angle(arg0: Quaternion, arg1: Quaternion, /) -> Rad
- Angle between normalized quaternions
- def angle(arg0: Quaterniond, arg1: Quaterniond, /) -> Rad
- Angle between normalized quaternions
- def asin(arg0: float, /) -> Rad
- Arc sine
- def atan(arg0: float, /) -> Rad
- Arc tangent
- def cos(arg0: Rad, /) -> float
- Cosine
- def cross(arg0: Vector2, arg1: Vector2, /) -> float
- 2D cross product
- def cross(arg0: Vector3, arg1: Vector3, /) -> Vector3
- Cross product
- def cross(arg0: Vector2d, arg1: Vector2d, /) -> float
- 2D cross product
- def cross(arg0: Vector3d, arg1: Vector3d, /) -> Vector3d
- Cross product
- def dot(arg0: Vector2i, arg1: Vector2i, /) -> int
- Dot product of two vectors
- def dot(arg0: Vector3i, arg1: Vector3i, /) -> int
- Dot product of two vectors
- def dot(arg0: Vector4i, arg1: Vector4i, /) -> int
- Dot product of two vectors
- def dot(arg0: Vector2ui, arg1: Vector2ui, /) -> int
- Dot product of two vectors
- def dot(arg0: Vector3ui, arg1: Vector3ui, /) -> int
- Dot product of two vectors
- def dot(arg0: Vector4ui, arg1: Vector4ui, /) -> int
- Dot product of two vectors
- def dot(arg0: Vector2, arg1: Vector2, /) -> float
- Dot product of two vectors
- def dot(arg0: Vector3, arg1: Vector3, /) -> float
- Dot product of two vectors
- def dot(arg0: Vector4, arg1: Vector4, /) -> float
- Dot product of two vectors
- def dot(arg0: Vector2d, arg1: Vector2d, /) -> float
- Dot product of two vectors
- def dot(arg0: Vector3d, arg1: Vector3d, /) -> float
- Dot product of two vectors
- def dot(arg0: Vector4d, arg1: Vector4d, /) -> float
- Dot product of two vectors
- def dot(arg0: Quaternion, arg1: Quaternion, /) -> float
- Dot product between two quaternions
- def dot(arg0: Quaterniond, arg1: Quaterniond, /) -> float
- Dot product between two quaternions
- def intersect(arg0: Range1D, arg1: Range1D, /) -> Range1D
- intersect two ranges
- def intersect(arg0: Range2D, arg1: Range2D, /) -> Range2D
- intersect two ranges
- def intersect(arg0: Range3D, arg1: Range3D, /) -> Range3D
- intersect two ranges
- def intersect(arg0: Range1Di, arg1: Range1Di, /) -> Range1Di
- intersect two ranges
- def intersect(arg0: Range2Di, arg1: Range2Di, /) -> Range2Di
- intersect two ranges
- def intersect(arg0: Range3Di, arg1: Range3Di, /) -> Range3Di
- intersect two ranges
- def intersect(arg0: Range1Dd, arg1: Range1Dd, /) -> Range1Dd
- intersect two ranges
- def intersect(arg0: Range2Dd, arg1: Range2Dd, /) -> Range2Dd
- intersect two ranges
- def intersect(arg0: Range3Dd, arg1: Range3Dd, /) -> Range3Dd
- intersect two ranges
- def intersects(arg0: Range1D, arg1: Range1D, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range2D, arg1: Range2D, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range3D, arg1: Range3D, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range1Di, arg1: Range1Di, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range2Di, arg1: Range2Di, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range3Di, arg1: Range3Di, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range1Dd, arg1: Range1Dd, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range2Dd, arg1: Range2Dd, /) -> bool
- Whether two ranges intersect
- def intersects(arg0: Range3Dd, arg1: Range3Dd, /) -> bool
- Whether two ranges intersect
- def join(arg0: Range1D, arg1: Range1D, /) -> Range1D
- Join two ranges
- def join(arg0: Range2D, arg1: Range2D, /) -> Range2D
- Join two ranges
- def join(arg0: Range3D, arg1: Range3D, /) -> Range3D
- Join two ranges
- def join(arg0: Range1Di, arg1: Range1Di, /) -> Range1Di
- Join two ranges
- def join(arg0: Range2Di, arg1: Range2Di, /) -> Range2Di
- Join two ranges
- def join(arg0: Range3Di, arg1: Range3Di, /) -> Range3Di
- Join two ranges
- def join(arg0: Range1Dd, arg1: Range1Dd, /) -> Range1Dd
- Join two ranges
- def join(arg0: Range2Dd, arg1: Range2Dd, /) -> Range2Dd
- Join two ranges
- def join(arg0: Range3Dd, arg1: Range3Dd, /) -> Range3Dd
- Join two ranges
- def lerp(normalized_a: Quaternion, normalized_b: Quaternion, t: float) -> Quaternion
- Linear interpolation of two quaternions
- def lerp(normalized_a: Quaterniond, normalized_b: Quaterniond, t: float) -> Quaterniond
- Linear interpolation of two quaternions
- def lerp_shortest_path(normalized_a: Quaternion, normalized_b: Quaternion, t: float) -> Quaternion
- Linear shortest-path interpolation of two quaternions
- def lerp_shortest_path(normalized_a: Quaterniond, normalized_b: Quaterniond, t: float) -> Quaterniond
- Linear shortest-path interpolation of two quaternions
- def sin(arg0: Rad, /) -> float
- Sine
- def sincos(arg0: Rad, /) -> typing.Tuple[float, float]
- Sine and cosine
- def slerp(normalized_a: Quaternion, normalized_b: Quaternion, t: float) -> Quaternion
- Spherical linear interpolation of two quaternions
- def slerp(normalized_a: Quaterniond, normalized_b: Quaterniond, t: float) -> Quaterniond
- Spherical linear interpolation of two quaternions
- def slerp_shortest_path(normalized_a: Quaternion, normalized_b: Quaternion, t: float) -> Quaternion
- Spherical linear shortest-path interpolation of two quaternions
- def slerp_shortest_path(normalized_a: Quaterniond, normalized_b: Quaterniond, t: float) -> Quaterniond
- Spherical linear shortest-path interpolation of two quaternions
- def tan(arg0: Rad, /) -> float
- Tangent

## Data

- e = 2.718281828459045
- Euler’s number
- inf = inf
- Positive
- nan = nan
- Quiet NaN
- pi = 3.141592653589793
- pi_half = 1.5707963267948966
- Half of a
- pi_quarter = 0.7853981633974483
- Quarter of a
- sqrt2 = 1.414213562373095
- Square root of 2
- sqrt3 = 1.7320508075688772
- Square root of 3
- sqrt_half = 0.7071067811865475
- Square root of
- tau = 6.283185307179586
- , or