std/linear/matrix4
std/linear/src/matrix4.trb
Matrix4, the 4x4 matrix: the affine transformation of space - rotation, scale, shear and a translation - that a
scene graph is built out of.
The fields are the columns, and a column is where a basis vector lands; the fourth column is the translation. What is deliberately absent is a projection: a projection matrix depends on the clip space of the API that consumes it - how deep it is and which way it points - and this package knows nothing about an API. Those belong where that convention is known.
type Matrix4
type Matrix4<Scalar: Numeric = Float> with Add, Subtract, Multiply
An affine transformation of space, held as the four vectors its homogeneous basis lands on.
Vectors are columns and a transformation is applied on the left, so composing a after b is a * b and a chain
reads right to left, the way it does in mathematics.
Examples
const move = Matrix4.translation of: Vector3(1.0, 2.0, 3.0)
print move.transformedPoint(Vector3(0.0, 0.0, 0.0))
Related
Matrix3- the linear part on its own, and the affine form for the plane.Quaternion- a rotation that interpolates without shearing.
field xAxis
xAxis: Vector4<Scalar>
Where the first basis vector lands.
field yAxis
yAxis: Vector4<Scalar>
Where the second basis vector lands.
field zAxis
zAxis: Vector4<Scalar>
Where the third basis vector lands.
field wAxis
wAxis: Vector4<Scalar>
Where the origin lands: the translation, with a one in its fourth component.
const identity
static identity: Matrix4<Scalar>
The transformation that changes nothing, over whichever scalar is asked for: Matrix4<Int>.identity.
fn linearPart
fn linearPart(): Matrix3<Scalar>
The three rows and columns that are the linear part: the rotation, the scale and the shear, without the move.
fn translationPart
fn translationPart(): Vector3<Scalar>
The translation the transformation carries.
fn transposed
fn transposed(): Matrix4<Scalar>
The rows read as columns.
fn column
fn column(index: Int): Vector4<Scalar>
The column at that index. Panics outside 0..4.
fn at
fn at(row: Int, index: Int): Scalar
The cell in that row and that column. Panics outside 0..4.
fn row
fn row(index: Int): Vector4<Scalar>
The row at that index. Panics outside 0..4.
fn add
fn add(other: Matrix4<Scalar>): Matrix4<Scalar>
Cell by cell. Adding two transformations is not composing them; multiply is.
fn subtract
fn subtract(other: Matrix4<Scalar>): Matrix4<Scalar>
Cell by cell.
fn multiply
fn multiply(other: Matrix4<Scalar>): Matrix4<Scalar>
The composition: self after other.
fn applied
fn applied(to: Vector4<Scalar>): Vector4<Scalar>
The homogeneous vector transformed: the combination of the four columns.
It is a method and not matrix * vector, because a type has one namespace of members and multiply is already the
composition of two matrices.
fn transformedDirection
fn transformedDirection(direction: Vector3<Scalar>): Vector3<Scalar>
A direction, turned by the transformation: the translation is not applied.
fn determinant
fn determinant(): Scalar
The factor by which the transformation scales a volume of the homogeneous space, negative where it turns space
inside out and zero exactly where it flattens one - which is where Matrix4.inverse answers None.
print Matrix4.scaling(by: Vector3(2.0, 3.0, 4.0)).determinant()
fn scaling
static fn scaling(by: Vector3<Scalar>): Matrix4<Scalar>
A diagonal matrix: each axis scaled on its own, and the translation left at the origin.
fn translation
static fn translation(of: Vector3<Scalar>): Matrix4<Scalar>
The transformation that moves everything by that much and changes nothing else.
const move = Matrix4.translation of: Vector3(1.0, 0.0, 0.0)
print move.translationPart()
fn affine
static fn affine(linear: Matrix3<Scalar>, by: Vector3<Scalar>): Matrix4<Scalar>
The affine transformation that applies the linear part and then moves by by.
fn transformedPoint
fn transformedPoint(point: Vector3<Scalar>): Vector3<Scalar>
A point, moved by the transformation: the translation is applied.
extend Matrix4<Scalar> with Negate
extend<Scalar: Signed> Matrix4<Scalar> with Negate
Every cell turned around.
fn negate
fn negate(): Matrix4<Scalar>
Every cell with its sign flipped.
extend Matrix4<Scalar>
extend<Scalar: Real> Matrix4<Scalar>
What a division buys: the inverse of an affine transformation, and the general one.
fn inverseAffine
fn inverseAffine(): Matrix4<Scalar>?
The transformation that undoes this one, read as an affine transformation: the linear part is inverted and the
translation is carried back through it. None where the linear part has no inverse.
It answers nothing about the bottom row, which an affine transformation has as (0, 0, 0, 1) by construction.
fn inverse
fn inverse(): Matrix4<Scalar>?
The transformation that undoes this one, for a matrix of any shape: the adjugate - the transpose of the
sixteen cofactors - divided by the determinant. None where the determinant is zero, which is exactly where the
transformation flattens space and nothing can undo it.
Matrix4.inverseAffine is the short way for the matrices a scene graph is made of, and the two answer the same
transformation for one whose bottom row is (0, 0, 0, 1). Reach for this one where the bottom row is not that -
which in practice means a projection.
const move = Matrix4.translation of: Vector3(1.0, 2.0, 3.0)
print move.inverse()?.translationPart()
fn isCloseTo
fn isCloseTo(other: Matrix4<Scalar>, tolerance: Scalar): Bool
Whether every cell is within tolerance of the other matrix's.
extend Matrix4<Scalar> with Power<Int64>
extend<Scalar: Numeric> Matrix4<Scalar> with Power<Int64>
A whole power: the transformation applied that many times over.
fn power
fn power(exponent: Int64): Matrix4<Scalar>
turn ** 3 is turn * turn * turn, by squaring, and matrix ** 0 is the identity.
Panics
On a negative exponent, which is a power of the inverse: a matrix has one only over a Real scalar and only where
its determinant is not zero, so the caller asks for inverse() and raises that.