Storage Types
The
com.io7m.jtensors package provides mutable
storage matrices. A
storage matrix is a mutable matrix upon which only very simple
get and
set operations are defined. The intention is to allow all intermediate computations to be written with immutable
computation matrices, with the final results of those computations being written to storage matrices in order to, for example, be passed directly to native code without requiring copying.
To enumerate the available storage matrix types, see the API documentation for the
MatrixStorageType interface.
Matrix data is stored in column-major format , in whatever is the platform's native byte order. For an m x m square matrix, assuming that each element of the matrix uses n bytes, the first byte of the element at row r and column c (assuming 0 <= r < m and 0 <= c < m) can be found by (c * m * n) + (r * n).
So, the element at row 0, column 0 would be stored in bytes [0 .. 3]. The element at row 1, column 0 would be stored in bytes [4 .. 7]. The element at row 0, column 1 would be stored in bytes [16 .. 19], and so on.
Phantom Types
As with the vector types, the com.io7m.jtensors package provides copies of all of the existing matrix types indexed by a pair of phantom type parameters.
Conceptually, a matrix can be considered as storing a transform from coordinate space T0 to space T1. For a 4x4 matrix in the com.io7m.jtensors package, this is denoted by the type PMatrix4x4D<T0,T1>. It then follows that when matrices are concatenated via multiplications, their type parameters are translated accordingly. For example, a matrix PMatrix4x4D<T0,T1> multiplied by a matrix PMatrix4x4D<T1,T2> results in a matrix of type PMatrix4x4D<T0,T2>. Inverting a matrix results in a matrix that represents the inverse of the original transform that the matrix represented. For example, inverting a matrix of type PMatrix4x4D<T0,T1> results in a matrix of type PMatrix4x4D<T1,T0>.
Type parameters are also translated across multiplications by vectors. A multiplication of a vector of type PVector4D<T0> by a matrix of type PMatrix4x4D<T0,T1> results in a vector of type PVector4D<T1>.
Being able to track the types of transforms at this level of detail is invaluable when using systems such as OpenGL, where accidentally mixing up matrices tends to result in visual anomalies that can be extremely hard to track down. By explicitly denoting coordinate spaces with empty types, it's possible to statically prevent all bugs involving accidentally mixing up matrices. It's also possible to prevent the incorrect construction of matrices . Additionally, with each matrix labelled by the type of transform it represents, code becomes self-documenting.