use of org.opengis.referencing.operation.MathTransform2D 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);
}
use of org.opengis.referencing.operation.MathTransform2D in project sis by apache.
the class TransformTestCase method testTransform.
/**
* Tests the transformation of an envelope or rectangle. This is a relatively simple test case
* working in the two-dimensional space only, with a coordinate operation of type "conversion"
* (not a "transformation") and with no need to adjust for poles.
*
* @throws FactoryException if an error occurred while creating the operation.
* @throws TransformException if an error occurred while transforming the envelope.
*/
@Test
public final void testTransform() throws FactoryException, TransformException {
final ProjectedCRS targetCRS = CommonCRS.WGS84.universal(10, -123.5);
final GeographicCRS sourceCRS = targetCRS.getBaseCRS();
final Conversion conversion = targetCRS.getConversionFromBase();
final MathTransform2D transform = (MathTransform2D) conversion.getMathTransform();
/*
* Transforms envelopes using MathTransform. Geographic coordinates are in (latitude, longitude) order.
* Opportunistically check that the transform using a CoordinateOperation object produces the same result.
*/
final G rectλφ = createFromExtremums(sourceCRS, -20, -126, 40, -120);
final G rectXY = transform(targetCRS, transform, rectλφ);
assertEquals("Conversion should produce the same result.", rectXY, transform(conversion, rectλφ));
/*
* Expected values are determined empirically by projecting many points.
* Those values are the same than in EnvelopesTest.testTransform().
*/
final G expected = createFromExtremums(targetCRS, 166021.56, -2214294.03, 833978.44, 4432069.06);
assertGeometryEquals(expected, rectXY, LINEAR_TOLERANCE, LINEAR_TOLERANCE);
/*
* Test the inverse conversion.
* Final envelope should be slightly bigger than the original.
*/
final G rectBack = transform(sourceCRS, transform.inverse(), rectXY);
assertTrue("Transformed envelope should not be smaller than the original one.", contains(rectBack, rectλφ));
assertGeometryEquals(rectλφ, rectBack, 0.05, 1.0);
}
use of org.opengis.referencing.operation.MathTransform2D in project sis by apache.
the class ConcatenatedTransform method create.
/**
* Concatenates the two given transforms.
* If the concatenation result works with two-dimensional input and output points,
* then the returned transform will implement {@link MathTransform2D}.
* Likewise if the concatenation result works with one-dimensional input and output points,
* then the returned transform will implement {@link MathTransform1D}.
*
* <div class="note"><b>Implementation note:</b>
* {@code ConcatenatedTransform} implementations are available in two versions: direct and non-direct.
* The "non-direct" versions use an intermediate buffer when performing transformations; they are slower
* and consume more memory. They are used only as a fallback when a "direct" version can not be created.</div>
*
* @param tr1 the first math transform.
* @param tr2 the second math transform.
* @param factory the factory which is (indirectly) invoking this method, or {@code null} if none.
* @return the concatenated transform.
*
* @see MathTransforms#concatenate(MathTransform, MathTransform)
*/
public static MathTransform create(MathTransform tr1, MathTransform tr2, final MathTransformFactory factory) throws FactoryException, MismatchedDimensionException {
final int dim1 = tr1.getTargetDimensions();
final int dim2 = tr2.getSourceDimensions();
if (dim1 != dim2) {
throw new MismatchedDimensionException(Resources.format(Resources.Keys.CanNotConcatenateTransforms_2, getName(tr1), getName(tr2)) + ' ' + Errors.format(Errors.Keys.MismatchedDimension_2, dim1, dim2));
}
MathTransform mt = createOptimized(tr1, tr2, factory);
if (mt != null) {
return mt;
}
/*
* If at least one math transform is an instance of ConcatenatedTransform and assuming
* that MathTransforms are associatives, tries the following arrangements and select
* the one with the fewest amount of steps:
*
* Assuming : tr1 = (A * B)
* tr2 = (C * D)
*
* Current : (A * B) * (C * D) Will be the selected one if nothing better.
* Try k=0 : A * (B * (C * D)) Implies A * ((B * C) * D) through recursivity.
* Try k=1 : ((A * B) * C) * D Implies (A * (B * C)) * D through recursivity.
* Try k=2 : Tried only if try k=1 changed something.
*
* TODO: The same combination may be computed more than once (e.g. (B * C) above).
* Should not be a big deal if there is not two many steps. In the even where
* it would appears a performance issue, we could maintain a Map of combinations
* already computed. The map would be local to a "create" method execution.
*/
int stepCount = getStepCount(tr1) + getStepCount(tr2);
// Really 'true' because we want at least 2 iterations.
boolean tryAgain = true;
for (int k = 0; ; k++) {
MathTransform c1 = tr1;
MathTransform c2 = tr2;
final boolean first = (k & 1) == 0;
MathTransform candidate = first ? c1 : c2;
while (candidate instanceof ConcatenatedTransform) {
final ConcatenatedTransform ctr = (ConcatenatedTransform) candidate;
if (first) {
c1 = candidate = ctr.transform1;
c2 = create(ctr.transform2, c2, factory);
} else {
c1 = create(c1, ctr.transform1, factory);
c2 = candidate = ctr.transform2;
}
final int c = getStepCount(c1) + getStepCount(c2);
if (c < stepCount) {
tr1 = c1;
tr2 = c2;
stepCount = c;
tryAgain = true;
}
}
if (!tryAgain)
break;
tryAgain = false;
}
/*
* Tries again the check for optimized cases (identity, etc.), because a
* transform may have been simplified to identity as a result of the above.
*/
mt = createOptimized(tr1, tr2, factory);
if (mt != null) {
return mt;
}
/*
* Can not avoid the creation of a ConcatenatedTransform object.
* Check for the type to create (1D, 2D, general case...)
*/
final int dimSource = tr1.getSourceDimensions();
final int dimTarget = tr2.getTargetDimensions();
if (dimSource == 1 && dimTarget == 1) {
/*
* Result needs to be a MathTransform1D.
*/
if (tr1 instanceof MathTransform1D && tr2 instanceof MathTransform1D) {
return new ConcatenatedTransformDirect1D((MathTransform1D) tr1, (MathTransform1D) tr2);
} else {
return new ConcatenatedTransform1D(tr1, tr2);
}
} else if (dimSource == 2 && dimTarget == 2) {
/*
* Result needs to be a MathTransform2D.
*/
if (tr1 instanceof MathTransform2D && tr2 instanceof MathTransform2D) {
return new ConcatenatedTransformDirect2D((MathTransform2D) tr1, (MathTransform2D) tr2);
} else {
return new ConcatenatedTransform2D(tr1, tr2);
}
} else if (// dim1 = tr1.getTargetDimensions() and
dimSource == tr1.getTargetDimensions() && // dim2 = tr2.getSourceDimensions() may not be true anymore.
dimTarget == tr2.getSourceDimensions()) {
return new ConcatenatedTransformDirect(tr1, tr2);
} else {
return new ConcatenatedTransform(tr1, tr2);
}
}
Aggregations