if (!Classes.implementSameInterfaces(sourceCS.getClass(), targetCS.getClass(), CoordinateSystem.class)) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleCoordinateSystemTypes));
}
final AxisDirection[] sourceAxis = getAxisDirections(sourceCS);
final AxisDirection[] targetAxis = getAxisDirections(targetCS);
final MatrixSIS matrix = Matrices.createTransform(sourceAxis, targetAxis);
assert Arrays.equals(sourceAxis, targetAxis) == matrix.isIdentity() : matrix;
/*
* The previous code computed a matrix for swapping axes. Usually, this
* matrix contains only 0 and 1 values with only one "1" value by row.
* For example, the matrix operation for swapping x and y axes is:
* ┌ ┐ ┌ ┐ ┌ ┐
* │y│ │ 0 1 0 │ │x│
* │x│ = │ 1 0 0 │ │y│
* │1│ │ 0 0 1 │ │1│
* └ ┘ └ ┘ └ ┘
* Now, take in account units conversions. Each matrix's element (j,i)
* is multiplied by the conversion factor from sourceCS.getUnit(i) to
* targetCS.getUnit(j). This is an element-by-element multiplication,
* not a matrix multiplication. The last column is processed in a special
* way, since it contains the offset values.
*/
final int sourceDim = matrix.getNumCol() - 1; // == sourceCS.getDimension()
final int targetDim = matrix.getNumRow() - 1; // == targetCS.getDimension()
for (int j=0; j<targetDim; j++) {
final Unit<?> targetUnit = targetCS.getAxis(j).getUnit();
for (int i=0; i<sourceDim; i++) {
final double element = matrix.getElement(j,i);
if (element == 0) {
// There is no dependency between source[i] and target[j]
// (i.e. axes are orthogonal).
continue;
}
final Unit<?> sourceUnit = sourceCS.getAxis(i).getUnit();
if (Objects.equals(sourceUnit, targetUnit)) {
// There is no units conversion to apply
// between source[i] and target[j].
continue;
}
final UnitConverter converter = sourceUnit.getConverterToAny(targetUnit);
if (!(converter instanceof LinearConverter)) {
throw new ConversionException(Errors.format(
Errors.Keys.NonLinearUnitConversion_2, sourceUnit, targetUnit));
}
final double offset = converter.convert(0);
final double scale = Units.derivative(converter, 0);
matrix.setElement(j, i, element*scale);
matrix.setElement(j, sourceDim, matrix.getElement(j, sourceDim) + element*offset);
}
}
return matrix;
}