You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2019/03/11 19:30:11 UTC

[sis] branch geoapi-4.0 updated: The non-linear transform concatenated by LocalizationGridBuilder needs to take in account axis swapping.

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 aca9be6  The non-linear transform concatenated by LocalizationGridBuilder needs to take in account axis swapping.
aca9be6 is described below

commit aca9be685b338e5dc9e1d4cb065074e78ee75780
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Mon Mar 11 20:29:42 2019 +0100

    The non-linear transform concatenated by LocalizationGridBuilder needs to take in account axis swapping.
---
 .../operation/builder/LinearTransformBuilder.java  | 16 ++++++-------
 .../operation/builder/LocalizationGridBuilder.java | 18 ++++++++++++--
 .../operation/builder/ProjectedTransformTry.java   | 28 ++++++++++++++++------
 .../builder/LinearTransformBuilderTest.java        | 10 ++++----
 4 files changed, 50 insertions(+), 22 deletions(-)

diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
index c1492e2..df447ae 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
@@ -1121,8 +1121,9 @@ search:         for (int j=domain(); --j >= 0;) {
      * {@linkplain #correlation() correlation} coefficients. It may be none.
      *
      * <p>The linearizers are specified as {@link MathTransform}s from current target coordinates to other spaces
-     * where <cite>sources to new targets</cite> transforms may be more linear. The keys in the map are arbitrary
-     * identifiers used in {@link #toString()} for debugging purpose.
+     * where <cite>sources to new targets</cite> transforms may be more linear.
+     * Keys in the map are arbitrary identifiers used in {@link #toString()} for debugging purpose.
+     * Values in the map are non-{@link LinearTransform} (linear transforms are not forbidden, but are useless for this process).
      * The {@code dimensions} argument specifies which target dimensions to project and can be null or omitted
      * if the projections shall be applied on all target coordinates. It is possible to invoke this method many
      * times with different {@code dimensions} argument values.</p>
@@ -1148,10 +1149,7 @@ search:         for (int j=domain(); --j >= 0;) {
             linearizers = new ArrayList<>();
         }
         for (final Map.Entry<String,MathTransform> entry : projections.entrySet()) {
-            ProjectedTransformTry t = new ProjectedTransformTry(entry.getKey(), entry.getValue(), dimensions, tgtDim);
-            if (!t.projection.isIdentity()) {
-                linearizers.add(t);
-            }
+            linearizers.add(new ProjectedTransformTry(entry.getKey(), entry.getValue(), dimensions, tgtDim));
         }
     }
 
@@ -1328,7 +1326,7 @@ search:         for (int j=domain(); --j >= 0;) {
     }
 
     /**
-     * If all target coordinates have been projected to another space, returns the projection applied.
+     * If target coordinates have been projected to another space, returns that projection.
      * This method returns a non-empty value only if all the following conditions are met:
      *
      * <ol>
@@ -1340,13 +1338,15 @@ search:         for (int j=domain(); --j >= 0;) {
      *
      * If this method returns a non-empty value, then the envelope returned by {@link #getTargetEnvelope()}
      * and all control points returned by {@link #getControlPoint(int[])} are projected by this transform.
+     * The returned transform includes axes swapping specified by the {@code dimensions} argument given to
+     * <code>{@linkplain #addLinearizers(Map, int...) addLinearizers}(…, dimensions)</code>.
      *
      * @return the projection applied on target coordinates before to compute a linear transform.
      *
      * @since 1.0
      */
     public Optional<MathTransform> linearizer() {
-        return (appliedLinearizer != null) ? Optional.of(appliedLinearizer.projection) : Optional.empty();
+        return (appliedLinearizer != null) ? Optional.of(appliedLinearizer.projection()) : Optional.empty();
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
index 6a919d0..86a9304 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
@@ -664,7 +664,21 @@ public class LocalizationGridBuilder extends TransformBuilder {
     /**
      * Returns statistics of differences between values calculated by the given transform and actual values.
      * The given math transform is typically the transform computed by {@link #create(MathTransformFactory)},
-     * but not necessarily.
+     * but not necessarily. The returned statistics are:
+     *
+     * <ol class="verbose">
+     *   <li>One {@code Statistics} instance for each target dimension, containing statistics about the differences between
+     *     coordinates computed by the given transform and expected coordinates. For each (<var>i</var>,<var>j</var>) indices
+     *     in this grid, the indices are transformed by a call to {@code mt.transform(…)} and the result is compared with the
+     *     coordinates given by <code>{@linkplain #getControlPoint(int, int) getControlPoint}(i,j)</code>.
+     *     Those statistics are identified by labels like “P → x” and “P → y” where <var>P</var> stands for pixel coordinates.</li>
+     *   <li>One {@code Statistics} instance for each source dimension, containing statistics about the differences between
+     *     coordinates computed by the <em>inverse</em> of the transform and expected coordinates.
+     *     For each (<var>x</var>,<var>y</var>) control point in this grid, the points are transformed by a call
+     *     to {@code mt.inverse().transform(…)} and the result is compared with the pixel indices of that point.
+     *     Those statistics are identified by labels like “i ← P′” and “j ← P′” where <var>P′</var> stands for
+     *     the control point.</li>
+     * </ol>
      *
      * @param  mt  the transform to test.
      * @return statistics of difference between computed values and expected values for each target dimension.
@@ -741,7 +755,7 @@ public class LocalizationGridBuilder extends TransformBuilder {
      *   <li>Number of points.</li>
      *   <li>Linearizers and their correlation coefficients (if available).</li>
      *   <li>The linear component of the transform.</li>
-     *   <li>Error statistics.</li>
+     *   <li>Error statistics, as documented in the {@link #error(MathTransform)} method.</li>
      * </ul>
      *
      * The string representation may change in any future version.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java
index 92f01ba..4be4ecd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java
@@ -28,7 +28,10 @@ import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.io.TableAppender;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Exceptions;
+import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
 
 
 /**
@@ -66,15 +69,17 @@ final class ProjectedTransformTry implements Comparable<ProjectedTransformTry> {
     private static final int BUFFER_CAPACITY = 512;
 
     /**
-     * A name by witch this projection attempt is identified.
+     * A name by witch this projection attempt is identified, or {@code null} for the identity transform.
      */
     private String name;
 
     /**
      * A conversion from a non-linear grid (typically with longitude and latitude values) to
      * something that may be more linear (typically, but not necessarily, a map projection).
+     *
+     * @see #projection()
      */
-    final MathTransform projection;
+    private final MathTransform projection;
 
     /**
      * Maps {@link #projection} dimensions to {@link LinearTransformBuilder} target dimensions.
@@ -123,6 +128,8 @@ final class ProjectedTransformTry implements Comparable<ProjectedTransformTry> {
      * @param expectedDimension  number of {@link LinearTransformBuilder} target dimensions.
      */
     ProjectedTransformTry(final String name, final MathTransform projection, final int[] dimensions, int expectedDimension) {
+        ArgumentChecks.ensureNonNull("name", name);
+        ArgumentChecks.ensureNonNull("projection", projection);
         this.name       = name;
         this.projection = projection;
         this.dimensions = dimensions;
@@ -143,14 +150,22 @@ final class ProjectedTransformTry implements Comparable<ProjectedTransformTry> {
     }
 
     /**
-     * Returns the name of this object, or {@code null} if unspecified.
-     * This is used only for formatting error messages.
+     * Returns the name of this object, or {@code null} if this is the identity transform created by
+     * {@link #ProjectedTransformTry(float)}. Should never be {@code null} for name returned to user.
      */
     final String name() {
         return name;
     }
 
     /**
+     * Returns the projection, taking in account axis swapping if {@link #dimensions} is not an arithmetic progression.
+     */
+    final MathTransform projection() {
+        MathTransform mt = MathTransforms.linear(Matrices.createDimensionSelect(dimensions.length, dimensions));
+        return MathTransforms.concatenate(mt, projection);
+    }
+
+    /**
      * Transforms target coordinates of a localization grid. The {@code coordinates} argument is the value
      * of {@link LinearTransformBuilder#targets}, without clone (this method will only read those arrays).
      * Only arrays at indices given by {@link #dimensions} will be read; the other arrays will be ignored.
@@ -306,13 +321,12 @@ final class ProjectedTransformTry implements Comparable<ProjectedTransformTry> {
      *
      * @param  table   the table where to write a row.
      * @param  nf      format to use for writing coefficients, or {@code null} if not yet created.
-     * @param  locale  the locale to use if a number format must be created.
+     * @param  locale  the locale to use for messages or if a number format must be created.
      * @return format used for writing coefficients, or {@code null}.
      */
     final NumberFormat summarize(final TableAppender table, NumberFormat nf, final Locale locale) {
         if (name == null) {
-            final short key = (projection == null) ? Vocabulary.Keys.Identity : Vocabulary.Keys.Unnamed;
-            name = Vocabulary.getResources(locale).getString(key);
+            name = Vocabulary.getResources(locale).getString(Vocabulary.Keys.Identity);
         }
         table.append(name).nextColumn();
         String message = "";
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
index 582eaa1..868ce37 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
@@ -430,12 +430,12 @@ public final strictfp class LinearTransformBuilderTest extends TestCase {
                 builder.setControlPoint(source, target);
             }
         }
-        final NonLinearTransform x2y3 = new NonLinearTransform();
-        final NonLinearTransform x3y2 = new NonLinearTransform();
-        builder.addLinearizers(Collections.singletonMap("x² y³", x2y3));
-        builder.addLinearizers(Collections.singletonMap("x³ y²", x3y2), 1, 0);
+        final NonLinearTransform tr = new NonLinearTransform();
+        builder.addLinearizers(Collections.singletonMap("x² y³", tr));
+        builder.addLinearizers(Collections.singletonMap("x³ y²", tr), 1, 0);
         final Matrix m = builder.create(null).getMatrix();
-        assertSame("linearizer", x3y2, builder.linearizer().get());
+        assertEquals("linearizer", "x³ y²", builder.linearizerID());
+        assertNotSame("linearizer", tr, builder.linearizer().get());    // Not same because axes should have been swapped.
         assertMatrixEquals("linear",
                 new Matrix3(2, 0, 3,
                             0, 1, 1,