public final class Matrices extends Static
Matrix
factory methods and utilities.
This class provides the following methods:
createIdentity
,
createDiagonal
,
createZero
,
create
,
copy
.
createTransform
,
createDimensionSelect
,
createPassThrough
.
isAffine
,
isIdentity
,
equals
,
toString
.
multiply
,
inverse
,
unmodifiable
,
TensorParameters
Defined in the sisreferencing
module
Modifier and Type  Method and Description 

static MatrixSIS 
copy(Matrix matrix)
Creates a new matrix which is a copy of the given matrix.

static MatrixSIS 
create(int numRow,
int numCol,
double[] elements)
Creates a matrix of size
numRow × numCol initialized to the given elements. 
static MatrixSIS 
create(int numRow,
int numCol,
Number[] elements)
Creates a matrix of size
numRow × numCol initialized to the given numbers. 
static MatrixSIS 
createDiagonal(int numRow,
int numCol)
Creates a matrix of size
numRow × numCol . 
static MatrixSIS 
createDimensionSelect(int sourceDimensions,
int[] selectedDimensions)
Creates a matrix for a transform that keep only a subset of source ordinate values.

static MatrixSIS 
createIdentity(int size)
Creates a square identity matrix of size
size × size . 
static MatrixSIS 
createPassThrough(int firstAffectedOrdinate,
Matrix subMatrix,
int numTrailingOrdinates)
Creates a matrix which converts a subset of ordinates using the transform given by another matrix.

static MatrixSIS 
createTransform(AxisDirection[] srcAxes,
AxisDirection[] dstAxes)
Creates a transform matrix changing axis order and/or direction.

static MatrixSIS 
createTransform(Envelope srcEnvelope,
AxisDirection[] srcAxes,
Envelope dstEnvelope,
AxisDirection[] dstAxes)
Creates a transform matrix mapping the given source envelope to the given destination envelope,
combined with changes in axis order and/or direction.

static MatrixSIS 
createTransform(Envelope srcEnvelope,
Envelope dstEnvelope)
Creates a transform matrix mapping the given source envelope to the given destination envelope.

static MatrixSIS 
createZero(int numRow,
int numCol)
Creates a matrix of size
numRow × numCol filled with zero values. 
static boolean 
equals(Matrix m1,
Matrix m2,
ComparisonMode mode)
Compares the given matrices for equality, using the given comparison strictness level.

static boolean 
equals(Matrix m1,
Matrix m2,
double epsilon,
boolean relative)
Compares the given matrices for equality, using the given relative or absolute tolerance threshold.

static MatrixSIS 
inverse(Matrix matrix)
Returns the inverse of the given matrix.

static boolean 
isAffine(Matrix matrix)
Returns
true if the given matrix represents an affine transform. 
static boolean 
isIdentity(Matrix matrix,
double tolerance)
Returns
true if the given matrix is close to an identity matrix, given a tolerance threshold. 
static boolean 
isTranslation(Matrix matrix)
Returns
true if the given matrix represents a translation. 
static MatrixSIS 
multiply(Matrix m1,
Matrix m2)
Returns a new matrix which is the result of multiplying the first matrix with the second one.

static Matrix 
resizeAffine(Matrix matrix,
int numRow,
int numCol)
Returns a matrix with the same content than the given matrix but a different size, assuming an affine transform.

static String 
toString(Matrix matrix)
Returns a unlocalized string representation of the given matrix.

static MatrixSIS 
unmodifiable(Matrix matrix)
Returns an unmodifiable view of the given matrix.

public static MatrixSIS createIdentity(int size)
size
× size
.
Elements on the diagonal (j == i) are set to 1.
public static MatrixSIS createDiagonal(int numRow, int numCol)
numRow
× numCol
.
Elements on the diagonal (j == i) are set to 1.
The result is an identity matrix if numRow
= numCol
.
numRow
 for a math transform, this is the number of target dimensions + 1.numCol
 for a math transform, this is the number of source dimensions + 1.public static MatrixSIS createZero(int numRow, int numCol)
numRow
× numCol
filled with zero values.
This constructor is convenient when the caller wants to initialize the matrix elements himself.
numRow
 for a math transform, this is the number of target dimensions + 1.numCol
 for a math transform, this is the number of source dimensions + 1.public static MatrixSIS create(int numRow, int numCol, double[] elements)
numRow
× numCol
initialized to the given elements.
The elements array size must be equals to numRow*numCol
. Column indices vary fastest.
numRow
 number of rows.numCol
 number of columns.elements
 the matrix elements in a rowmajor array. Column indices vary fastest.MatrixSIS.setElements(double[])
