This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 7c0e987 Add a MathTransforms.tangent(MathTransform, DirectPosition)
method for computing linear approximation of a MathTransform at a given
location.
7c0e987 is described below
commit 7c0e987b57ac7ed7cec75bc7b5e52e16712cdd3c
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Feb 8 13:00:04 2020 +0100
Add a MathTransforms.tangent(MathTransform, DirectPosition) method for
computing linear approximation of a MathTransform at a given location.
---
.../sis/referencing/operation/matrix/Matrices.java | 1 +
.../referencing/operation/matrix/MatrixSIS.java | 6 +--
.../operation/transform/MathTransforms.java | 52 ++++++++++++++++++++--
.../operation/transform/package-info.java | 2 +-
.../org/apache/sis/geometry/EnvelopesTest.java | 2 +-
.../operation/transform/MathTransformWrapper.java | 14 +++---
.../operation/transform/MathTransformsTest.java | 34 +++++++++++++-
7 files changed, 96 insertions(+), 15 deletions(-)
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
index f6c6208..85bb19f 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
@@ -727,6 +727,7 @@ public final class Matrices extends Static {
* the number of {@code derivative} rows is not equal to the
number of {@code translation} dimensions.
*
* @see MathTransforms#derivativeAndTransform(MathTransform, double[],
int, double[], int)
+ * @see MathTransforms#tangent(MathTransform, DirectPosition)
*
* @since 1.1
*/
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
index ccaf964..a39ca3c 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
@@ -454,7 +454,7 @@ public abstract class MatrixSIS implements Matrix,
LenientComparable, Cloneable,
*
* <h4>Equivalence between this method and Java2D {@code AffineTransform}
methods</h4>
* If this matrix was an instance of Java2D {@link AffineTransform}, then
invoking this method would
- * be equivalent to invoke the following {@code AffineTransform} methods
in the order shown below:
+ * be equivalent to invoking the following {@code AffineTransform} methods
in the order shown below:
*
* <table class="sis">
* <caption>Equivalence between this method and AffineTransform
methods</caption>
@@ -462,11 +462,11 @@ public abstract class MatrixSIS implements Matrix,
LenientComparable, Cloneable,
* <th>{@code MatrixSIS} method</th>
* <th class="sep">{@code AffineTransform} methods</th>
* </tr><tr>
- * <td>{@code concatenate(0, scale, offset)}</td>
+ * <td>{@code convertBefore(0, scale, offset)}</td>
* <td class="sep"><code>at.{@linkplain
AffineTransform#translate(double, double) translate}(offset, 0);
* at.{@linkplain AffineTransform#scale(double, double) scale}(scale,
1);</code></td>
* </tr><tr>
- * <td class="hsep">{@code concatenate(1, scale, offset)}</td>
+ * <td class="hsep">{@code convertBefore(1, scale, offset)}</td>
* <td class="hsep sep"><code>at.{@linkplain
AffineTransform#translate(double, double) translate}(0, offset);
* at.{@linkplain AffineTransform#scale(double, double) scale}(1,
scale);</code></td>
* </tr>
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
index 9e7287c..eb81518 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
@@ -56,7 +56,7 @@ import org.apache.sis.util.Static;
* GeoAPI factory interfaces instead.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
*
* @see MathTransformFactory
*
@@ -669,9 +669,11 @@ public final class MathTransforms extends Static {
* @param dstPts the array into which the transformed coordinate is
returned.
* @param dstOff the offset to the location of the transformed point
that is stored in the destination array.
* @return the matrix of the transform derivative at the given source
position.
- * @throws TransformException if the point can't be transformed or if a
problem occurred
- * while calculating the derivative.
+ * @throws TransformException if the point can not be transformed
+ * or if a problem occurred while calculating the derivative.
*
+ * @see #tangent(MathTransform, DirectPosition)
+ * @see MathTransform#derivative(DirectPosition)
* @see Matrices#createAffine(Matrix, DirectPosition)
*/
public static Matrix derivativeAndTransform(final MathTransform transform,
@@ -690,4 +692,48 @@ public final class MathTransforms extends Static {
}
return derivative;
}
+
+ /**
+ * Computes a linear approximation of the given math transform at the
given position.
+ * If the given transform is already an instance of {@link
LinearTransform}, then it is returned as-is.
+ * Otherwise an affine transform is created from the {@linkplain
MathTransform#derivative(DirectPosition)
+ * transform derivative} and the tangent point coordinates. The returned
transform has the same number of
+ * source and target dimensions than the given transform.
+ *
+ * <p>If the given transform is a one dimensional curve, then this method
computes the tangent at the given
+ * position. The same computation is generalized to any number of
dimensions (computes a tangent plane if the
+ * given transform is two-dimensional, <i>etc.</i>).</p>
+ *
+ * @param toApproximate the non-linear transform to approximate by a
linear transform.
+ * @param tangentPoint the point where to compute a linear
approximation.
+ * @return linear approximation of the given math transform at the given
position.
+ * @throws TransformException if the point can not be transformed
+ * or if a problem occurred while calculating the derivative.
+ *
+ * @since 1.1
+ */
+ public static LinearTransform tangent(final MathTransform toApproximate,
final DirectPosition tangentPoint)
+ throws TransformException
+ {
+ if (toApproximate instanceof LinearTransform) {
+ return (LinearTransform) toApproximate;
+ }
+ ArgumentChecks.ensureNonNull("toApproximate", toApproximate);
+ final int srcDim = toApproximate.getSourceDimensions();
+ ArgumentChecks.ensureDimensionMatches("tangentPoint", srcDim,
tangentPoint);
+ final int tgtDim = toApproximate.getTargetDimensions();
+ final double[] coordinates = new double[Math.max(srcDim, tgtDim)];
+ for (int i=0; i<srcDim; i++) {
+ coordinates[i] = tangentPoint.getOrdinate(i);
+ }
+ final Matrix derivative = derivativeAndTransform(toApproximate,
coordinates, 0, coordinates, 0);
+ final MatrixSIS m = Matrices.createAffine(derivative, new
DirectPositionView.Double(coordinates, 0, tgtDim));
+ for (int i=0; i<srcDim; i++) {
+ m.convertBefore(i, null, -tangentPoint.getOrdinate(i));
+ }
+ final LinearTransform tangent = linear(m);
+ assert tangent.getSourceDimensions() == srcDim;
+ assert tangent.getTargetDimensions() == tgtDim;
+ return tangent;
+ }
}
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java
index 72a4164..db70c02 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java
@@ -61,7 +61,7 @@
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Adrian Custer (Geomatys)
- * @version 1.0
+ * @version 1.1
* @since 0.5
* @module
*/
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
index e0bf6b5..097192f 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
@@ -70,7 +70,7 @@ public final strictfp class EnvelopesTest extends
TransformTestCase<GeneralEnvel
* This transformation can not handle poles.
*
* <p>This method wraps the math transform into an opaque object for
hiding the fact that the given
- * transform implement the {@link MathTransform2D} interface. The intent
is to disable optimization
+ * transform implements the {@link MathTransform2D} interface. The intent
is to disable optimization
* paths (if any), in order to test the generic path.</p>
*/
@Override
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java
index 83b31fc..e113a99 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformWrapper.java
@@ -20,6 +20,7 @@ import java.util.Objects;
import java.io.Serializable;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.NoninvertibleTransformException;
import org.opengis.referencing.operation.TransformException;
import org.opengis.geometry.MismatchedDimensionException;
@@ -31,16 +32,17 @@ import org.apache.sis.io.wkt.UnformattableObjectException;
/**
- * The base class of math transform wrappers. Despite being a concrete class,
there is no point
- * to instantiate directly this base class. Instantiate one of the subclasses
instead.
+ * The base class of math transform wrappers. This can be used as an opaque
object for hiding the fact
+ * that a given transform implements the {@link MathTransform2D} or {@link
LinearTransform} interface,
+ * in order to disable optimization paths in some tests.
*
- * <strong>Do not implement {@code MathTransform2D} in this base
class</strong>.
+ * <strong>Do not implement {@link MathTransform2D} in this base
class</strong>.
* This wrapper is sometime used for hiding the fact that a transform
implements
* the {@code MathTransform2D} interface, typically for testing a different
code
* path in a JUnit test.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.1
* @since 0.8
* @module
*/
@@ -70,7 +72,7 @@ public strictfp class MathTransformWrapper extends
FormattableObject implements
*/
@Override
public final int getSourceDimensions() {
- return transform.getTargetDimensions();
+ return transform.getSourceDimensions();
}
/**
@@ -78,7 +80,7 @@ public strictfp class MathTransformWrapper extends
FormattableObject implements
*/
@Override
public final int getTargetDimensions() {
- return transform.getSourceDimensions();
+ return transform.getTargetDimensions();
}
/**
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java
index c8dce85..11c199b 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java
@@ -29,6 +29,7 @@ import org.apache.sis.referencing.operation.matrix.Matrix3;
import org.apache.sis.referencing.operation.matrix.Matrix4;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -39,10 +40,11 @@ import static org.opengis.test.Assert.*;
* Tests {@link MathTransforms}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
* @since 0.5
* @module
*/
+@DependsOn(org.apache.sis.referencing.operation.matrix.MatricesTest.class)
public final strictfp class MathTransformsTest extends TestCase {
/**
* Creates a dummy transform for testing purpose.
@@ -212,4 +214,34 @@ public final strictfp class MathTransformsTest extends
TestCase {
assertInstanceOf("2D", MathTransform2D.class, tr);
assertFalse("isIdentity", tr.isIdentity());
}
+
+ /**
+ * Tests {@link MathTransforms#tangent(MathTransform, DirectPosition)}.
+ *
+ * @throws TransformException should never happen since this test uses a
linear transform.
+ */
+ @Test
+ public void testTangent() throws TransformException {
+ /*
+ * The random values in Matrix and DirectPosition below does not
matter; we will just verify
+ * that we get the same values in final result. In particular the
`tangentPoint` coordinates
+ * are ignored since we use a linear transform for this test.
+ */
+ final Matrix expected = Matrices.create(3, 4, new double[] {
+ -4, 5, 7, 2,
+ 3, 4, 2, 9,
+ 0, 0, 0, 1,
+ });
+ final DirectPosition tangentPoint = new GeneralDirectPosition(3, 8, 7);
+ MathTransform transform = MathTransforms.linear(expected);
+ assertSame(transform, MathTransforms.tangent(transform, tangentPoint));
+ /*
+ * Above test returned the transform directly because it found that it
was already an instance
+ * of `LinearTransform`. For a real test, we need to hide that fact to
the `tangent` method.
+ */
+ transform = new MathTransformWrapper(transform);
+ final LinearTransform result = MathTransforms.tangent(transform,
tangentPoint);
+ assertNotSame(transform, result);
+ assertMatrixEquals("tangent", expected, result.getMatrix(), STRICT);
+ }
}