use of org.apache.sis.internal.referencing.provider.VerticalOffset in project sis by apache.
the class DefaultMathTransformFactory method swapAndScaleAxes.
/**
* Given a transform between normalized spaces,
* creates a transform taking in account axis directions, units of measurement and longitude rotation.
* This method {@linkplain #createConcatenatedTransform concatenates} the given parameterized transform
* with any other transform required for performing units changes and ordinates swapping.
*
* <p>The given {@code parameterized} transform shall expect
* {@linkplain org.apache.sis.referencing.cs.AxesConvention#NORMALIZED normalized} input coordinates and
* produce normalized output coordinates. See {@link org.apache.sis.referencing.cs.AxesConvention} for more
* information about what Apache SIS means by "normalized".</p>
*
* <div class="note"><b>Example:</b>
* The most typical examples of transforms with normalized inputs/outputs are normalized
* map projections expecting (<cite>longitude</cite>, <cite>latitude</cite>) inputs in degrees
* and calculating (<cite>x</cite>, <cite>y</cite>) coordinates in metres,
* both of them with ({@linkplain org.opengis.referencing.cs.AxisDirection#EAST East},
* {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}) axis orientations.</div>
*
* <div class="section">Controlling the normalization process</div>
* Users who need a different normalized space than the default one way find more convenient to
* override the {@link Context#getMatrix Context.getMatrix(ContextualParameters.MatrixRole)} method.
*
* @param parameterized a transform for normalized input and output coordinates.
* @param context source and target coordinate systems in which the transform is going to be used.
* @return a transform taking in account unit conversions and axis swapping.
* @throws FactoryException if the object creation failed.
*
* @see org.apache.sis.referencing.cs.AxesConvention#NORMALIZED
* @see org.apache.sis.referencing.operation.DefaultConversion#DefaultConversion(Map, OperationMethod, MathTransform, ParameterValueGroup)
*
* @since 0.7
*/
public MathTransform swapAndScaleAxes(final MathTransform parameterized, final Context context) throws FactoryException {
ArgumentChecks.ensureNonNull("parameterized", parameterized);
ArgumentChecks.ensureNonNull("context", context);
/*
* Computes matrix for swapping axis and performing units conversion.
* There is one matrix to apply before projection on (longitude,latitude)
* coordinates, and one matrix to apply after projection on (easting,northing)
* coordinates.
*/
final Matrix swap1 = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
final Matrix swap3 = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
/*
* Prepares the concatenation of the matrices computed above and the projection.
* Note that at this stage, the dimensions between each step may not be compatible.
* For example the projection (step2) is usually two-dimensional while the source
* coordinate system (step1) may be three-dimensional if it has a height.
*/
MathTransform step1 = (swap1 != null) ? createAffineTransform(swap1) : MathTransforms.identity(parameterized.getSourceDimensions());
MathTransform step3 = (swap3 != null) ? createAffineTransform(swap3) : MathTransforms.identity(parameterized.getTargetDimensions());
MathTransform step2 = parameterized;
/*
* Special case for the way EPSG handles reversal of axis direction. For now the "Vertical Offset" (EPSG:9616)
* method is the only one for which we found a need for special case. But if more special cases are added in a
* future SIS version, then we should replace the static method by a non-static one defined in AbstractProvider.
*/
if (context.provider instanceof VerticalOffset) {
step2 = VerticalOffset.postCreate(step2, swap3);
}
/*
* If the target coordinate system has a height, instructs the projection to pass
* the height unchanged from the base CRS to the target CRS. After this block, the
* dimensions of 'step2' and 'step3' should match.
*/
final int numTrailingOrdinates = step3.getSourceDimensions() - step2.getTargetDimensions();
if (numTrailingOrdinates > 0) {
step2 = createPassThroughTransform(0, step2, numTrailingOrdinates);
}
/*
* If the source CS has a height but the target CS doesn't, drops the extra coordinates.
* After this block, the dimensions of 'step1' and 'step2' should match.
*/
final int sourceDim = step1.getTargetDimensions();
final int targetDim = step2.getSourceDimensions();
if (sourceDim > targetDim) {
final Matrix drop = Matrices.createDiagonal(targetDim + 1, sourceDim + 1);
// Element in the lower-right corner.
drop.setElement(targetDim, sourceDim, 1);
step1 = createConcatenatedTransform(createAffineTransform(drop), step1);
}
MathTransform mt = createConcatenatedTransform(createConcatenatedTransform(step1, step2), step3);
/*
* At this point we finished to create the transform. But before to return it, verify if the
* parameterized transform given in argument had some custom parameters. This happen with the
* Equirectangular projection, which can be simplified as an AffineTransform while we want to
* continue to describe it with the "semi_major", "semi_minor", etc. parameters instead than
* "elt_0_0", "elt_0_1", etc. The following code just forwards those parameters to the newly
* created transform; it does not change the operation.
*/
if (parameterized instanceof ParameterizedAffine && !(mt instanceof ParameterizedAffine)) {
mt = ((ParameterizedAffine) parameterized).newTransform(mt);
}
return mt;
}
Aggregations