public static MatrixSIS create(int numRow, int numCol, Number[] elements)
numRow
× numCol
initialized to the given numbers.
The elements array size must be equals to numRow*numCol
. Column indices vary fastest.numRow
 number of rows.numCol
 number of columns.elements
 the matrix elements in a rowmajor array. Column indices vary fastest.public static MatrixSIS createTransform(Envelope srcEnvelope, Envelope dstEnvelope)
getSpan(int)
method
to behave as documented in the AbstractEnvelope.getSpan(int)
javadoc.
Furthermore the matrix created by this method will produce expected results only for source or destination
points before the date line, since the wrap around operation can not be represented by an affine transform.
matrix = Matrices.createTransform( new Envelope2D(null, 20, 40, 100, 200), new Envelope2D(null, 10, 25, 300, 500));will return the following square matrix. The transform of the lower corner is given as an example:
┌ ┐ ┌ ┐ ┌ ┐ │ 10 │ │ 3.0 0 50 │ │ 20 │ // 3.0 is the scale factor from width of 100 to 300 │ 25 │ = │ 0 2.5 75 │ × │ 40 │ // 2.5 is the scale factor from height of 200 to 500 │ 1 │ │ 0 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘
srcEnvelope
 the source envelope.dstEnvelope
 the destination envelope.createTransform(AxisDirection[], AxisDirection[])
,
createTransform(Envelope, AxisDirection[], Envelope, AxisDirection[])
,
CoordinateSystems.swapAndScaleAxes(CoordinateSystem, CoordinateSystem)
public static MatrixSIS createTransform(AxisDirection[] srcAxes, AxisDirection[] dstAxes)
dstAxes
direction to either an equals srcAxis
direction, or to an opposite srcAxis
direction.
srcAxes
directions can not be mapped to dstAxes
directions, then the transform
will silently drops the ordinates associated to those extra source axis directions.dstAxes
directions can not be mapped to srcAxes
directions,
then an exception will be thrown.matrix = Matrices.createTransform( new AxisDirection[] {AxisDirection.NORTH, AxisDirection.WEST}, new AxisDirection[] {AxisDirection.EAST, AxisDirection.NORTH});will return the following square matrix, which can be used in coordinate conversions as below:
┌ ┐ ┌ ┐ ┌ ┐ │ +x │ │ 0 1 0 │ │ y │ │ y │ = │ 1 0 0 │ × │ x │ │ 1 │ │ 0 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘
srcAxes
 the ordered sequence of axis directions for source coordinate system.dstAxes
 the ordered sequence of axis directions for destination coordinate system.IllegalArgumentException
 if dstAxes
contains at least one axis not found in srcAxes
,
or if some colinear axes were found.createTransform(Envelope, Envelope)
,
createTransform(Envelope, AxisDirection[], Envelope, AxisDirection[])
,
CoordinateSystems.swapAndScaleAxes(CoordinateSystem, CoordinateSystem)
public static MatrixSIS createTransform(Envelope srcEnvelope, AxisDirection[] srcAxes, Envelope dstEnvelope, AxisDirection[] dstAxes)
createTransform(srcEnvelope, dstEnvelope)
createTransform(srcAxes, dstAxes)
getSpan(int)
method
to behave as documented in the AbstractEnvelope.getSpan(int)
javadoc.
Furthermore the matrix created by this method will produce expected results only for source or destination
points on one side of the date line (depending on whether axis direction is reversed), since the wrap around
operation can not be represented by an affine transform.
createTransform(…)
methods, the following method call:
matrix = Matrices.createTransform( new Envelope2D(null, 40, +20, 200, 100), new AxisDirection[] {AxisDirection.NORTH, AxisDirection.WEST}, new Envelope2D(null, 10, 25, 300, 500), new AxisDirection[] {AxisDirection.EAST, AxisDirection.NORTH});will return the following square matrix. The transform of a corner is given as an example. Note that the input ordinate values are swapped because of the (North, West) axis directions, and the lowerleft corner of the destination envelope is the lowerright corner of the source envelope because of the opposite axis direction.
┌ ┐ ┌ ┐ ┌ ┐ │ 10 │ │ 0 3.0 350 │ │ 40 │ │ 25 │ = │ 2.5 0 75 │ × │ 120 │ // 120 is the westernmost source ordinate: (x=20) + (width=100) │ 1 │ │ 0 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘
srcEnvelope
 the source envelope.srcAxes
 the ordered sequence of axis directions for source coordinate system.dstEnvelope
 the destination envelope.dstAxes
 the ordered sequence of axis directions for destination coordinate system.MismatchedDimensionException
 if an envelope dimension does not
