use of org.apache.sis.internal.referencing.j2d.ParameterizedAffine in project sis by apache.
the class Equirectangular method createMathTransform.
/**
* Creates an Equirectangular projection from the specified group of parameter values. This method is an
* adaptation of {@link org.apache.sis.referencing.operation.projection.NormalizedProjection} constructor,
* reproduced in this method because we will create an affine transform instead than the usual projection
* classes.
*
* @param factory the factory to use if this constructor needs to create other math transforms.
* @param parameters the parameter values that define the transform to create.
* @return the map projection created from the given parameter values.
* @throws FactoryException if an error occurred while creating the math transform.
*/
@Override
public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup parameters) throws FactoryException {
final Parameters p = Parameters.castOrWrap(parameters);
final ContextualParameters context = new ContextualParameters(this);
double a = getAndStore(p, context, MapProjection.SEMI_MAJOR);
double b = getAndStore(p, context, MapProjection.SEMI_MINOR);
double λ0 = getAndStore(p, context, LONGITUDE_OF_ORIGIN);
double φ0 = getAndStore(p, context, LATITUDE_OF_ORIGIN);
double φ1 = getAndStore(p, context, STANDARD_PARALLEL);
double fe = getAndStore(p, context, FALSE_EASTING);
double fn = getAndStore(p, context, FALSE_NORTHING);
/*
* Perform following transformation, in that order. Note that following
* AffineTransform convention, the Java code appears in reverse order:
*
* 1) Subtract φ0 to the latitude.
* 2) Subtract λ0 to the longitude.
* 3) Convert degrees to radians.
* 4) Scale longitude by cos(φ1).
*/
φ1 = toRadians(φ1);
final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
normalize.convertBefore(0, cos(φ1), null);
context.normalizeGeographicInputs(λ0).convertBefore(1, null, -φ0);
/*
* At this point, we usually invoke 'denormalize.convertAfter(…, a, …)' where 'a' (the semi-major axis length)
* is taken as the Earth radius (R). However quoting EPSG: "If the figure of the earth used is an ellipsoid
* rather than a sphere then R should be calculated as the radius of the conformal sphere at the projection
* origin at latitude φ1 using the formula for RC given in section 1.2, table 3".
*/
if (a != b) {
final double rs = b / a;
final double sinφ1 = sin(φ1);
a = b / (1 - (1 - rs * rs) * (sinφ1 * sinφ1));
}
final DoubleDouble k = new DoubleDouble(a);
final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
denormalize.convertAfter(0, k, new DoubleDouble(fe));
denormalize.convertAfter(1, k, new DoubleDouble(fn));
/*
* Creates the ConcatenatedTransform, letting the factory returns the cached instance
* if the caller already invoked this method previously (which usually do not happen).
*/
MathTransform mt = context.completeTransform(factory, MathTransforms.identity(2));
if (mt instanceof AffineTransform) {
// Always true in Apache SIS implementation.
mt = new ParameterizedAffine((AffineTransform) mt, context, true);
}
return mt;
}
use of org.apache.sis.internal.referencing.j2d.ParameterizedAffine 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