Matrix

Square (NxN) matrix.

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).

struct Matrix (
T
size_t N
) {}

Constructors

this
this(F[] 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

Members

Aliases

affine
alias affine = isAffine

Check if matrix represents affine transformation

det
alias det = determinant
Undocumented in source.
determinant
alias determinant = determinant3x3
Undocumented in source.
singular
alias singular = isSingular
Undocumented in source.

Functions

adjugate
Matrix!(T, N) adjugate()

Adjugate and cofactor matrices

adjugate
Matrix!(T, N) adjugate()
Undocumented in source.
adjugate
Matrix!(T, N) adjugate()
Undocumented in source.
cofactor
Matrix!(T, N) cofactor()

Adjugate and cofactor matrices

cofactor
Matrix!(T, N) cofactor()
Undocumented in source. Be warned that the author may not have intended to support it.
cofactor
Matrix!(T, N) cofactor()
Undocumented in source.
determinant
T determinant()

Determinant (of upper-left 3x3 portion for 4x4 matrices)

determinant
T determinant()
Undocumented in source.
determinant
T determinant(size_t n)
Undocumented in source.
determinant3x3
T determinant3x3()
Undocumented in source.
flatten
auto flatten()
Undocumented in source. Be warned that the author may not have intended to support it.
getColumn
Vector!(T, N) getColumn(size_t j)
Undocumented in source. Be warned that the author may not have intended to support it.
getRow
Vector!(T, N) getRow(size_t i)

Row/column manipulations

invRotate
Vector!(T, 3) invRotate(Vector!(T, 3) v)

Rotate a vector by the inverse 3x3 upper-left portion of the matrix

inverse
Matrix!(T, N) inverse()

Inverse of a matrix

inverse
Matrix!(T, N) inverse()
Undocumented in source.
inverse
Matrix!(T, N) inverse()
Undocumented in source.
inverse
Matrix!(T, N) inverse()
Undocumented in source.
invert
void invert()

Invert

isAffine
bool isAffine()

Check if matrix represents affine transformation

isSingular
bool isSingular()

Return true if matrix is singular

negative
Matrix!(T, N) negative()

Negative matrix

opBinary
Matrix!(T, N) opBinary(Matrix!(T, N) mat)

Matrix + Matrix

opBinary
Matrix!(T, N) opBinary(Matrix!(T, N) mat)

Matrix - Matrix

opBinary
Matrix!(T, N) opBinary(Matrix!(T, N) mat)

Matrix * Matrix

opBinary
Matrix!(T, N) opBinary(T k)

Matrix * T

opBinaryRight
Vector!(T, 2) opBinaryRight(Vector!(T, 2) v)

Multiply column vector by the matrix

opBinaryRight
Vector!(T, 3) opBinaryRight(Vector!(T, 3) v)
Undocumented in source.
opBinaryRight
Vector!(T, N) opBinaryRight(Vector!(T, N) v)
Undocumented in source.
opBinaryRight
Vector!(T, 3) opBinaryRight(Vector!(T, 3) v)

Multiply column 3D vector by the affine 4x4 matrix

opEquals
bool opEquals(Matrix!(T, N) that)

Compare two matrices.

opIndex
T opIndex(size_t i, size_t j)

T = Matrix[i, j]

opIndex
T opIndex(size_t index)

T = Matrixindex Indices start with 0

opIndexAssign
T opIndexAssign(T t, size_t i, size_t j)

Matrix[i, j] = T

opIndexAssign
T opIndexAssign(T t, size_t index)

Matrixindex = T Indices start with 0

opOpAssign
Matrix!(T, N) opOpAssign(Matrix!(T, N) mat)

Matrix += Matrix

opOpAssign
Matrix!(T, N) opOpAssign(Matrix!(T, N) mat)

Matrix -= Matrix

opOpAssign
Matrix!(T, N) opOpAssign(Matrix!(T, N) mat)

Matrix *= Matrix

opOpAssign
Matrix!(T, N) opOpAssign(T k)

Matrix *= T

opSliceAssign
T[] opSliceAssign(T t, size_t index1, size_t index2)

Matrix4x4!(T)index1..index2 = T

opSliceAssign
T[] opSliceAssign(T t)

Matrix[] = T

rotate
Vector!(T, 3) rotate(Vector!(T, 3) v)

Rotate a vector by the 3x3 upper-left portion of the matrix

setColumn
void setColumn(size_t j, Vector!(T, N) v)
Undocumented in source. Be warned that the author may not have intended to support it.
setIdentity
void setIdentity()

Set to identity

setRow
void setRow(size_t i, Vector!(T, N) v)
Undocumented in source. Be warned that the author may not have intended to support it.
swapColumns
void swapColumns(size_t c1, size_t c2)
Undocumented in source. Be warned that the author may not have intended to support it.
swapRows
void swapRows(size_t r1, size_t r2)
Undocumented in source. Be warned that the author may not have intended to support it.
toString
string toString()

Convert to string

transpose
void transpose()

Transpose

transposed
Matrix!(T, N) transposed()

Return the transposed matrix

Static functions

identity
identity()

Return identity matrix

zero
zero()

Return zero matrix

Unions

__anonymous
union __anonymous

Matrix elements

Examples

1 auto m1 = matrixf(
2     1, 2, 0, 6,
3     4, 6, 3, 1,
4     2, 7, 8, 2,
5     0, 5, 2, 1
6 );
7 auto m2 = matrixf(
8     0, 3, 7, 1,
9     1, 0, 2, 5,
10     1, 9, 2, 6,
11     5, 2, 0, 0
12 );
13 assert(m1 * m2 == matrixf(
14     32, 15, 11, 11,
15     14, 41, 46, 52,
16     25, 82, 44, 85,
17     12, 20, 14, 37)
18 );
19 
20 auto m3 = Matrix4f.identity;
21 assert(m3 == matrixf(
22     1, 0, 0, 0,
23     0, 1, 0, 0,
24     0, 0, 1, 0,
25     0, 0, 0, 1)
26 );
27 
28 m3[12] = 1;
29 m3.a24 = 2;
30 m3.a34 = 3;
31 m3[1..4] = 0;
32 
33 assert(m3[12] == 1);
34 
35 assert(m1.determinant3x3 == -25);
36 assert(m1.determinant == 567);
37 
38 assert(m1.singular == false);
39 
40 assert(m1.affine == false);
41 
42 assert(m1.transposed == matrixf(
43     1, 4, 2, 0,
44     2, 6, 7, 5,
45     0, 3, 8, 2,
46     6, 1, 2, 1)
47 );
48 
49 auto m4 = matrixf(
50     0, 3, 2,
51     1, 0, 8,
52     0, 1, 0
53 );
54 
55 assert(m4.inverse == matrixf(
56     -4,   1, 12,
57     -0,   0,  1,
58      0.5, 0, -1.5)
59 );
60 
61 assert(m1.adjugate == matrixf(
62     7, 148, -16, -158,
63   -14,  28, -49,  154,
64   -14, -53, 113,  -89,
65    98, -34,  19,  -25)
66 );
67 
68 assert(m1.cofactor == matrixf(
69     7, -14, -14,  98,
70   148,  28, -53, -34,
71   -16, -49, 113,  19,
72  -158, 154, -89, -25)
73 );
74 
75 m1.transpose();
76 assert(m1 == matrixf(
77     1, 4, 2, 0,
78     2, 6, 7, 5,
79     0, 3, 8, 2,
80     6, 1, 2, 1)
81 );
82 
83 Matrix2f m5;
84 m5[] = 1.0f;
85 m5 += matrixf(
86   2, 2,
87   2, 2
88 );
89 m5 *= m5;
90 assert(m5 == matrixf(
91   18, 18,
92   18, 18)
93 );
94 
95 m5 = m5 - m5;
96 assert(m5 == Matrix2f.zero);
97 
98 Matrix2f m6 = matrixf(
99   2, 2,
100   2, 2
101 );
102 m6 = m6 * m6;
103 m6 = m6 * 2;
104 m6 *= 2;
105 assert(m6 == matrixf(
106   32, 32,
107   32, 32)
108 );
109 assert(m6.determinant == 0);
110 
111 Matrix3f m7 = matrixf(
112   3, 3, 3,
113   3, 3, 3,
114   3, 3, 3
115 );
116 m7 = m7 * m7;
117 assert(m7 == matrixf(
118   27, 27, 27,
119   27, 27, 27,
120   27, 27, 27)
121 );
122 
123 Matrix2f m8 = matrixf(
124     1, 0,
125     0, 1
126 );
127 m8.invert();
128 assert(m8 == matrixf(
129     1, 0,
130     0, 1)
131 );
132 assert(m8.negative == matrixf(
133    -1,  0,
134     0, -1)
135 );
136 
137 auto m9 = matrixf(
138     1, 0, 0, 2,
139     0, 1, 0, 3,
140     0, 0, 1, 4,
141     0, 0, 0, 1
142 );
143 assert(m9.affine == true);
144 assert(m9.inverse == matrixf(
145     1, 0, 0, -2,
146     0, 1, 0, -3,
147     0, 0, 1, -4,
148     0, 0, 0,  1)
149 );
150 
151 bool isAlmostZero3(Vector3f v)
152 {
153     float e = 0.002f;
154     return abs(v.x) < e &&
155            abs(v.y) < e &&
156            abs(v.z) < e;
157 }
158 
159 Vector3f v1 = Vector3f(1, 0, 0);
160 v1 = v1 * matrixf(
161     1, 0, 0, 2,
162     0, 1, 0, 3,
163     0, 0, 1, 4,
164     0, 0, 0, 1
165 );
166 assert(v1 == Vector3f(3, 3, 4));
167 
168 Vector3f v2 = Vector3f(0, 1, 0);
169 const float a1 = PI * 0.5f;
170 v2 = matrixf(
171     1, 0,        0,       0,
172     0, cos(a1), -sin(a1), 0,
173     0, sin(a1),  cos(a1), 0,
174     0, 0,        0,       1
175 ).rotate(v2);
176 assert(isAlmostZero3(v2 - Vector3f(0, 0, 1)));
177 
178 Vector3f v3 = Vector3f(0, 1, 0);
179 v3 = matrixf(
180     1, 0,        0,       0,
181     0, cos(a1), -sin(a1), 0,
182     0, sin(a1),  cos(a1), 0,
183     0, 0,        0,       1
184 ).invRotate(v3);
185 assert(isAlmostZero3(v3 - Vector3f(0, 0, -1)));
186 
187 auto m10 = matrixf(
188     1, 2, 3,
189     3, 2, 1,
190     2, 3, 1
191 );
192 
193 Vector3f r0 = m10.getRow(0);
194 assert(isAlmostZero3(r0 - Vector3f(1, 2, 3)));
195 
196 Vector3f c0 = m10.getColumn(0);
197 assert(isAlmostZero3(c0 - Vector3f(1, 3, 2)));
198 
199 m10.setRow(2, Vector3f(1, 1, 1));
200 Vector3f r2 = m10.getRow(2);
201 assert(isAlmostZero3(r2 - Vector3f(1, 1, 1)));
202 
203 m10.setColumn(2, Vector3f(1, 1, 1));
204 Vector3f c2 = m10.getColumn(2);
205 assert(isAlmostZero3(c2 - Vector3f(1, 1, 1)));
206 
207 m10.swapRows(0, 1);
208 Vector3f r1 = m10.getRow(1);
209 assert(isAlmostZero3(r1 - Vector3f(1, 2, 1)));
210 
211 m10.swapColumns(1, 2);
212 Vector3f c1 = m10.getColumn(1);
213 assert(isAlmostZero3(c1 - Vector3f(1, 1, 1)));
214 
215 Matrix2f m11 = matrixf(
216     2, 1,
217     2, 1
218 );
219 assert(m11.adjugate == matrixf(
220     1, -1,
221    -2,  2)
222 );
223 assert(m11.cofactor == matrixf(
224     1, -2,
225    -1,  2)
226 );
227 assert(m11.flatten == [2, 1, 2, 1]);
228 
229 assert(m11.elements("a") == "T a11;T a21;T a12;T a22;");
230 
231 Matrix!(float, 1) m12 = matrixf(1);
232 assert(m12.determinant == 1);
233 assert(m12.inverse == matrixf(1));
234 assert(m12.adjugate == matrixf(1));
235 assert(m12.cofactor == matrixf(1));

Meta