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);
}
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());
}
}
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);
}
}
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;
}
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);
}
Aggregations