Search in sources :

Example 1 with Conversion

use of org.opengis.referencing.operation.Conversion in project sis by apache.

the class DefaultConversionTest method testSpecialize.

/**
 * Tests {@link DefaultConversion#specialize DefaultConversion.specialize(…)} with new source and target CRS.
 * This test attempts to swap axis order and change the number of dimensions of the <em>target</em> CRS.
 *
 * <div class="note"><b>Note:</b>
 * By contrast, {@link #testDefiningConversion()} tested swapping axis order in the <em>source</em> CRS.</div>
 *
 * @throws FactoryException if an error occurred while creating the conversion.
 */
@Test
@DependsOnMethod("testDefiningConversion")
public void testSpecialize() throws FactoryException {
    final MathTransformFactory factory = DefaultFactories.forBuildin(MathTransformFactory.class);
    DefaultConversion op = createLongitudeRotation(createParisCRS(true, HardCodedCS.GEODETIC_3D, false), createParisCRS(false, HardCodedCS.GEODETIC_3D, true), null);
    assertMatrixEquals("Longitude rotation of a three-dimensional CRS", new Matrix4(1, 0, 0, OFFSET, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1), MathTransforms.getMatrix(op.getMathTransform()), STRICT);
    /*
         * When asking for a "specialization" with the same properties,
         * we should get the existing instance since no change is needed.
         */
    assertSame(op, op.specialize(Conversion.class, op.getSourceCRS(), op.getTargetCRS(), factory));
    /*
         * Reducing the number of dimensions to 2 and swapping (latitude, longitude) axes.
         */
    op = op.specialize(DefaultConversion.class, op.getSourceCRS(), changeCS(op.getTargetCRS(), HardCodedCS.GEODETIC_φλ), factory);
    assertMatrixEquals("Longitude rotation of a two-dimensional CRS", Matrices.create(3, 4, new double[] { 0, 1, 0, 0, 1, 0, 0, OFFSET, 0, 0, 0, 1 }), MathTransforms.getMatrix(op.getMathTransform()), STRICT);
}
Also used : MathTransformFactory(org.opengis.referencing.operation.MathTransformFactory) Conversion(org.opengis.referencing.operation.Conversion) Matrix4(org.apache.sis.referencing.operation.matrix.Matrix4) Test(org.junit.Test) DefaultParameterDescriptorTest(org.apache.sis.parameter.DefaultParameterDescriptorTest) DependsOnMethod(org.apache.sis.test.DependsOnMethod)

Example 2 with Conversion

use of org.opengis.referencing.operation.Conversion in project sis by apache.

the class DefaultMathTransformFactoryTest method testAllMapProjections.

/**
 * Tests the creation of all registered map projections.
 * Only the semi-axis lengths are specified. For the rest, we rely on default values.
 *
 * @throws FactoryException if the construction of a map projection failed.
 *
 * @since 0.7
 */
