Moggle

moggle.math.matrix



struct Matrix(T, size_t N, size_t M = N);
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)));


template Vector(T, size_t N)
Alias for a Matrix with a width of 1.

struct HVector(T, size_t N);
A 'homogeneous vector': A vector with the last element set to 1 by default.

Examples:
// A HVector is a Vector with the last element set to 1 by default.
// This is handy for 4D representations of positions in 3D graphics
// and RGBA color vectors.
auto h = HVector4d(1, 0.3, 0.4);
assert(h[] == [1, 0.3, 0.4, 1]);
h = [0, 2, 3];
assert(h[] == [0, 2, 3, 1]);

// They can be converted back and forth to normal vectors.
Vector4d v = h;
HVector4d h1 = w;
HVector4d h2 = Vector3d(1, 2, 3);
h = v;
v = h;
h += v;