silk.geometry.matrix.
Square 3x3 and 4x4 matrices for projective and three-dimensional transforms.
When to use#
Use Matrix3 for a projective transform of a plane, such as a perspective-correct image warp:
a homography that silk.geometry.affine.Affine2 cannot express. Use Matrix4 for transforms
in space, such as a CSS matrix3d, a perspective, or a 3D rotation, and to project those
transforms back onto a plane. Use Affine2 for every transform of a plane that keeps parallel
lines parallel; it is smaller and cheaper.
Details#
A matrix is a Copy struct that holds its entries in the public array values in column-major
order: entry (row, column) is values[column * size + row]. That is the order of WGSL, GLSL,
and CSS matrix3d, so a matrix copies to a GPU uniform or from CSS as written. A matrix
multiplies a column vector: left * right applies right first, then left.
Matrix3.project and Matrix4.project divide by the homogeneous w coordinate and return
None where w is zero. Matrix3.transformHomogeneous and Matrix4.transformHomogeneous
return the coordinates before that division, for renderers that must clip against w.
Examples#
Round-trip a point through a perspective#
import silk.geometry.matrix { Matrix4 }
import silk.geometry.point { Point3 }
import silk.core.option { Option }
pub fn main() -> i32 {
let camera = Matrix4<f64>.perspective(100.0) * Matrix4<f64>.rotationY(0.5)
let inverse = match camera.inverse() {
Option<Matrix4<f64>>.Some { value } => value
Option<Matrix4<f64>>.None => {
return 1
}
}
let point = Point3<f64>.new(10.0, 20.0, 5.0)
let back = match (inverse * camera).project(point) {
Option<Point3<f64>>.Some { value } => value
Option<Point3<f64>>.None => {
return 2
}
}
if back.x < 9.999999 || back.x > 10.000001 || back.z < 4.999999 || back.z > 5.000001 {
return 3
}
return 0
}Import as Matrix3 with import silk.geometry.matrix { Matrix3 }.
Public declarations: 2.
Matrix3#
pub struct Matrix3<T>A 3x3 matrix of number type T, stored in column-major order.
When to use#
Use Matrix3 for a projective transform of a plane (a homography). Use
silk.geometry.affine.Affine2 when the transform keeps parallel lines parallel.
Details#
Entry (row, column) is values[column * 3 + row]. The matrix maps (x, y) through the
homogeneous vector (x, y, 1): project divides the first two results by the third. left *
right applies right first. &a == &b compares all nine entries when T: Equal.
Field values#
pub values: [T; 9]The nine entries in column-major order: entry (row, column) is values[column * 3 + row].
Implementation Copy for Matrix3<T>#
impl<T: Copy> Copy for Matrix3<T>Implementation Matrix3<T>#
impl<T> Matrix3<T>Associated function new#
pub fn new(values: [T; 9]) -> Matrix3<T>Returns the matrix with values in column-major order.
Implementation Matrix3<T>#
impl<T: Copy> Matrix3<T>Method at#
pub fn at(self: &Self, row: usize, column: usize) -> TReturns entry (row, column), where both count from zero.
Gotchas#
The program traps if row or column is greater than 2.
Method transpose#
pub fn transpose(self: Self) -> Matrix3<T>Returns the matrix with rows and columns exchanged.
Implementation Matrix3<T>#
impl<T: Copy + Zero + One> Matrix3<T>Associated function identity#
pub fn identity() -> Matrix3<T>Returns the matrix that maps every point to itself.
Associated function fromAffine#
pub fn fromAffine(transform: Affine2<T>) -> Matrix3<T>Returns the matrix of the same transform as transform: [xx xy dx; yx yy dy; 0 0 1].
Implementation Matrix3<T>#
impl<T: Copy + Equal + Zero + One> Matrix3<T>Method toAffine#
pub fn toAffine(self: Self) -> Option<Affine2<T>>Returns the affine transform of the matrix, or None when its last row is not [0 0 1].
Details#
A matrix whose last row is [0 0 1] keeps parallel lines parallel. Any other last row
describes a perspective, which Affine2 cannot hold.
Implementation Matrix3<T>#
impl<T: Copy + Add<T, T> + Subtract<T, T> + Multiply<T, T>> Matrix3<T>Method determinant#
pub fn determinant(self: Self) -> TReturns the determinant. Zero means the matrix has no inverse.
Method transformHomogeneous#
pub fn transformHomogeneous(self: Self, point: Point2<T>) -> Vector3<T>Returns (x', y', w): point mapped through (x, y, 1) before the division by w.
When to use#
Use transformHomogeneous when the sign of w matters, such as to clip the part of a plane
behind a projection. Use project for the divided point.
Implementation Matrix3<T>#
impl<T: Copy + Equal + Zero + Add<T, T> + Subtract<T, T> + Multiply<T, T> + Divide<T, T>> Matrix3<
T
>Method project#
pub fn project(self: Self, point: Point2<T>) -> Option<Point2<T>>Returns point mapped through the matrix and divided by w, or None where w is zero.
Gotchas#
A negative w still gives a point, which is the mirror image of a point behind the
projection. Use transformHomogeneous to test the sign of w first.
Implementation Matrix3<T>#
impl<
T: Copy + Equal + Zero + One + Float + Add<T, T> + Subtract<T, T> + Multiply<T, T> + Divide<T, T>
> Matrix3<T>Method inverse#
pub fn inverse(self: Self) -> Option<Matrix3<T>>Returns the matrix that undoes self, or None when self has no finite inverse.
Details#
None means the determinant is zero, or that the inverse has an infinite or NaN entry, such
as when an input entry is infinite or NaN.
Implementation Multiply<Matrix3<T>, Matrix3<T>> for Matrix3<T>#
impl<T: Copy + Zero + Add<T, T> + Multiply<T, T>> Multiply<Matrix3<T>, Matrix3<T>> for Matrix3<T>Operation multiply#
fn multiply(left: Self, right: Self) -> SelfImplementation Equal for Matrix3<T>#
impl<T: Equal> Equal for Matrix3<T>Operation equals#
fn equals(left: &Self, right: &Self) -> boolMatrix4#
pub struct Matrix4<T>A 4x4 matrix of number type T, stored in column-major order.
When to use#
Use Matrix4 for transforms in space, such as CSS matrix3d, perspective, and 3D rotations.
Use silk.geometry.affine.Affine2 for a transform of a plane.
Details#
Entry (row, column) is values[column * 4 + row], the order of CSS matrix3d(...) arguments
and of WGSL mat4x4. The matrix maps (x, y, z) through the homogeneous vector (x, y, z, 1):
project divides the first three results by the fourth. left * right applies right first.
&a == &b compares all sixteen entries when T: Equal.
Field values#
pub values: [T; 16]The sixteen entries in column-major order: entry (row, column) is values[column * 4 +
row].
Implementation Copy for Matrix4<T>#
impl<T: Copy> Copy for Matrix4<T>Implementation Matrix4<T>#
impl<T> Matrix4<T>Associated function new#
pub fn new(values: [T; 16]) -> Matrix4<T>Returns the matrix with values in column-major order, the order of CSS matrix3d.
Implementation Matrix4<T>#
impl<T: Copy> Matrix4<T>Method at#
pub fn at(self: &Self, row: usize, column: usize) -> TReturns entry (row, column), where both count from zero.
Gotchas#
The program traps if row or column is greater than 3.
Method transpose#
pub fn transpose(self: Self) -> Matrix4<T>Returns the matrix with rows and columns exchanged.
Implementation Matrix4<T>#
impl<T: Copy + Zero + One> Matrix4<T>Associated function identity#
pub fn identity() -> Matrix4<T>Returns the matrix that maps every point to itself.
Associated function fromAffine#
pub fn fromAffine(transform: Affine2<T>) -> Matrix4<T>Returns the matrix of transform acting on x and y, with z unchanged.
Details#
This is the CSS rule for a 2D transform in a 3D context: matrix(a, b, c, d, e, f) equals
matrix3d(a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, e, f, 0, 1).
Associated function translation#
pub fn translation(offset: Vector3<T>) -> Matrix4<T>Returns the matrix that moves every point by offset.
Associated function scale#
pub fn scale(x: T, y: T, z: T) -> Matrix4<T>Returns the matrix that multiplies x by x, y by y, and z by z around the origin.
Implementation Matrix4<T>#
impl<T: Copy + Equal + Zero + One> Matrix4<T>Method toAffine#
pub fn toAffine(self: Self) -> Option<Affine2<T>>Returns the affine transform of the matrix, or None when it is not a 2D transform.
Details#
The result is Some exactly when the matrix leaves z and w alone, as CSS "is 2D" requires:
entries (2, 0), (3, 0), (2, 1), (3, 1), (0, 2), (1, 2), (3, 2), and (2, 3) are
zero and entries (2, 2) and (3, 3) are one.
Implementation Matrix4<T>#
impl<T: Copy + Zero + One + Float + Subtract<T, T>> Matrix4<T>Associated function rotationX#
pub fn rotationX(radians: T) -> Matrix4<T>Returns the matrix that rotates by radians around the x axis, turning positive y toward
positive z.
Associated function rotationY#
pub fn rotationY(radians: T) -> Matrix4<T>Returns the matrix that rotates by radians around the y axis, turning positive z toward
positive x.
Associated function rotationZ#
pub fn rotationZ(radians: T) -> Matrix4<T>Returns the matrix that rotates by radians around the z axis, turning positive x toward
positive y.
Details#
On the x-y plane this is silk.geometry.affine.Affine2.rotation with the same angle, which is
clockwise in a y-down space such as CSS.
Implementation Matrix4<T>#
impl<T: Copy + Zero + One + Subtract<T, T> + Divide<T, T>> Matrix4<T>Associated function perspective#
pub fn perspective(distance: T) -> Matrix4<T>Returns the CSS perspective(distance) matrix: a viewer at distance along positive z.
Details#
The matrix is the identity with entry (3, 2) set to -1 / distance, so a point at depth z
scales by distance / (distance - z) after project.
Gotchas#
A zero distance divides by zero. CSS treats perspective(0) as no perspective; pass the
identity in that case.
Implementation Matrix4<T>#
impl<T: Copy + Add<T, T> + Subtract<T, T> + Multiply<T, T>> Matrix4<T>Method determinant#
pub fn determinant(self: Self) -> TReturns the determinant. Zero means the matrix has no inverse.
Method transformHomogeneous#
pub fn transformHomogeneous(self: Self, point: Point3<T>) -> [T; 4]Returns (x', y', z', w): point mapped through (x, y, z, 1) before the division by w.
When to use#
Use transformHomogeneous when the sign of w matters, such as to clip geometry behind the
viewer of a perspective. Use project for the divided point.
Implementation Matrix4<T>#
impl<T: Copy + Equal + Zero + Add<T, T> + Subtract<T, T> + Multiply<T, T> + Divide<T, T>> Matrix4<
T
>Method project#
pub fn project(self: Self, point: Point3<T>) -> Option<Point3<T>>Returns point mapped through the matrix and divided by w, or None where w is zero.
Gotchas#
A negative w still gives a point, which is the mirror image of a point behind the viewer.
Use transformHomogeneous to test the sign of w first.
Method projectPoint2#
pub fn projectPoint2(self: Self, point: Point2<T>) -> Option<Point2<T>>Returns the point of the plane z = 0 mapped through the matrix, flattened onto the x-y
plane, or None where w is zero.
When to use#
Use projectPoint2 to draw a 2D element under a CSS 3D transform: the element lies in the
plane z = 0, and the screen shows the x and y of each projected point.
Implementation Matrix4<T>#
impl<
T: Copy + Equal + Zero + One + Float + Add<T, T> + Subtract<T, T> + Multiply<T, T> + Divide<T, T>
> Matrix4<T>Method inverse#
pub fn inverse(self: Self) -> Option<Matrix4<T>>Returns the matrix that undoes self, or None when self has no finite inverse.
Details#
The inverse is the adjugate divided by the determinant. None means the determinant is zero,
or that the inverse has an infinite or NaN entry, such as when an input entry is infinite or
NaN.
Implementation Multiply<Matrix4<T>, Matrix4<T>> for Matrix4<T>#
impl<T: Copy + Zero + Add<T, T> + Multiply<T, T>> Multiply<Matrix4<T>, Matrix4<T>> for Matrix4<T>Operation multiply#
fn multiply(left: Self, right: Self) -> SelfImplementation Equal for Matrix4<T>#
impl<T: Equal> Equal for Matrix4<T>Operation equals#
fn equals(left: &Self, right: &Self) -> boolCategory: Geometry.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.