@Test
public void testAllMapProjections() throws FactoryException {
    /*
         * Gets all map projections and creates a projection using the WGS84 ellipsoid
         * and default parameter values.
         */
    final Map<String, ?> dummyName = Collections.singletonMap(DefaultProjectedCRS.NAME_KEY, "Test");
    final MathTransformFactory mtFactory = DefaultFactories.forBuildin(MathTransformFactory.class);
    final Collection<OperationMethod> methods = mtFactory.getAvailableMethods(Projection.class);
    for (final OperationMethod method : methods) {
        final String classification = method.getName().getCode();
        ParameterValueGroup param = mtFactory.getDefaultParameters(classification);
        param.parameter("semi_major").setValue(6377563.396);
        param.parameter("semi_minor").setValue(6356256.909237285);
        final MathTransform mt;
        try {
            mt = mtFactory.createParameterizedTransform(param);
        } catch (InvalidGeodeticParameterException e) {
            /*
                 * Some map projections have mandatory parameters which we ignore for now
                 * except for a few well-known projection that we know should not fail.
                 */
            if (classification.contains("Mercator")) {
                throw e;
            }
            out.print(classification);
            out.print(CharSequences.spaces(42 - classification.length()));
            out.print(": ");
            out.println(e.getLocalizedMessage());
            continue;
        }
        /*
             * Verifies that the map projection properties are the ones that we specified.
             * Note that the Equirectangular projection has been optimized as an affine transform, which we skip.
             */
        if (mt instanceof LinearTransform) {
            continue;
        }
        assertInstanceOf(classification, Parameterized.class, mt);
        param = ((Parameterized) mt).getParameterValues();
        assertEquals(classification, param.getDescriptor().getName().getCode());
        assertEquals(classification, 6377563.396, param.parameter("semi_major").doubleValue(), 1E-4);
        assertEquals(classification, 6356256.909237285, param.parameter("semi_minor").doubleValue(), 1E-4);
        /*
             * Creates a ProjectedCRS from the map projection. This part is more an integration test than
             * a DefaultMathTransformFactory test. Again, the intent is to verify that the properties are
             * the one that we specified.
             */
        final DefaultProjectedCRS crs = new DefaultProjectedCRS(dummyName, CommonCRS.WGS84.normalizedGeographic(), new DefaultConversion(dummyName, method, mt, null), HardCodedCS.PROJECTED);
        final Conversion projection = crs.getConversionFromBase();
        assertSame(classification, mt, projection.getMathTransform());
        assertEquals(classification, projection.getMethod().getName().getCode());
    }
}
Also used : InvalidGeodeticParameterException(org.apache.sis.referencing.factory.InvalidGeodeticParameterException) MathTransform(org.opengis.referencing.operation.MathTransform) MathTransformFactory(org.opengis.referencing.operation.MathTransformFactory) ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) DefaultConversion(org.apache.sis.referencing.operation.DefaultConversion) DefaultProjectedCRS(org.apache.sis.referencing.crs.DefaultProjectedCRS) Conversion(org.opengis.referencing.operation.Conversion) DefaultConversion(org.apache.sis.referencing.operation.DefaultConversion) OperationMethod(org.opengis.referencing.operation.OperationMethod) Test(org.junit.Test)

Example 3 with Conversion

use of org.opengis.referencing.operation.Conversion in project sis by apache.

the class GeodeticObjectBuilder method createProjectedCRS.

/**
 * Creates a projected CRS using a conversion built from the values given by the {@code setParameter(…)} calls.
 *
 * <div class="note"><b>Example:</b>
 * The following example creates a projected CRS for the <cite>"NTF (Paris) / Lambert zone II"</cite> projection,
 * from a base CRS which is presumed to already exists in this example.
 *
 * {@preformat java
 *   GeodeticObjectBuilder builder = new GeodeticObjectBuilder();
 *   GeographicCRS baseCRS = ...;
 *   CartesianCS derivedCS = ...;
 *   ProjectedCRS crs = builder
 *           .setConversionMethod("Lambert Conic Conformal (1SP)")
 *           .setConversionName("Lambert zone II")
 *           .setParameter("Latitude of natural origin",             52, Units.GRAD)
 *           .setParameter("Scale factor at natural origin", 0.99987742, Units.UNITY)
 *           .setParameter("False easting",                      600000, Units.METRE)
 *           .setParameter("False northing",                    2200000, Units.METRE)
 *           .addName("NTF (Paris) / Lambert zone II")
 *           .createProjectedCRS(baseCRS, derivedCS);
 * }
 * </div>
 *
 * @param  baseCRS    coordinate reference system to base the derived CRS on.
 * @param  derivedCS  the coordinate system for the derived CRS.
 * @return the projected CRS.
 * @throws FactoryException if an error occurred while building the projected CRS.
 */
