An N by M Matrix of T.
Examples:
// Matrix!(T=ElementType, N=Height, M=Width) can be initialized
// with an array of N*M elements, or by passing N*M values to the constructor.
auto m = Matrix!(float, 2, 3)(
7, 3, 2,
9, 1, 5,
);
// Elements can be accessed with [i] (i=0..N*M) and [row, column] (row=0..N, column=0..M)
assert(m[4] == 1);
assert(m[1, 1] == 1);
assert(m[0, 2] == 2);
// A matrix is default-initialied to just N*M default-initialized Ts.
{
Matrix!(float, 3, 3) a;
Matrix!(int, 2, 3) b;
assert(isNaN(a[2]));
assert(b[2] == 0);
}
// .zero gives a zero-filled matrix.
{
auto a = Matrix!(float, 3, 3).zero;
assert(a[3] == 0);
}
// For square matrices, .identity gives the identity matrix.
{
auto a = Matrix!(float, 2, 2).identity;
// The identity is also accessible as a.identity.
assert(a[0, 0] == 1);
assert(a[0, 1] == 0);
}
// .width and .height are aliases for N and M.
assert(Matrix!(int, 13, 37).height == 13);
assert(m.width == 3);
// [] gives a T[] slice of all N*M elements.
assert(m[] == [7, 3, 2, 9, 1, 5]);
m[] = 0;
assert(m == m.zero);
// .transposed gives the transposed M*N matrix.
assert(m.transposed.width == m.height);
assert(m.transposed.height == m.width);
m[0, 2] = 4;
assert(m.transposed[2, 0] == 4);
// For square matrices, .transpose() transposes the matrix in place.
{
auto a = Matrix!(float, 2, 2)(1, 2, 3, 4);
a.transpose();
assert(a[] == [1, 3, 2, 4]);
}
// Vectors are just matrices with a width of 1. Vector!(T, N) is just an alias.
assert(is(Vector!(float, 3) == Matrix!(float, 3, 1)));
// For vectors, [i..j] can be used to get/set/modify a part of the vector.
auto a = Vector!(float, 4).zero;
a[0..2] = 1;
a[1..3] += 2;
assert(a[0..3] == [1, 3, 2]);
// Vectors of different sizes can be used together, they're padded with zeros.
a += Vector!(float, 2)(1, 2);
assert(a[] == [2, 5, 2, 0]);
assert((a - Vector!(float, 5)(0, 0, 0, 0, 1))[] == [2, 5, 2, 0, -1]);
// .column(i) and .row(i) give you a specific row or column as N*1 or 1*M matrix, respectively.
assert(m.row(0)[] == [0, 0, 4]);
assert(m.column(2)[] == [4, 0]);
assert(m.row(0).height == 1);
assert(m.column(0).width == 1);
// .without_row(i), .without_column(i), and .without_row_column(r, c) do as they say.
assert(m.without_column(1) == Matrix!(float, 2, 2)(0, 4, 0, 0));
assert(m.without_row(1) == Matrix!(float, 1, 3)(0, 0, 4));
assert(m.without_row_column(1, 1) == Matrix!(float, 1, 2)(0, 4));
// For (column) vectors, .length gives the Euclidian length,
// .normalized and .normalize do what you want.
Vector!(float, 2) v = [3, 4];
assert(v.length == 5);
assert(v.normalized == Vector!(float, 2)(0.6, 0.8));
v.normalize();
assert(v.length == 1);
// For square matrices, there is .determinant, .cofactor(row, column),
// .cofactor_matrix, .adjugate, .inverse and .invert.
Matrix!(float, 3, 3) x = [
1, 2, 3,
0, 6, 1,
0, 5, 0,
];
assert(x.determinant == -5);
assert(x.cofactor(1, 0) == -x.without_row_column(1, 0).determinant);
assert(x.cofactor_matrix[1, 0] == x.cofactor(1, 0));
assert(x.adjugate == x.cofactor_matrix.transposed);
assert(x.inverse == x.adjugate / x.determinant);
x.invert();
assert(x.column(1)[] == [-3, 0, 1]);
// You can add and subtract same-sized matrices with +=, -=, + and -,
// and scale them with *=, /=, *, and /.
auto y = x.without_row(2) + m;
y -= -m * 2;
y /= 0.5;
assert(y[1] == -6);
// Matrix multiplication is done with * and *=.
assert(x * x.inverse == x.identity);
x *= x.inverse;
assert(x == x.identity);
// For vectors, * gives you the dot product.
assert(v * v == 1);
// There are aliases available for the most common matrices and vectors.
// (1..4 in size, for types int, float, double and real.)
assert(is(Matrix2x3f == Matrix!(float, 2, 3)));
assert(is(Matrix3d == Matrix!(double, 3, 3)));
assert(is(Vector2i == Vector!(int, 2)));
assert(is(HVector4r == HVector!(real, 4)));