Class Matrices

public final class Matrices extends Static
Matrix
factory methods and utilities. This class provides the following methods: Creating new matrices of arbitrary size:
createIdentity
,createDiagonal
,createZero
,create
,copy
.  Creating new matrices for coordinate operation steps:
createTransform
,createDimensionSelect
,createPassThrough
.  Information:
isAffine
,isIdentity
,equals
,toString
.  Miscellaneous:
multiply
,inverse
,unmodifiable
,
 Since:
 0.4
 See Also:
TensorParameters
Defined in the
sisreferencing
module  Creating new matrices of arbitrary size:


Method Summary
All Methods Static Methods Concrete Methods Modifier and Type Method 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 sizenumRow
×numCol
initialized to the given elements.static MatrixSIS
create(int numRow, int numCol, Number[] elements)
Creates a matrix of sizenumRow
×numCol
initialized to the given numbers.static MatrixSIS
createDiagonal(int numRow, int numCol)
Creates a matrix of sizenumRow
×numCol
.static MatrixSIS
createDimensionSelect(int sourceDimensions, int[] selectedDimensions)
Creates a matrix for a transform that keep only a subset of source coordinate values.static MatrixSIS
createIdentity(int size)
Creates a square identity matrix of sizesize
×size
.static MatrixSIS
createPassThrough(int firstAffectedCoordinate, Matrix subMatrix, int numTrailingCoordinates)
Creates a matrix which converts a subset of coordinates using the transform given by another matrix.static MatrixSIS
createTransform(Envelope srcEnvelope, Envelope dstEnvelope)
Creates a transform matrix mapping the given source envelope to the given destination envelope.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(AxisDirection[] srcAxes, AxisDirection[] dstAxes)
Creates a transform matrix changing axis order and/or direction.static MatrixSIS
createZero(int numRow, int numCol)
Creates a matrix of sizenumRow
×numCol
filled with zero values.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 boolean
equals(Matrix m1, Matrix m2, ComparisonMode mode)
Compares the given matrices for equality, using the given comparison strictness level.static MatrixSIS
inverse(Matrix matrix)
Returns the inverse of the given matrix.static boolean
isAffine(Matrix matrix)
Returnstrue
if the given matrix represents an affine transform.static boolean
isIdentity(Matrix matrix, double tolerance)
Returnstrue
if the given matrix is close to an identity matrix, given a tolerance threshold.static boolean
isTranslation(Matrix matrix)
Returnstrue
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.



Method Detail

createIdentity
public static MatrixSIS createIdentity(int size)
Creates a square identity matrix of sizesize
×size
. Elements on the diagonal (j == i) are set to 1.

createDiagonal
public static MatrixSIS createDiagonal(int numRow, int numCol)
Creates a matrix of sizenumRow
×numCol
. Elements on the diagonal (j == i) are set to 1. The result is an identity matrix ifnumRow
=numCol
. Parameters:
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. Returns:
 an identity matrix of the given size.

createZero
public static MatrixSIS createZero(int numRow, int numCol)
Creates a matrix of sizenumRow
×numCol
filled with zero values. This constructor is convenient when the caller wants to initialize the matrix elements himself. Parameters:
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. Returns:
 a matrix of the given size with only zero values.

create
public static MatrixSIS create(int numRow, int numCol, double[] elements)
Creates a matrix of sizenumRow
×numCol
initialized to the given elements. The elements array size must be equals tonumRow*numCol
. Column indices vary fastest. Parameters:
numRow
 number of rows.numCol
 number of columns.elements
 the matrix elements in a rowmajor array. Column indices vary fastest. Returns:
 a matrix initialized to the given elements.
 See Also:
MatrixSIS.setElements(double[])

create
public static MatrixSIS create(int numRow, int numCol, Number[] elements)
Creates a matrix of sizenumRow
×numCol
initialized to the given numbers. The elements array size must be equals tonumRow*numCol
. Column indices vary fastest. Parameters:
numRow
 number of rows.numCol
 number of columns.elements
 the matrix elements in a rowmajor array. Column indices vary fastest. Returns:
 a matrix initialized to the given elements.