public ProjectedCRS createProjectedCRS(final GeographicCRS baseCRS, final CartesianCS derivedCS) throws FactoryException {
    ensureConversionMethodSet();
    onCreate(false);
    try {
        /*
             * Create a conversion with the same properties than the ProjectedCRS properties,
             * except the aliases and identifiers. The name defaults to the ProjectedCRS name,
             * but can optionally be different.
             */
        final Object name = (conversionName != null) ? properties.put(Conversion.NAME_KEY, conversionName) : null;
        final Object alias = properties.put(Conversion.ALIAS_KEY, null);
        final Object identifier = properties.put(Conversion.IDENTIFIERS_KEY, null);
        final Conversion conversion = getCoordinateOperationFactory().createDefiningConversion(properties, method, parameters);
        /*
             * Restore the original properties and create the final ProjectedCRS.
             */
        properties.put(Conversion.IDENTIFIERS_KEY, identifier);
        properties.put(Conversion.ALIAS_KEY, alias);
        if (name != null) {
            properties.put(Conversion.NAME_KEY, name);
        }
        return getCRSFactory().createProjectedCRS(properties, baseCRS, conversion, derivedCS);
    } finally {
        onCreate(true);
    }
}
Also used : IdentifiedObject(org.opengis.referencing.IdentifiedObject) Conversion(org.opengis.referencing.operation.Conversion)

Example 4 with Conversion

use of org.opengis.referencing.operation.Conversion in project sis by apache.

the class PositionalAccuracyConstant method getLinearAccuracy.

/**
 * Convenience method returning the accuracy in meters for the specified operation.
 * This method tries each of the following procedures and returns the first successful one:
 *
 * <ul>
 *   <li>If at least one {@link QuantitativeResult} is found with a linear unit, then the largest
 *       accuracy estimate is converted to {@linkplain Units#METRE metres} and returned.</li>
 *   <li>Otherwise, if the operation is a {@link Conversion}, then returns 0 since a conversion
 *       is by definition accurate up to rounding errors.</li>
 *   <li>Otherwise, if the operation is a {@link Transformation}, then checks if the datum shift
 *       were applied with the help of Bursa-Wolf parameters. This procedure looks for SIS-specific
 *       {@link #DATUM_SHIFT_APPLIED} and {@link #DATUM_SHIFT_OMITTED DATUM_SHIFT_OMITTED} constants.</li>
 *   <li>Otherwise, if the operation is a {@link ConcatenatedOperation}, returns the sum of the accuracy
 *       of all components. This is a conservative scenario where we assume that errors cumulate linearly.
 *       Note that this is not necessarily the "worst case" scenario since the accuracy could be worst
 *       if the math transforms are highly non-linear.</li>
 * </ul>
 *
 * If the above is modified, please update {@code AbstractCoordinateOperation.getLinearAccuracy()} javadoc.
 *
 * @param  operation  the operation to inspect for accuracy.
 * @return the accuracy estimate (always in meters), or NaN if unknown.
 *
 * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getLinearAccuracy()
 */
