Search in sources :

Example 1 with ParameterizedAffine

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;
}
Also used : Parameters(org.apache.sis.parameter.Parameters) ContextualParameters(org.apache.sis.referencing.operation.transform.ContextualParameters) ContextualParameters(org.apache.sis.referencing.operation.transform.ContextualParameters) MathTransform(org.opengis.referencing.operation.MathTransform) AffineTransform(java.awt.geom.AffineTransform) ParameterizedAffine(org.apache.sis.internal.referencing.j2d.ParameterizedAffine) MatrixSIS(org.apache.sis.referencing.operation.matrix.MatrixSIS) DoubleDouble(org.apache.sis.internal.util.DoubleDouble)

Example 2 with ParameterizedAffine

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;
}
Also used : Matrix(org.opengis.referencing.operation.Matrix) MathTransform(org.opengis.referencing.operation.MathTransform) ParameterizedAffine(org.apache.sis.internal.referencing.j2d.ParameterizedAffine) VerticalOffset(org.apache.sis.internal.referencing.provider.VerticalOffset)

Aggregations

ParameterizedAffine (org.apache.sis.internal.referencing.j2d.ParameterizedAffine)2 MathTransform (org.opengis.referencing.operation.MathTransform)2 AffineTransform (java.awt.geom.AffineTransform)1 VerticalOffset (org.apache.sis.internal.referencing.provider.VerticalOffset)1 DoubleDouble (org.apache.sis.internal.util.DoubleDouble)1 Parameters (org.apache.sis.parameter.Parameters)1 MatrixSIS (org.apache.sis.referencing.operation.matrix.MatrixSIS)1 ContextualParameters (org.apache.sis.referencing.operation.transform.ContextualParameters)1 Matrix (org.opengis.referencing.operation.Matrix)1