createTransform
public static MatrixSIS createTransform(Envelope srcEnvelope, Envelope dstEnvelope)
Creates a transform matrix mapping the given source envelope to the given destination envelope. The given envelopes can have any dimensions, which are handled as below: If the two envelopes have the same dimension, then the transform is affine.
 If the destination envelope has less dimensions than the source envelope, then trailing dimensions are silently dropped.
 If the target envelope has more dimensions than the source envelope, then the transform will append trailing coordinates with the 0 value.
Spanning the antimeridian of a Geographic CRSIf the given envelopes cross the date line, then this method requires theirgetSpan(int)
method to behave as documented in theAbstractEnvelope.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.ExampleGiven a source envelope of size 100 × 200 (the units do not matter for this method) and a destination envelope of size 300 × 500, and given lower corner translation from (20, 40) to (10, 25), then the following method call:
will return the following square matrix. The transform of the lower corner is given as an example:matrix = Matrices.createTransform( new Envelope2D(null, 20, 40, 100, 200), new Envelope2D(null, 10, 25, 300, 500));
┌ ┐ ┌ ┐ ┌ ┐ │ 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 │ └ ┘ └ ┘ └ ┘
 Parameters:
srcEnvelope
 the source envelope.dstEnvelope
 the destination envelope. Returns:
 the transform from the given source envelope to target envelope.
 See Also:
createTransform(AxisDirection[], AxisDirection[])
,createTransform(Envelope, AxisDirection[], Envelope, AxisDirection[])
,CoordinateSystems.swapAndScaleAxes(CoordinateSystem, CoordinateSystem)

createTransform
public static MatrixSIS createTransform(AxisDirection[] srcAxes, AxisDirection[] dstAxes)
Creates a transform matrix changing axis order and/or direction. For example the transform may convert (northing, westing) coordinates into (easting, northing) coordinates. This method tries to associate eachdstAxes
direction to either an equalssrcAxis
direction, or to an oppositesrcAxis
direction. If some
srcAxes
directions can not be mapped todstAxes
directions, then the transform will silently drops the coordinates associated to those extra source axis directions.  If some
dstAxes
directions can not be mapped tosrcAxes
directions, then an exception will be thrown.
Example: it is legal to transform from (easting, northing, up) to (easting, northing) — this is the first above case — but illegal to transform (easting, northing) to (easting, up).ExampleThe following method call:
will return the following square matrix, which can be used in coordinate conversions as below:matrix = Matrices.createTransform( new AxisDirection[] {AxisDirection.NORTH, AxisDirection.WEST}, new AxisDirection[] {AxisDirection.EAST, AxisDirection.NORTH});
┌ ┐ ┌ ┐ ┌ ┐ │ +x │ │ 0 1 0 │ │ y │ │ y │ = │ 1 0 0 │ × │ x │ │ 1 │ │ 0 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘
 Parameters:
srcAxes
 the ordered sequence of axis directions for source coordinate system.dstAxes
 the ordered sequence of axis directions for destination coordinate system. Returns:
 the transform from the given source axis directions to the given target axis directions.
 Throws:
IllegalArgumentException
 ifdstAxes
contains at least one axis not found insrcAxes
, or if some colinear axes were found. See Also:
createTransform(Envelope, Envelope)
,createTransform(Envelope, AxisDirection[], Envelope, AxisDirection[])
,CoordinateSystems.swapAndScaleAxes(CoordinateSystem, CoordinateSystem)
 If some

createTransform
public 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. Invoking this method is equivalent to concatenating the following matrix transforms:createTransform(srcEnvelope, dstEnvelope)
createTransform(srcAxes, dstAxes)
Spanning the antimeridian of a Geographic CRSIf the given envelopes cross the date line, then this method requires theirgetSpan(int)
method to behave as documented in theAbstractEnvelope.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.Example: combining the examples documented in the abovecreateTransform(…)
methods, the following method call:
will return the following square matrix. The transform of a corner is given as an example. Note that the input coordinate 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.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});
┌ ┐ ┌ ┐ ┌ ┐ │ 10 │ │ 0 3.0 350 │ │ 40 │ │ 25 │ = │ 2.5 0 75 │ × │ 120 │ // 120 is the westernmost source coordinate: (x=20) + (width=100) │ 1 │ │ 0 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘
 Parameters:
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. Returns:
 the transform from the given source envelope and axis directions to the given envelope and target axis directions.
 Throws:
MismatchedDimensionException
 if an envelope dimension does not match the length of the axis directions sequence.IllegalArgumentException
 ifdstAxes
