sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Add a MathTransforms.tangent(MathTransform, DirectPosition) method for computing linear approximation of a MathTransform at a given location.
Date Sat, 08 Feb 2020 12:01:44 GMT
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 <martin.desruisseaux@geomatys.com>
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);
+    }
 }


Mime
View raw message