com.io7m.jtensors 9.0.0 Documentation

Package Information

Orientation

Overview

The com.io7m.jtensors package implements a set of efficient vector, matrix, and quaternion classes intended for use in computer graphics applications.

Efficiency

The package uses simple and efficient algorithms for all operations. The design of the package distinguishes between computation and storage tensors. This allows code that computes with vectors to consist entirely of static, monomorphic method calls - the type of code that produces the best results under Java virtual machines that use JIT compilation.

The package also provides storage tensors that are backed by direct memory, allowing for zero-copy sharing of structures with native code.

Installation

License

All files distributed with the com.io7m.jtensors package are placed under the following license:

Copyright © 2017 <code@io7m.com> http://io7m.com Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Conventions

Vectors

Computation Types

The com.io7m.jtensors package provides computation vectors with single-precision (float) elements, double-precision (double) elements, integer (int), and long integer (long) elements. Each vector type is available in two, three, and four element versions. The package unambiguously identifies the vector types by using the following naming conventions for the types (given as a simple EBNF grammar) :

prefix = "Vector" | "PVector" ; size = "2" | "3" | "4" ; element_type = "I" | "L" | "F" | "D" ; type = prefix , size , element_type ;

Computation vectors are always immutable and are defined in such a way to allow the Java virtual machine to efficiently inline all vector method calls and to eliminate the allocations of intermediate vectors via escape analysis.

The available vector types include:

Storage Types

The com.io7m.jtensors package provides mutable storage vectors. A storage vector is a mutable vector 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 vectors, with the final results of those computations being written to storage vectors in order to, for example, be passed directly to native code without requiring copying.

To enumerate the available storage vector types, see the API documentation for the VectorStorageType interface.

Matrices

Computation Types

The com.io7m.jtensors package provides square computation matrices with single-precision (float) elements, and double-precision (double) elements. Each matrix type is available in 2x2, 3x3, and 4x4 versions. The package unambiguously identifies the matrix types by using the following naming conventions for the types (given as a simple EBNF grammar) :

prefix = "Matrix" | "PMatrix" size = "2x2" | "3x3" | "4x4" ; element_type = "F" | "D" ; type = prefix , size , element_type ;

Computation matrices are always immutable and are defined in such a way to allow the Java virtual machine to efficiently inline all matrix method calls and to eliminate the allocations of intermediate matrices via escape analysis.

The available matrix types include:

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 [2], 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 [3]. Additionally, with each matrix labelled by the type of transform it represents, code becomes self-documenting.

interface WorldSpace { } interface ViewSpace { } interface ObjectSpace { } PMatrix4x4D<ObjectSpace, WorldSpace> matrix_model; PMatrix4x4D<WorldSpace, ViewSpace> matrix_view; PMatrix4x4D<ObjectSpace, ViewSpace> matrix_modelview; // Correct! matrix_modelview = PMatrices4x4D.multiply (matrix_view, matrix_model); // Correct! Optional<PMatrix4x4D<ViewSpace, WorldSpace>> matrix_view_inverse = PMatrices4x4D.invert(matrix_view); // Compilation error: The resulting matrix would be of type PMatrix4x4D<ViewSpace, ObjectSpace> // matrix_modelview = PMatrices4x4D.multiply (matrix_model, matrix_view);

Quaternions

The com.io7m.jtensors package provides quaternions with single-precision (float) elements, and double-precision (double) elements. The package unambiguously identifies the quaternion types by using the following naming conventions for the types (given as a simple EBNF grammar) :

The available quaternion types include:

[3]

It is common for people to make mistakes with matrix multiplication: The order of matrices is effectively the reverse of the order in which the transforms will be applied.