Author: desruisseaux
Date: Mon Mar 5 13:11:24 2018
New Revision: 1825890
URL: http://svn.apache.org/viewvc?rev=1825890&view=rev
Log:
Implement the inverse of SpecializableTransform (needed for quasi-regular
localisation grids).
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1825890&r1=1825889&r2=1825890&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
[UTF-8] Mon Mar 5 13:11:24 2018
@@ -1003,11 +1003,14 @@ public abstract class AbstractMathTransf
*/
protected abstract class Inverse extends AbstractMathTransform implements
Serializable {
/**
- * Serial number for inter-operability with different versions. This
serial number is
- * especially important for inner classes, since the default {@code
serialVersionUID}
- * computation will not produce consistent results across
implementations of different
- * Java compiler. This is because different compilers may generate
different names for
- * synthetic members used in the implementation of inner classes. See:
+ * Serial number for inter-operability with different versions.
+ *
+ * Note: the default {@code serialVersionUID} computation does not
produce consistent results
+ * across implementation of different Java compilers because different
compilers may generate
+ * different names for synthetic members used in the implementation of
inner classes. Fixing
+ * the serial number here avoid this issue, but may create new
problems since reading a class
+ * serialized with an Apache SIS library compiled with a different
compiler may not recognize
+ * the fields that are named differently. See:
*
* http://developer.java.sun.com/developer/bugParade/bugs/4211550.html
*/
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java?rev=1825890&r1=1825889&r2=1825890&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
[UTF-8] Mon Mar 5 13:11:24 2018
@@ -19,12 +19,14 @@ package org.apache.sis.referencing.opera
import java.util.Map;
import java.util.Arrays;
import java.util.Objects;
+import java.io.Serializable;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
import org.apache.sis.internal.referencing.DirectPositionView;
import org.apache.sis.internal.referencing.Resources;
@@ -45,7 +47,7 @@ import org.apache.sis.util.ArraysExt;
* @since 1.0
* @module
*/
-class SpecializableTransform extends AbstractMathTransform {
+class SpecializableTransform extends AbstractMathTransform implements
Serializable {
/**
* The generic transform to use if there is no suitable specialization.
*/
@@ -56,13 +58,27 @@ class SpecializableTransform extends Abs
* Contains also a chain of {@code SubArea}s fully included in this area.
* Shall be unmodified after {@link SpecializableTransform} construction.
*/
+ @SuppressWarnings("CloneableClassWithoutClone")
// We will not use clone().
private static final class SubArea extends GeneralEnvelope {
/**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = 4197316795428796526L;
+
+ /**
* The transform to apply in this area.
*/
final MathTransform transform;
/**
+ * The inverse of the transform, computed when first needed.
+ * Synchronization for multi-threading is done (indirectly) in {@link
SpecializableTransform#inverse()}.
+ *
+ * @see #createInverse(SubArea)
+ */
+ MathTransform inverse;
+
+ /**
* Specialization, or {@code null} if none. If non-null, that sub-area
shall be fully included
* in this {@code SubArea}. The specialization may itself contain
another specialization. This
* form a chain from this wider area to smallest area, where each step
is a smaller area.
@@ -121,6 +137,17 @@ class SpecializableTransform extends Abs
}
/**
+ * Creates the inverse transforms. This method should be invoked only
once when first needed
+ * in a block synchronized (indirectly) by {@link
SpecializableTransform#inverse()}.
+ */
+ static void createInverse(SubArea area) throws
NoninvertibleTransformException {
+ do {
+ area.inverse = area.transform.inverse();
+ area = area.specialization;
+ } while (area != null);
+ }
+
+ /**
* Returns the area that contains the given position, or {@code null}
if none.
* This method may be replaced by an R-Tree in a future Apache SIS
version.
*/
@@ -147,11 +174,24 @@ class SpecializableTransform extends Abs
while (area.contains(pos)) {
found = area;
area = area.specialization;
+ if (area == null) break;
}
return found;
}
/**
+ * Formats the given area and its transform as a pseudo-WKT.
+ * For {@link SpecializableTransform#formatTo(Formatter)}
implementation only.
+ */
+ static void format(SubArea area, final Formatter formatter) {
+ while (area != null) {
+ formatter.newLine(); formatter.append(area);
+ formatter.newLine(); formatter.append(area.transform);
+ area = area.specialization;
+ }
+ }
+
+ /**
* For {@link SpecializableTransform#computeHashCode()} implementation.
*/
@Override
@@ -194,7 +234,18 @@ class SpecializableTransform extends Abs
private final SubArea[] domains;
/**
+ * The inverse of this transform, computed when first needed.
+ * Part of serialization for avoiding rounding error issues.
+ *
+ * @see #inverse()
+ */
+ private MathTransform inverse;
+
+ /**
* Creates a new transform with the given generic transform and some
amount of specializations.
+ *
+ * @param generic the generic transform to use if there is no suitable
specialization.
+ * @param specializations more accurate transforms available in
sub-areas.
*/
SpecializableTransform(final MathTransform generic, final
Map<Envelope,MathTransform> specializations)
throws InvalidGeodeticParameterException
@@ -299,8 +350,9 @@ next: for (final Map.Entry<Envelope,Ma
if (tr instanceof AbstractMathTransform) {
return ((AbstractMathTransform) tr).transform(srcPts, srcOff,
dstPts, dstOff, derivate);
} else {
+ Matrix derivative = derivate ? tr.derivative(pos) : null; //
Must be before transform(srcPts, …).
tr.transform(srcPts, srcOff, dstPts, dstOff, 1);
- return derivate ? tr.derivative(pos) : null;
+ return derivative;
}
}
@@ -369,7 +421,7 @@ next: for (final Map.Entry<Envelope,Ma
* This method delegates to the most specialized transform.
*/
@Override
- public void transform(double[] srcPts, int srcOff, double[] dstPts, int
dstOff, int numPts)
+ public final void transform(double[] srcPts, int srcOff, final double[]
dstPts, int dstOff, final int numPts)
throws TransformException
{
int srcInc = getSourceDimensions();
@@ -402,7 +454,7 @@ next: for (final Map.Entry<Envelope,Ma
* This method delegates to the most specialized transform.
*/
@Override
- public void transform(float[] srcPts, int srcOff, float[] dstPts, int
dstOff, int numPts)
+ public final void transform(float[] srcPts, int srcOff, final float[]
dstPts, int dstOff, final int numPts)
throws TransformException
{
int srcInc = getSourceDimensions();
@@ -435,8 +487,9 @@ next: for (final Map.Entry<Envelope,Ma
* with single {@code transform(…)} calls for coordinate sequences as long
as possible.
*/
@Override
- public void transform(final double[] srcPts, int srcOff,
- final float [] dstPts, int dstOff, int numPts)
throws TransformException
+ public final void transform(final double[] srcPts, final int srcOff,
+ final float [] dstPts, final int dstOff,
+ final int numPts) throws TransformException
{
final int srcDim = getSourceDimensions();
final int dstDim = getTargetDimensions();
@@ -450,9 +503,9 @@ next: for (final Map.Entry<Envelope,Ma
* with single {@code transform(…)} calls for coordinate sequences as long
as possible.
*/
@Override
- public void transform(final float [] srcPts, int srcOff,
- final double[] dstPts, int dstOff, int numPts)
- throws TransformException
+ public final void transform(final float [] srcPts, final int srcOff,
+ final double[] dstPts, final int dstOff,
+ final int numPts) throws TransformException
{
final int srcDim = getSourceDimensions();
final int dstDim = getTargetDimensions();
@@ -466,7 +519,7 @@ next: for (final Map.Entry<Envelope,Ma
* This method is invoked by {@link #hashCode()} when first needed.
*/
@Override
- protected int computeHashCode() {
+ protected final int computeHashCode() {
return super.computeHashCode() + 7*generic.hashCode() ^
Arrays.hashCode(domains);
}
@@ -474,7 +527,7 @@ next: for (final Map.Entry<Envelope,Ma
* Compares the specified object with this math transform for equality.
*/
@Override
- public boolean equals(final Object object, final ComparisonMode mode) {
+ public final boolean equals(final Object object, final ComparisonMode
mode) {
if (super.equals(object, mode)) {
final SpecializableTransform other = (SpecializableTransform)
object;
return Utilities.deepEquals(generic, other.generic, mode) &&
@@ -493,13 +546,229 @@ next: for (final Map.Entry<Envelope,Ma
* @return the WKT element name, which is {@code "Specializable_MT"}.
*/
@Override
- protected String formatTo(final Formatter formatter) {
- for (final SubArea domain : domains) {
- formatter.newLine(); formatter.append(generic);
- formatter.newLine(); formatter.append(domain);
- formatter.newLine(); formatter.append(domain.transform);
+ protected final String formatTo(final Formatter formatter) {
+ formatter.newLine();
+ formatter.append(generic);
+ for (SubArea domain : domains) {
+ SubArea.format(domain, formatter);
}
formatter.setInvalidWKT(SpecializableTransform.class, null);
return "Specializable_MT";
}
+
+ /**
+ * Returns the inverse of this transform.
+ */
+ @Override
+ public final synchronized MathTransform inverse() throws
NoninvertibleTransformException {
+ if (inverse == null) {
+ inverse = new Inverse(generic);
+ }
+ return inverse;
+ }
+
+ /**
+ * The inverse of {@link SpecializableTransform}.
+ */
+ private final class Inverse extends AbstractMathTransform.Inverse {
+ /**
+ * The inverse of {@link SpecializableTransform#generic}.
+ */
+ private final MathTransform generic;
+
+ /**
+ * Creates the inverse of a specialized transform having the given
properties.
+ */
+ Inverse(final MathTransform generic) throws
NoninvertibleTransformException {
+ this.generic = generic.inverse();
+ for (final SubArea domain : domains) {
+ SubArea.createInverse(domain);
+ }
+ }
+
+ /**
+ * Inverse transforms the specified {@code ptSrc} and stores the
result in {@code ptDst}.
+ */
+ @Override
+ public final DirectPosition transform(final DirectPosition ptSrc,
DirectPosition ptDst) throws TransformException {
+ final double[] source = ptSrc.getCoordinate(); // Needs to be
first in case ptDst overwrites ptSrc.
+ ptDst = generic.transform(ptSrc, ptDst);
+ final SubArea domain = SubArea.find(domains, ptDst);
+ if (domain != null) {
+ ptDst = domain.inverse.transform(new
DirectPositionView.Double(source, 0, source.length), ptDst);
+ }
+ return ptDst;
+ }
+
+ /**
+ * Gets the inverse derivative of this transform at a point.
+ * This method is overridden for consistency.
+ */
+ @Override
+ public final Matrix derivative(final DirectPosition point) throws
TransformException {
+ return transform(point.getCoordinate(), 0, null, 0, true);
+ }
+
+ /**
+ * Inverse transforms a single coordinate point in an array, and
optionally computes the transform
+ * derivative at that location.
+ */
+ @Override
+ public final Matrix transform(double[] srcPts, int srcOff, double[]
dstPts, int dstOff, final boolean derivate)
+ throws TransformException
+ {
+ final int srcInc = generic.getSourceDimensions();
+ final int dstInc = generic.getTargetDimensions();
+ if (dstPts == null) {
+ dstPts = new double[dstInc]; // Needed for
checking if inside a sub-area.
+ dstOff = 0;
+ } else if (srcPts == dstPts && srcOff + srcInc > dstOff && srcOff
< dstOff + dstInc) {
+ srcPts = Arrays.copyOfRange(srcPts, srcOff, srcInc);
+ srcOff = 0;
+ }
+ /*
+ * Above 'srcPts' dhould keep the source coordinates unchanged
even if the source and destination
+ * given in arguments overlap. We need this stability because the
source coordinates may be used
+ * twice, if 'secondTry' become true.
+ */
+ MathTransform tr = generic;
+ boolean secondTry = false;
+ Matrix derivative;
+ do {
+ if (tr instanceof AbstractMathTransform) {
+ derivative = ((AbstractMathTransform)
tr).transform(srcPts, srcOff, dstPts, dstOff, derivate);
+ } else {
+ tr.transform(srcPts, srcOff, dstPts, dstOff, 1);
+ derivative = derivate ? tr.derivative(new
DirectPositionView.Double(srcPts, srcOff, srcInc)) : null;
+ }
+ if (secondTry) break;
+ final SubArea domain = SubArea.find(domains, new
DirectPositionView.Double(dstPts, dstOff, dstInc));
+ if (domain != null) {
+ tr = domain.inverse;
+ secondTry = true;
+ }
+ } while (secondTry);
+ return derivative;
+ }
+
+ /**
+ * Invoked for transforming, then verifying if more appropriate
transform exists for the result.
+ * This implementation is similar to the algorithm applied by {@link
SpecializableTransform} parent
+ * class, except that {@link SubArea} is verified <em>after</em>
transformations instead than before.
+ */
+ private void transform(final TransformCall transform, final double[]
dstPts,
+ int srcOff, int dstOff, int srcInc, int dstInc, int numPts)
throws TransformException
+ {
+ final SubArea[] domains = SpecializableTransform.this.domains;
+ transform.apply(generic, srcOff, dstOff, numPts);
+ final DirectPositionView dst = new
DirectPositionView.Double(dstPts, dstOff, dstInc);
+ while (numPts > 0) {
+ SubArea domain = SubArea.find(domains, dst);
+ if (domain == null) {
+ dst.offset += dstInc;
+ numPts--;
+ continue;
+ }
+ do {
+ final SubArea specialized = domain; //
Contains the specialized transform to use.
+ int num = (dst.offset - dstOff) / dstInc; // Number
of points that are not retransformeD.
+ srcOff += num * srcInc; // Skip
the source coordinates that are not retransformed.
+ dstOff = dst.offset; //
Destination index of the first coordinate to retransform.
+ do {
+ dst.offset += dstInc; //
Destination index after the last coordinate to transform.
+ if (--numPts <= 0) {
+ domain = null;
+ break;
+ }
+ domain = SubArea.find(domain, dst);
+ } while (domain == specialized);
+ num = (dst.offset - dstOff) / dstInc; // Number
of points to retransform.
+ transform.apply(specialized.inverse, srcOff, dstOff, num);
+ srcOff += srcInc * num;
+ dstOff = dst.offset;
+ } while (domain != null);
+ }
+ }
+
+ /**
+ * Inverse transforms a list of coordinate points.
+ * The transformed points are written directly in the destination
array.
+ */
+ @Override
+ public void transform(double[] srcPts, int srcOff, final double[]
dstPts, final int dstOff, final int numPts)
+ throws TransformException
+ {
+ if (numPts <= 0) return;
+ final int srcInc = generic.getSourceDimensions();
+ final int dstInc = generic.getTargetDimensions();
+ if (srcPts == dstPts) {
+ final int srcEnd = srcOff + numPts*srcInc;
+ if (srcEnd > dstOff || dstOff + numPts*dstInc > srcOff) {
+ srcPts = Arrays.copyOfRange(srcPts, srcOff, srcEnd);
+ srcOff = 0;
+ }
+ }
+ final double[] refPts = srcPts;
+ transform((tr, src, dst, num) -> tr.transform(refPts, src, dstPts,
dst, num),
+ dstPts, srcOff, dstOff, srcInc, dstInc, numPts);
+ }
+
+ /**
+ * Inverse transforms a list of coordinate points. This method uses an
temporary {@code double[]} buffer
+ * for testing {@code SubArea} inclusion with full precision before to
cast to {@code float} values.
+ */
+ @Override
+ public void transform(final float[] srcPts, int srcOff,
+ final float[] dstPts, int dstOff, int numPts)
+ throws TransformException
+ {
+ if (numPts <= 0) return;
+ final int srcInc = generic.getSourceDimensions();
+ final int dstInc = generic.getTargetDimensions();
+ final double[] buffer = new double[numPts * dstInc];
+ transform((tr, src, dst, num) -> tr.transform(srcPts, src, buffer,
dst, num),
+ buffer, srcOff, 0, srcInc, dstInc, numPts);
+
+ numPts *= dstInc;
+ for (int i=0; i<numPts; i++) {
+ dstPts[dstOff++] = (float) buffer[i];
+ }
+ }
+
+ /**
+ * Inverse transforms a list of coordinate points. This method uses an
temporary {@code double[]} buffer
+ * for testing {@code SubArea} inclusion with full precision before to
cast to {@code float} values.
+ */
+ @Override
+ public void transform(final double[] srcPts, int srcOff,
+ final float [] dstPts, int dstOff, int numPts)
throws TransformException
+ {
+ if (numPts <= 0) return;
+ final int srcInc = generic.getSourceDimensions();
+ final int dstInc = generic.getTargetDimensions();
+ final double[] buffer = new double[numPts * dstInc];
+ transform((tr, src, dst, num) -> tr.transform(srcPts, src, buffer,
dst, num),
+ buffer, srcOff, 0, srcInc, dstInc, numPts);
+
+ numPts *= dstInc;
+ for (int i=0; i<numPts; i++) {
+ dstPts[dstOff++] = (float) buffer[i];
+ }
+ }
+
+ /**
+ * Inverse transforms a list of coordinate points.
+ * The transformed points are written directly in the destination
array.
+ */
+ @Override
+ public void transform(final float [] srcPts, int srcOff,
+ final double[] dstPts, int dstOff, int numPts)
throws TransformException
+ {
+ if (numPts <= 0) return;
+ final int srcInc = generic.getSourceDimensions();
+ final int dstInc = generic.getTargetDimensions();
+ transform((tr, src, dst, num) -> tr.transform(srcPts, src, dstPts,
dst, num),
+ dstPts, srcOff, dstOff, srcInc, dstInc, numPts);
+ }
+ }
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java?rev=1825890&r1=1825889&r2=1825890&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java
[UTF-8] Mon Mar 5 13:11:24 2018
@@ -32,7 +32,7 @@ import org.apache.sis.referencing.datum.
* This class can generate random number suitable for their domain.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.0
* @since 0.5
* @module
*/
@@ -215,6 +215,14 @@ public strictfp class CoordinateDomain {
-10, 10);
/**
+ * Values in the -100 to 100 range in all dimensions.
+ */
+ public static final CoordinateDomain RANGE_100 = new CoordinateDomain(
+ -100, 100,
+ -100, 100,
+ -100, 100);
+
+ /**
* The domain of the coordinates to test.
*/
final double xmin, xmax, ymin, ymax, zmin, zmax;
Modified:
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java?rev=1825890&r1=1825889&r2=1825890&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
[UTF-8] Mon Mar 5 13:11:24 2018
@@ -59,20 +59,79 @@ public final strictfp class Specializabl
}
/**
- * Tests consistency between different {@code transform(…)} methods.
+ * Invokes {@link #verifyDerivative(double...)} for all points in the
given array.
+ */
+ private void verifyDerivatives(final double[] coordinates) throws
TransformException {
+ tolerance = 1E-10;
+ derivativeDeltas = new double[] {0.001};
+ final double[] point = new double[2];
+ for (int i=0; i < coordinates.length; i += 2) {
+ System.arraycopy(coordinates, i, point, 0, 2);
+ verifyDerivative(point);
+ }
+ }
+
+ /**
+ * Verifies the transform with a few hard-coded points. The point are
selected in order to avoid
+ * situations where two transforms could calculate the same point (because
of the way we created
+ * our test transform).
*
* @throws InvalidGeodeticParameterException if {@link
SpecializableTransform} constructor reject a parameter.
* @throws TransformException if a transformation failed.
*/
@Test
- public void testConsistency() throws InvalidGeodeticParameterException,
TransformException {
+ public void testTransform() throws InvalidGeodeticParameterException,
TransformException {
+ // ┌─── generic ───┐┌───── Special. 1
──────┐┌──── Special. 2 ─────┐
+ final double[] source = {8, 2, 4, 5, 3, 2, 2, -2, -2,
0, 1, 0, 8, 3};
+ final double[] target = {80, 20, 40, 50, 30.1, 20.1, 20.1, -19.9,
-19.8, 0.2, 10.2, 0.2, 80, 30};
+
+ tolerance = 1E-14;
transform = create();
+ verifyTransform(source, target);
+ verifyDerivatives(source);
+
+ tolerance = 1E-14;
+ transform = transform.inverse();
+ verifyTransform(target, source);
+ verifyDerivatives(target);
+ }
+
+ /**
+ * Tests consistency between different {@code transform(…)} methods in
forward transforms.
+ * This test uses a fixed sequence of random numbers. We fix the sequence
because the transform
+ * used in this test is {@linkplain
org.apache.sis.math.FunctionProperty#SURJECTIVE surjective}:
+ * some target coordinates can be created from more than one source
coordinates. We need to be
+ * "lucky" enough for not testing a point in this case, otherwise the
result is undetermined.
+ *
+ * @throws InvalidGeodeticParameterException if {@link
SpecializableTransform} constructor reject a parameter.
+ * @throws TransformException if a transformation failed.
+ */
+ @Test
+ public void testForwardConsistency() throws
InvalidGeodeticParameterException, TransformException {
+ transform = create();
+ tolerance = 1E-14;
isDerivativeSupported = false; // Actually supported, but our
test transform has discontinuities.
- isInverseTransformSupported = false;
verifyInDomain(CoordinateDomain.RANGE_10, -672445632505596619L);
}
/**
+ * Tests consistency between different {@code transform(…)} methods in
inverse transforms.
+ * This test uses a fixed sequence of random numbers. We fix the sequence
because the transform
+ * used in this test is {@linkplain
org.apache.sis.math.FunctionProperty#SURJECTIVE surjective}.
+ * See {@link #testForwardConsistency()}.
+ *
+ * @throws InvalidGeodeticParameterException if {@link
SpecializableTransform} constructor reject a parameter.
+ * @throws TransformException if a transformation failed.
+ */
+ @Test
+ public void testInverseConsistency() throws
InvalidGeodeticParameterException, TransformException {
+ transform = create().inverse();
+ tolerance = 1E-12;
+ isDerivativeSupported = false; // Actually supported, but our
test transform has discontinuities.
+ verifyInDomain(CoordinateDomain.RANGE_100, 4308397764777385180L);
+ }
+
+ /**
* Tests the pseudo Well-Known Text formatting.
* The format used by this transform is non-standard and may change in any
future Apache SIS version.
*
@@ -92,6 +151,13 @@ public final strictfp class Specializabl
" PARAMETER[“elt_0_0”, 10.0],\n" +
" PARAMETER[“elt_0_2”, 0.1],\n" +
" PARAMETER[“elt_1_1”, 10.0],\n" +
- " PARAMETER[“elt_1_2”, 0.1]]]");
+ " PARAMETER[“elt_1_2”, 0.1]],\n" +
+ " DOMAIN[-3 -1,\n" +
+ " 2 1],\n" +
+ " PARAM_MT[“Affine”,\n" +
+ " PARAMETER[“elt_0_0”, 10.0],\n" +
+ " PARAMETER[“elt_0_2”, 0.2],\n" +
+ " PARAMETER[“elt_1_1”, 10.0],\n" +
+ " PARAMETER[“elt_1_2”, 0.2]]]");
}
}