Struct Matrix
Square (NxN) matrix.
struct Matrix(T, ulong N)
;
Implementation notes:
- The storage order is column-major.
- Affine vector of 4x4 matrix is in the 4th column (as in OpenGL).
- Elements are stored in a fixed manner, so it is impossible to change matrix size once it's created.
- Actual data is allocated as a static array, so no references, no GC touching. When you pass a Matrix by value, it will be safely copied.
- This implementation is not perfect (as for now) for dealing with really big matrices, but ideal for smaller ones, e.g. those which are meant to be manipulated in real-time (in game engines, rendering pipelines etc).
Constructors
Name | Description |
---|---|
this
(arr)
|
Create matrix from array. This is a convenient way to deal with arrays of "classic" layout: the storage order in an array should be row-major |
Fields
Name | Type | Description |
---|---|---|
arrayof
|
T[N*N] | Linear array representing elements column by column |
Properties
Name | Type | Description |
---|---|---|
adjugate [get]
|
Matrix!(T,N) | Adjugate and cofactor matrices |
cofactor [get]
|
Matrix!(T,N) | Adjugate and cofactor matrices |
elements [set]
|
string | Symbolic element access |
inverse [get]
|
Matrix!(T,N) | Inverse of a matrix |
isAffine [get]
|
bool | Check if matrix represents affine transformation |
isSingular [get]
|
bool | Return true if matrix is singular |
negative [get]
|
Matrix!(T,N) | Negative matrix |
toString [get]
|
string | Convert to string |
transposed [get]
|
Matrix!(T,N) | Return the transposed matrix |
Methods
Name | Description |
---|---|
determinant
()
|
Determinant (of upper-left 3x3 portion for 4x4 matrices) |
getRow
(i)
|
Row/column manipulations |
identity
()
|
Return identity matrix |
invert
()
|
Invert |
invRotate
(v)
|
Rotate a vector by the inverse 3x3 upper-left portion of the matrix |
opBinary
(mat)
|
Matrix + Matrix |
opBinary
(mat)
|
Matrix - Matrix |
opBinary
(mat)
|
Matrix * Matrix |
opBinary
(k)
|
Matrix * T |
opBinaryRight
(v)
|
Multiply column vector by the matrix |
opBinaryRight
(v)
|
Multiply column 3D vector by the affine 4x4 matrix |
opEquals
(that)
|
Compare two matrices. |
opIndex
(i, j)
|
T = Matrix[i, j] |
opIndex
(index)
|
T = Matrix[index] Indices start with 0 |
opIndexAssign
(t, i, j)
|
Matrix[i, j] = T |
opIndexAssign
(t, index)
|
Matrix[index] = T Indices start with 0 |
opOpAssign
(mat)
|
Matrix += Matrix |
opOpAssign
(mat)
|
Matrix -= Matrix |
opOpAssign
(mat)
|
Matrix *= Matrix |
opOpAssign
(k)
|
Matrix *= T |
opSliceAssign
(t, index1, index2)
|
Matrix4x4!(T)[index1..index2] = T |
opSliceAssign
(t)
|
Matrix[] = T |
rotate
(v)
|
Rotate a vector by the 3x3 upper-left portion of the matrix |
setIdentity
()
|
Set to identity |
transpose
()
|
Transpose |
zero
()
|
Return zero matrix |
Aliases
Name | Description |
---|---|
affine
|
Check if matrix represents affine transformation |
Example
auto m1 = matrixf(
1, 2, 0, 6,
4, 6, 3, 1,
2, 7, 8, 2,
0, 5, 2, 1
);
auto m2 = matrixf(
0, 3, 7, 1,
1, 0, 2, 5,
1, 9, 2, 6,
5, 2, 0, 0
);
assert(m1 * m2 == matrixf(
32, 15, 11, 11,
14, 41, 46, 52,
25, 82, 44, 85,
12, 20, 14, 37)
);
auto m3 = Matrix4f .identity;
assert(m3 == matrixf(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1)
);
m3[12] = 1;
m3 .a24 = 2;
m3 .a34 = 3;
m3[1..4] = 0;
assert(m3[12] == 1);
assert(m1 .determinant3x3 == -25);
assert(m1 .determinant == 567);
assert(m1 .singular == false);
assert(m1 .affine == false);
assert(m1 .transposed == matrixf(
1, 4, 2, 0,
2, 6, 7, 5,
0, 3, 8, 2,
6, 1, 2, 1)
);
auto m4 = matrixf(
0, 3, 2,
1, 0, 8,
0, 1, 0
);
assert(m4 .inverse == matrixf(
-4, 1, 12,
-0, 0, 1,
0.5, 0, -1.5)
);
assert(m1 .adjugate == matrixf(
7, 148, -16, -158,
-14, 28, -49, 154,
-14, -53, 113, -89,
98, -34, 19, -25)
);
assert(m1 .cofactor == matrixf(
7, -14, -14, 98,
148, 28, -53, -34,
-16, -49, 113, 19,
-158, 154, -89, -25)
);
m1 .transpose();
assert(m1 == matrixf(
1, 4, 2, 0,
2, 6, 7, 5,
0, 3, 8, 2,
6, 1, 2, 1)
);
Matrix2f m5;
m5[] = 1.0f;
m5 += matrixf(
2, 2,
2, 2
);
m5 *= m5;
assert(m5 == matrixf(
18, 18,
18, 18)
);
m5 = m5 - m5;
assert(m5 == Matrix2f .zero);
Matrix2f m6 = matrixf(
2, 2,
2, 2
);
m6 = m6 * m6;
m6 = m6 * 2;
m6 *= 2;
assert(m6 == matrixf(
32, 32,
32, 32)
);
assert(m6 .determinant == 0);
Matrix3f m7 = matrixf(
3, 3, 3,
3, 3, 3,
3, 3, 3
);
m7 = m7 * m7;
assert(m7 == matrixf(
27, 27, 27,
27, 27, 27,
27, 27, 27)
);
Matrix2f m8 = matrixf(
1, 0,
0, 1
);
m8 .invert();
assert(m8 == matrixf(
1, 0,
0, 1)
);
assert(m8 .negative == matrixf(
-1, 0,
0, -1)
);
auto m9 = matrixf(
1, 0, 0, 2,
0, 1, 0, 3,
0, 0, 1, 4,
0, 0, 0, 1
);
assert(m9 .affine == true);
assert(m9 .inverse == matrixf(
1, 0, 0, -2,
0, 1, 0, -3,
0, 0, 1, -4,
0, 0, 0, 1)
);
bool isAlmostZero3(Vector3f v)
{
float e = 0.002f;
return abs(v .x) < e &&
abs(v .y) < e &&
abs(v .z) < e;
}
Vector3f v1 = Vector3f(1, 0, 0);
v1 = v1 * matrixf(
1, 0, 0, 2,
0, 1, 0, 3,
0, 0, 1, 4,
0, 0, 0, 1
);
assert(v1 == Vector3f(3, 3, 4));
Vector3f v2 = Vector3f(0, 1, 0);
const float a1 = PI * 0.5f;
v2 = matrixf(
1, 0, 0, 0,
0, cos(a1), -sin(a1), 0,
0, sin(a1), cos(a1), 0,
0, 0, 0, 1
) .rotate(v2);
assert(isAlmostZero3(v2 - Vector3f(0, 0, 1)));
Vector3f v3 = Vector3f(0, 1, 0);
v3 = matrixf(
1, 0, 0, 0,
0, cos(a1), -sin(a1), 0,
0, sin(a1), cos(a1), 0,
0, 0, 0, 1
) .invRotate(v3);
assert(isAlmostZero3(v3 - Vector3f(0, 0, -1)));
auto m10 = matrixf(
1, 2, 3,
3, 2, 1,
2, 3, 1
);
Vector3f r0 = m10 .getRow(0);
assert(isAlmostZero3(r0 - Vector3f(1, 2, 3)));
Vector3f c0 = m10 .getColumn(0);
assert(isAlmostZero3(c0 - Vector3f(1, 3, 2)));
m10 .setRow(2, Vector3f(1, 1, 1));
Vector3f r2 = m10 .getRow(2);
assert(isAlmostZero3(r2 - Vector3f(1, 1, 1)));
m10 .setColumn(2, Vector3f(1, 1, 1));
Vector3f c2 = m10 .getColumn(2);
assert(isAlmostZero3(c2 - Vector3f(1, 1, 1)));
m10 .swapRows(0, 1);
Vector3f r1 = m10 .getRow(1);
assert(isAlmostZero3(r1 - Vector3f(1, 2, 1)));
m10 .swapColumns(1, 2);
Vector3f c1 = m10 .getColumn(1);
assert(isAlmostZero3(c1 - Vector3f(1, 1, 1)));
Matrix2f m11 = matrixf(
2, 1,
2, 1
);
assert(m11 .adjugate == matrixf(
1, -1,
-2, 2)
);
assert(m11 .cofactor == matrixf(
1, -2,
-1, 2)
);
assert(m11 .flatten == [2, 1, 2, 1]);
assert(m11 .elements("a") == "T a11;T a21;T a12;T a22;");
Matrix!(float, 1) m12 = matrixf(1);
assert(m12 .determinant == 1);
assert(m12 .inverse == matrixf(1));
assert(m12 .adjugate == matrixf(1));
assert(m12 .cofactor == matrixf(1));