match the length of the axis directions sequence.IllegalArgumentException
 if dstAxes
contains at least one axis not found in srcAxes
,
or if some colinear axes were found.createTransform(Envelope, Envelope)
,
createTransform(AxisDirection[], AxisDirection[])
,
CoordinateSystems.swapAndScaleAxes(CoordinateSystem, CoordinateSystem)
public static MatrixSIS createDimensionSelect(int sourceDimensions, int[] selectedDimensions)
selectedDimensions.length
+ 1) × (sourceDimensions
+ 1).
The matrix will contain only zero elements, except for the following cells which will contain 1:
selectedDimensions[j]
.matrix = Matrices.createDimensionSelect(4, new int[] {1, 0, 3});The above method call will create the following 4×5 matrix, which can be used for converting coordinates as below:
┌ ┐ ┌ ┐ ┌ ┐ │ y │ │ 0 1 0 0 0 │ │ x │ │ x │ │ 1 0 0 0 0 │ │ y │ │ t │ = │ 0 0 0 1 0 │ × │ z │ │ 1 │ │ 0 0 0 0 1 │ │ t │ └ ┘ └ ┘ │ 1 │ └ ┘
Double.NaN
values in the extra dimensions.
Other dimensions will work as expected.sourceDimensions
 the number of dimensions in source coordinates.selectedDimensions
 the 0based indices of source ordinate values to keep.
The length of this array will be the number of dimensions in target coordinates.IllegalArgumentException
 if a value of selectedDimensions
is lower than 0
or not smaller than sourceDimensions
.TransformSeparator
public static MatrixSIS createPassThrough(int firstAffectedOrdinate, Matrix subMatrix, int numTrailingOrdinates)
The given submatrix shall have the following properties:
This method builds a new matrix with the following content:
firstAffectedOrdinate
rows and columns are inserted before the first
row and columns of the submatrix. The elements for the new rows and columns are set to 1
on the diagonal, and 0 elsewhere.firstAffectedOrdinate
, firstAffectedOrdinate
).numTrailingOrdinates
rows and columns are appended after the above submatrix.
Their elements are set to 1 on the pseudodiagonal ending in the lowerright corner, and 0 elsewhere.┌ ┐ ┌ ┐ ┌ ┐ │ z' │ = │ 0.3048 25 │ × │ z │ │ 1 │ │ 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘Then a call to
Matrices.createPassThrough(2, subMatrix, 1)
will return the following matrix,
which can be used for converting the height (z) without affecting the other ordinate values
(x,y,t):
┌ ┐ ┌ ┐ ┌ ┐ │ x │ │ 1 0 0 0 0 │ │ x │ │ y │ │ 0 1 0 0 0 │ │ y │ │ z' │ = │ 0 0 0.3048 0 25 │ × │ z │ │ t │ │ 0 0 0 1 0 │ │ t │ │ 1 │ │ 0 0 0 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘
firstAffectedOrdinate
 the lowest index of the affected ordinates.subMatrix
 the matrix to use for affected ordinates.numTrailingOrdinates
 number of trailing ordinates to pass through.DefaultMathTransformFactory.createPassThroughTransform(int, MathTransform, int)
public static Matrix resizeAffine(Matrix matrix, int numRow, int numCol)
numCol
is n less than the number of columns in the given matrix,
then the n columns before the last column are removed.
The last column is left unchanged because it is assumed to contain the translation terms.numCol
is n more than the number of columns in the given matrix,
then n columns are inserted before the last column.
All values in the new columns will be zero.numRow
is n less than the number of rows in the given matrix,
then the n rows before the last row are removed.
The last row is left unchanged because it is assumed to contain the usual [0 0 0 … 1] terms.numRow
is n more than the number of rows in the given matrix,
then n rows are inserted before the last row.
The corresponding offset and scale factors will be 0 and 1 respectively.
In other words, new dimensions are propagated unchanged.matrix
 the matrix to resize. This matrix will never be changed.numRow
 the new number of rows. This is equal to the desired number of target dimensions plus 1.numCol
 the new number of columns. This is equal to the desired number of source dimensions plus 1.matrix
if no resizing was needed.public static MatrixSIS copy(Matrix matrix)
matrix
 the matrix to copy, or null