contains at least one axis not found insrcAxes
, or if some colinear axes were found. See Also:
createTransform(Envelope, Envelope)
,createTransform(AxisDirection[], AxisDirection[])
,CoordinateSystems.swapAndScaleAxes(CoordinateSystem, CoordinateSystem)

createDimensionSelect
public static MatrixSIS createDimensionSelect(int sourceDimensions, int[] selectedDimensions)
Creates a matrix for a transform that keep only a subset of source coordinate values. The matrix size will be (selectedDimensions.length
+ 1) × (sourceDimensions
+ 1). The matrix will contain only zero elements, except for the following cells which will contain 1: The last column in the last row.
 For any row j other than the last row, the column
selectedDimensions[j]
.
Example: given (x,y,z,t) coordinate values, if one wants to keep (y,x,t) coordinates (note the x ↔ y swapping) and discard the z values, then the indices of source coordinates to select are 1 for y, 0 for x and 3 for t. One can use the following method call:The inverse of the matrix created by this method will put
The above method call will create the following 4×5 matrix, which can be used for converting coordinates as below:matrix = Matrices.createDimensionSelect(4, new int[] {1, 0, 3});
┌ ┐ ┌ ┐ ┌ ┐ │ 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. Parameters:
sourceDimensions
 the number of dimensions in source coordinates.selectedDimensions
 the 0based indices of source coordinate values to keep. The length of this array will be the number of dimensions in target coordinates. Returns:
 an affine transform matrix keeping only the given source dimensions, and discarding all others.
 Throws:
IllegalArgumentException
 if a value ofselectedDimensions
is lower than 0 or not smaller thansourceDimensions
. See Also:
TransformSeparator

createPassThrough
public static MatrixSIS createPassThrough(int firstAffectedCoordinate, Matrix subMatrix, int numTrailingCoordinates)
Creates a matrix which converts a subset of coordinates using the transform given by another matrix. For example giving (latitude, longitude, height) coordinates, a pass through operation can convert the height values from feet to metres without affecting the (latitude, longitude) values.The given submatrix shall have the following properties:
 The last row often (but not necessarily) contains 0 values everywhere except in the last column.
 Values in the last column are translation terms, except in the last row.
 All other values are scale or shear terms.
This method builds a new matrix with the following content:
 An amount of
firstAffectedCoordinate
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.  The submatrix  except for its last row and column  is copied in the new matrix starting
at index (
firstAffectedCoordinate
,firstAffectedCoordinate
).  An amount of
numTrailingCoordinates
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.  The last submatrix row is copied in the last row of the new matrix, and the last submatrix column is copied in the last column of the submatrix.
Example: given the following submatrix which converts height values from feet to metres before to subtracts 25 metres:
Then a call to┌ ┐ ┌ ┐ ┌ ┐ │ z' │ = │ 0.3048 25 │ × │ z │ │ 1 │ │ 0 1 │ │ 1 │ └ ┘ └ ┘ └ ┘
Matrices.createPassThrough(2, subMatrix, 1)
will return the following matrix, which can be used for converting the height (z) without affecting the other coordinate 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 │ └ ┘ └ ┘ └ ┘
 Parameters:
firstAffectedCoordinate
 the lowest index of the affected coordinates.subMatrix
 the matrix to use for affected coordinates.numTrailingCoordinates
 number of trailing coordinates to pass through. Returns:
 a matrix for the same transform than the given matrix, augmented with leading and trailing passthrough coordinates.
 See Also:
DefaultMathTransformFactory.createPassThroughTransform(int, MathTransform, int)

resizeAffine
public 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. This method can be invoked for adding or removing the last dimensions of an affine transform. More specifically: If the given
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.  If the given
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.  If the given
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.  If the given
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.
 Parameters:
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. Returns:
 a new matrix of the given size, or the given
matrix
if no resizing was needed.
 If the given

copy
public static MatrixSIS copy(Matrix matrix)
Creates a new matrix which is a copy of the given matrix. Parameters:
matrix
 the matrix to copy, ornull
. Returns:
 a copy of the given matrix, or
null
if the given matrix was null.  See Also:
MatrixSIS.clone()
,MatrixSIS.castOrCopy(Matrix)