public static double getLinearAccuracy(final CoordinateOperation operation) {
    double accuracy = Double.NaN;
    final Collection<PositionalAccuracy> accuracies = operation.getCoordinateOperationAccuracy();
    for (final PositionalAccuracy metadata : accuracies) {
        for (final Result result : metadata.getResults()) {
            if (result instanceof QuantitativeResult) {
                final QuantitativeResult quantity = (QuantitativeResult) result;
                final Collection<? extends Record> records = quantity.getValues();
                if (records != null) {
                    final Unit<?> unit = quantity.getValueUnit();
                    if (Units.isLinear(unit)) {
                        final Unit<Length> unitOfLength = unit.asType(Length.class);
                        for (final Record record : records) {
                            for (final Object value : record.getAttributes().values()) {
                                if (value instanceof Number) {
                                    double v = ((Number) value).doubleValue();
                                    v = unitOfLength.getConverterTo(Units.METRE).convert(v);
                                    if (v >= 0 && !(v <= accuracy)) {
                                        // '!' is for replacing the NaN value.
                                        accuracy = v;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    if (Double.isNaN(accuracy)) {
        /*
             * No quantitative (linear) accuracy were found. If the coordinate operation is actually
             * a conversion, the accuracy is up to rounding error (i.e. conceptually 0) by definition.
             */
        if (operation instanceof Conversion) {
            return 0;
        }
        /*
             * If the coordinate operation is actually a transformation, checks if Bursa-Wolf parameters
             * were available for the datum shift. This is SIS-specific. See field javadoc for a rational
             * about the return values chosen.
             */
        if (operation instanceof Transformation) {
            if (accuracies.contains(DATUM_SHIFT_APPLIED)) {
                return DATUM_SHIFT_ACCURACY;
            }
            if (accuracies.contains(DATUM_SHIFT_OMITTED)) {
                return UNKNOWN_ACCURACY;
            }
        }
        /*
             * If the coordinate operation is a compound of other coordinate operations, returns the sum of their accuracy,
             * skipping unknown ones. Making the sum is a conservative approach (not exactly the "worst case" scenario,
             * since it could be worst if the transforms are highly non-linear).
             */
        if (operation instanceof ConcatenatedOperation) {
            for (final CoordinateOperation op : ((ConcatenatedOperation) operation).getOperations()) {
                final double candidate = Math.abs(getLinearAccuracy(op));
                if (!Double.isNaN(candidate)) {
                    if (Double.isNaN(accuracy)) {
                        accuracy = candidate;
                    } else {
                        accuracy += candidate;
                    }
                }
            }
        }
    }
    return accuracy;
}
Also used : Transformation(org.opengis.referencing.operation.Transformation) PositionalAccuracy(org.opengis.metadata.quality.PositionalAccuracy) DefaultAbsoluteExternalPositionalAccuracy(org.apache.sis.metadata.iso.quality.DefaultAbsoluteExternalPositionalAccuracy) CoordinateOperation(org.opengis.referencing.operation.CoordinateOperation) Conversion(org.opengis.referencing.operation.Conversion) Result(org.opengis.metadata.quality.Result) QuantitativeResult(org.opengis.metadata.quality.QuantitativeResult) DefaultConformanceResult(org.apache.sis.metadata.iso.quality.DefaultConformanceResult) QuantitativeResult(org.opengis.metadata.quality.QuantitativeResult) Length(javax.measure.quantity.Length) Record(org.opengis.util.Record) ConcatenatedOperation(org.opengis.referencing.operation.ConcatenatedOperation)

Example 5 with Conversion

use of org.opengis.referencing.operation.Conversion in project sis by apache.

the class TransformTestCase method testTransformOverPole.

/**
 * Tests conversions of an envelope or rectangle over a pole using a coordinate operation.
 *
 * @throws FactoryException if an error occurred while creating the operation.
 * @throws TransformException if an error occurred while transforming the envelope.
 */
@Test
@DependsOnMethod("testTransform")
public final void testTransformOverPole() throws FactoryException, TransformException {
    final ProjectedCRS sourceCRS = (ProjectedCRS) CRS.fromWKT("PROJCS[“WGS 84 / Antarctic Polar Stereographic”,\n" + "  GEOGCS[“WGS 84”,\n" + "    DATUM[“World Geodetic System 1984”,\n" + "      SPHEROID[“WGS 84”, 6378137.0, 298.257223563]],\n" + "    PRIMEM[“Greenwich”, 0.0],\n" + "    UNIT[“degree”, 0.017453292519943295]],\n" + "  PROJECTION[“Polar Stereographic (variant B)”],\n" + "  PARAMETER[“standard_parallel_1”, -71.0],\n" + "  UNIT[“m”, 1.0]]");
    final GeographicCRS targetCRS = sourceCRS.getBaseCRS();
    final Conversion conversion = inverse(sourceCRS.getConversionFromBase());
    final MathTransform2D transform = (MathTransform2D) conversion.getMathTransform();
    /*
         * The rectangle to test, which contains the South pole.
         */
    G rectangle = createFromExtremums(sourceCRS, -3943612.4042124213, -4078471.954436003, 3729092.5890516187, 4033483.085688618);
    /*
         * This is what we get without special handling of singularity point.
         * Note that is does not include the South pole as we would expect.
         * The commented out values are what we get by projecting an arbitrary
         * larger amount of points.
         */
    G expected = createFromExtremums(targetCRS, // anti-regression values
    -179.8650137390031, // anti-regression values
    -88.99136583196396, // 178.8122742080059  -40.90577500420587]         // empirical values
    137.9769431693009, // anti-regression values
    -40.90577500420587);
    /*
         * Tests what we actually get. First, test using the method working on MathTransform.
         * Next, test again the same transform, but using the API on Envelope objects.
         */
    G actual = transform(targetCRS, transform, rectangle);
    assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
    /*
         * Using the transform(CoordinateOperation, …) method,
         * the singularity at South pole is taken in account.
         */
    expected = createFromExtremums(targetCRS, -180, -90, 180, -40.905775004205864);
    actual = transform(conversion, rectangle);
    assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
    /*
         * Another rectangle containing the South pole, but this time the south
         * pole is almost in a corner of the rectangle
         */
    rectangle = createFromExtremums(sourceCRS, -4000000, -4000000, 300000, 30000);
    expected = createFromExtremums(targetCRS, -180, -90, 180, -41.03163170198091);
    actual = transform(conversion, rectangle);
    assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
    /*
         * Another rectangle with the South pole close to the border.
         * This test should execute the step #3 in the transform method code.
         */
    rectangle = createFromExtremums(sourceCRS, -2000000, -1000000, 200000, 2000000);
    expected = createFromExtremums(targetCRS, -180, -90, 180, -64.3861643256928);
    actual = transform(conversion, rectangle);
    assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
}
Also used : ProjectedCRS(org.opengis.referencing.crs.ProjectedCRS) GeographicCRS(org.opengis.referencing.crs.GeographicCRS) MathTransform2D(org.opengis.referencing.operation.MathTransform2D) DefaultConversion(org.apache.sis.referencing.operation.DefaultConversion) Conversion(org.opengis.referencing.operation.Conversion) Test(org.junit.Test) DependsOnMethod(org.apache.sis.test.DependsOnMethod)

Aggregations

Conversion (org.opengis.referencing.operation.Conversion)15 DefaultConversion (org.apache.sis.referencing.operation.DefaultConversion)8 Test (org.junit.Test)8 GeographicCRS (org.opengis.referencing.crs.GeographicCRS)6 ProjectedCRS (org.opengis.referencing.crs.ProjectedCRS)5 DependsOnMethod (org.apache.sis.test.DependsOnMethod)4 Length (javax.measure.quantity.Length)2 DefaultConversionTest (org.apache.sis.referencing.operation.DefaultConversionTest)2 ParameterValueGroup (org.opengis.parameter.ParameterValueGroup)2 GeneralDerivedCRS (org.opengis.referencing.crs.GeneralDerivedCRS)2 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)2 MathTransform (org.opengis.referencing.operation.MathTransform)2 MathTransform2D (org.opengis.referencing.operation.MathTransform2D)2 MathTransformFactory (org.opengis.referencing.operation.MathTransformFactory)2 Angle (javax.measure.quantity.Angle)1 CS_CoordinateSystem (org.apache.sis.internal.jaxb.referencing.CS_CoordinateSystem)1 Convention (org.apache.sis.io.wkt.Convention)1 ElementKind (org.apache.sis.io.wkt.ElementKind)1 FormattableObject (org.apache.sis.io.wkt.FormattableObject)1 Formatter (org.apache.sis.io.wkt.Formatter)1