.null
if the given matrix was null.MatrixSIS.clone()
,
MatrixSIS.castOrCopy(Matrix)
public static MatrixSIS unmodifiable(Matrix matrix)
matrix
is not modified anymore after this method call.matrix
 the matrix for which to get an unmodifiable view, or null
.null
if the given matrix was null.public static MatrixSIS multiply(Matrix m1, Matrix m2) throws MismatchedMatrixSizeException
m1
× m2
.m1
 the first matrix to multiply.m2
 the second matrix to multiply.m1
× m2
.MismatchedMatrixSizeException
 if the number of columns in m1
is not equals to the
number of rows in m2
.MatrixSIS.multiply(Matrix)
public static MatrixSIS inverse(Matrix matrix) throws NoninvertibleMatrixException
matrix
 the matrix to inverse, or null
.null
if the given matrix was null.NoninvertibleMatrixException
 if the given matrix is not invertible.MatrixSIS.inverse()
public static boolean isAffine(Matrix matrix)
true
if the given matrix represents an affine transform.
A transform is affine if the matrix is square and its last row contains
only zeros, except in the last column which contains 1.matrix
 the matrix to test.true
if the matrix represents an affine transform.MatrixSIS.isAffine()
public static boolean isTranslation(Matrix matrix)
true
if the given matrix represents a translation.
This method returns true
if the given matrix is affine
and differs from the identity matrix only in the last column.matrix
 the matrix to test.true
if the matrix represents a translation.public static boolean isIdentity(Matrix matrix, double tolerance)
true
if the given matrix is close to an identity matrix, given a tolerance threshold.
This method is equivalent to computing the difference between the given matrix and an identity matrix
of identical size, and returning true
if and only if all differences are smaller than or equal
to tolerance
.
Caution: BursaWolf parameters,
when represented as a matrix, are close to an identity transform and could easily be confused with rounding
errors. In case of doubt, it is often safer to use the strict MatrixSIS.isIdentity()
method instead
than this one.
matrix
 the matrix to test for identity.tolerance
 the tolerance value, or 0 for a strict comparison.true
if this matrix is close to the identity matrix given the tolerance threshold.MatrixSIS.isIdentity()
public static boolean equals(Matrix m1, Matrix m2, double epsilon, boolean relative)
Double.NaN
values are considered equals to all other NaN valuesrelative
is true
, then for any pair of values v1_{j,i}
and v2_{j,i} to compare, the tolerance threshold is scaled by
max(abs(v1), abs(v2))
. Otherwise the threshold is used asis.m1
 the first matrix to compare, or null
.m2
 the second matrix to compare, or null
.epsilon
 the tolerance value.relative
 if true
, then the tolerance value is relative to the magnitude
of the matrix elements being compared.true
if the values of the two matrix do not differ by a quantity greater
than the given tolerance threshold.MatrixSIS.equals(Matrix, double)
public static boolean equals(Matrix m1, Matrix m2, ComparisonMode mode)
mode
argument:
STRICT
:
the two matrices must be of the same class, have the same size and the same element values.BY_CONTRACT
:
the two matrices must have the same size and the same element values,
but are not required to be the same implementation class (any Matrix
is okay).IGNORE_METADATA
: same as BY_CONTRACT
,
since matrices have no metadata.APPROXIMATIVE
:
the two matrices must have the same size, but the element values can differ up to some threshold.
The threshold value is determined empirically and may change in any future SIS versions.
For more control, use equals(Matrix, Matrix, double, boolean)
instead.m1
 the first matrix to compare, or null
.m2
 the second matrix to compare, or null
.mode
 the strictness level of the comparison.true
if both matrices are equal.MatrixSIS.equals(Object, ComparisonMode)
public static String toString(Matrix matrix)
The current implementation formats ±0 and ±1 without trailing ".0"
, and all other values with
a percolumn uniform number of fraction digits. The ±0 and ±1 values are treated especially because they
usually imply a "no scale", "no translation" or "orthogonal axes"
meaning. A matrix in SIS is often populated mostly by ±0 and ±1 values, with a few "interesting" values.
The simpler ±0 and ±1 formatting makes easier to spot the "interesting" values.
The following example shows the string representation of an affine transform which swap (latitude, longitude) axes, converts degrees to radians and converts height values from feet to metres:
┌ ┐ │ 0 0.017453292519943295 0 0 │ │ 0.017453292519943295 0 0 0 │ │ 0 0 0.3048 0 │ │ 0 0 0 1 │ └ ┘
matrix
 the matrix for which to get a string representation.Copyright © 2010–2017 The Apache Software Foundation. All rights reserved.