unmodifiable
public static MatrixSIS unmodifiable(Matrix matrix)
Returns an unmodifiable view of the given matrix. The returned matrix is immutable only if the givenmatrix
is not modified anymore after this method call. Parameters:
matrix
 the matrix for which to get an unmodifiable view, ornull
. Returns:
 a unmodifiable view of the given matrix, or
null
if the given matrix was null.  Since:
 0.6

multiply
public static MatrixSIS multiply(Matrix m1, Matrix m2) throws MismatchedMatrixSizeException
Returns a new matrix which is the result of multiplying the first matrix with the second one. In other words, returnsm1
×m2
. Parameters:
m1
 the first matrix to multiply.m2
 the second matrix to multiply. Returns:
 the result of
m1
×m2
.  Throws:
MismatchedMatrixSizeException
 if the number of columns inm1
is not equals to the number of rows inm2
. Since:
 0.6
 See Also:
MatrixSIS.multiply(Matrix)

inverse
public static MatrixSIS inverse(Matrix matrix) throws NoninvertibleMatrixException
Returns the inverse of the given matrix. Parameters:
matrix
 the matrix to inverse, ornull
. Returns:
 the inverse of this matrix, or
null
if the given matrix was null.  Throws:
NoninvertibleMatrixException
 if the given matrix is not invertible. Since:
 0.6
 See Also:
MatrixSIS.inverse()

isAffine
public static boolean isAffine(Matrix matrix)
Returnstrue
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. Parameters:
matrix
 the matrix to test. Returns:
true
if the matrix represents an affine transform. See Also:
MatrixSIS.isAffine()

isTranslation
public static boolean isTranslation(Matrix matrix)
Returnstrue
if the given matrix represents a translation. This method returnstrue
if the given matrix is affine and differs from the identity matrix only in the last column. Parameters:
matrix
 the matrix to test. Returns:
true
if the matrix represents a translation. Since:
 0.7

isIdentity
public static boolean isIdentity(Matrix matrix, double tolerance)
Returnstrue
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 returningtrue
if and only if all differences are smaller than or equal totolerance
.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. Parameters:
matrix
 the matrix to test for identity.tolerance
 the tolerance value, or 0 for a strict comparison. Returns:
true
if this matrix is close to the identity matrix given the tolerance threshold. See Also:
MatrixSIS.isIdentity()

equals
public 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. The matrix elements are compared as below:Double.NaN
values are considered equals to all other NaN values Infinite values are considered equal to other infinite values of the same sign
 All other values are considered equal if the absolute value of their difference is smaller than or equals to the threshold described below.
relative
istrue
, then for any pair of values v1_{j,i} and v2_{j,i} to compare, the tolerance threshold is scaled bymax(abs(v1), abs(v2))
. Otherwise the threshold is used asis. Parameters:
m1
 the first matrix to compare, ornull
.m2
 the second matrix to compare, ornull
.epsilon
 the tolerance value.relative
 iftrue
, then the tolerance value is relative to the magnitude of the matrix elements being compared. Returns:
true
if the values of the two matrix do not differ by a quantity greater than the given tolerance threshold. See Also:
MatrixSIS.equals(Matrix, double)

equals
public static boolean equals(Matrix m1, Matrix m2, ComparisonMode mode)
Compares the given matrices for equality, using the given comparison strictness level. To be considered equal, the two matrices must met the following conditions, which depend on themode
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 (anyMatrix
is okay).IGNORE_METADATA
: same asBY_CONTRACT
, since matrices have no metadata.APPROXIMATE
: 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, useequals(Matrix, Matrix, double, boolean)
instead.
 Parameters:
m1
 the first matrix to compare, ornull
.m2
 the second matrix to compare, ornull
.mode
 the strictness level of the comparison. Returns:
true
if both matrices are equal. See Also:
MatrixSIS.equals(Object, ComparisonMode)

toString
public static String toString(Matrix matrix)
Returns a unlocalized string representation of the given matrix. For each column, the numbers are aligned on the decimal separator.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 │ └ ┘
Note: Formatting on a percolumn basis is convenient for the kind of matrices used in referencing by coordinates, because each column is typically a displacement vector in a different dimension of the source coordinate reference system. In addition, the last column is often a translation vector having a magnitude very different than the other columns. Parameters:
matrix
 the matrix for which to get a string representation. Returns:
 a string representation of the given matrix.

