sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1787666 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/referencing/operation/builder/ main/java/org/apache/sis/referencing/operation/matrix/ test/java/org/apache/sis/referencing/operation/builder/ test/java/org/...
Date Sun, 19 Mar 2017 22:18:23 GMT
Author: desruisseaux
Date: Sun Mar 19 22:18:23 2017
New Revision: 1787666

URL: http://svn.apache.org/viewvc?rev=1787666&view=rev
Log:
Fix the calculation done by LocalizationGridBuilder when computing the residuals to give to
InterpolatedTransform constructor.

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ResidualGrid.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilderTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -543,7 +543,8 @@ search: for (int j=0; j<numPoints; j++)
     final void getControlPoint2D(final int[] source, final double[] target) {
         assert gridSize != null;
         final int index = flatIndex(source);
-        for (int i=0; i<target.length; i++) {
+        final int tgtDim = targets.length;
+        for (int i=0; i<tgtDim; i++) {
             target[i] = targets[i][index];
         }
     }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -17,7 +17,6 @@
 package org.apache.sis.referencing.operation.builder;
 
 import org.opengis.util.FactoryException;
-import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
@@ -25,9 +24,12 @@ import org.opengis.referencing.operation
 import org.apache.sis.referencing.operation.transform.InterpolatedTransform;
 import org.apache.sis.referencing.operation.transform.LinearTransform;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.datum.DatumShiftGrid;
+import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.geometry.DirectPosition2D;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.math.MathFunctions;
 
 
 /**
@@ -76,18 +78,49 @@ public class LocalizationGridBuilder ext
     private LinearTransform sourceToGrid;
 
     /**
+     * The desired precision of inverse transformations in unit of source coordinates, or
0 in unspecified.
+     * If no {@link #sourceToGrid} transform has been specified, than this is in unit of
grid cell.
+     */
+    private double precision;
+
+    /**
+     * Arbitrary default {@link #precision} value. May change in any future SIS version.
+     */
+    static final double DEFAULT_PRECISION = 1E-7;
+
+    /**
      * Creates a new, initially empty, builder.
      *
      * @param width   the number of columns in the grid of target positions.
      * @param height  the number of rows in the grid of target positions.
      */
     public LocalizationGridBuilder(final int width, final int height) {
-        linear = new LinearTransformBuilder(width, height);
-        tmp    = new int[2];
+        linear       = new LinearTransformBuilder(width, height);
+        tmp          = new int[2];
         sourceToGrid = MathTransforms.identity(2);
     }
 
     /**
+     * Sets the desired precision of <em>inverse</em> transformations, in units
of source coordinates.
+     * If a conversion from "real world" to grid coordinates {@linkplain #setSourceToGrid
has been specified},
+     * then the given precision is in "real world" units. Otherwise the precision is in units
of grid cells.
+     *
+     * <div class="note"><b>Note:</b>
+     * there is no method for setting the desired target precision because forward transformations
<em>precision</em>
+     * (not to be confused with <em>accuracy</em>) are limited only by rounding
errors. Of course the accuracy of both
+     * forward and inverse transformations still limited by the accuracy of given control
points and the grid resolution.
+     * </div>
+     *
+     * @param precision  desired precision of the results of inverse transformations.
+     *
+     * @see DatumShiftGrid#getCellPrecision()
+     */
+    public void setDesiredPrecision(final double precision) {
+        ArgumentChecks.ensureStrictlyPositive("precision", precision);
+        this.precision = precision;
+    }
+
+    /**
      * Defines relationship between "real-world" source coordinates and grid coordinates.
      * The given transform is usually two-dimensional, in which case conversions from (<var>x</var>,<var>y</var>)
      * source coordinates to ({@code gridX}, {@code gridY}) indices can be done with the
following formulas:
@@ -114,6 +147,8 @@ public class LocalizationGridBuilder ext
      * }
      *
      * If this method is never invoked, then the default conversion is identity.
+     * If a {@linkplain #setDesiredPrecision(double) desired precision} has been specified
before this method call,
+     * it is caller's responsibility to convert that value to new source units if needed.
      *
      * @param sourceToGrid  conversion from the "real world" source coordinates to grid indices
including fractional parts.
      *
@@ -121,7 +156,18 @@ public class LocalizationGridBuilder ext
      */
     public void setSourceToGrid(final LinearTransform sourceToGrid) {
         ArgumentChecks.ensureNonNull("sourceToGrid", sourceToGrid);
-        this.sourceToGrid = sourceToGrid;
+        int isTarget = 0;
+        int dim = sourceToGrid.getSourceDimensions();
+        if (dim >= 2) {
+            isTarget = 1;
+            dim = sourceToGrid.getTargetDimensions();
+            if (dim == 2) {
+                this.sourceToGrid = sourceToGrid;
+                return;
+            }
+        }
+        throw new MismatchedDimensionException(Resources.format(
+                Resources.Keys.MismatchedTransformDimension_3, isTarget, 2, dim));
     }
 
     /**
@@ -155,19 +201,6 @@ public class LocalizationGridBuilder ext
     }
 
     /**
-     * Returns whether the result of last call to {@link LinearTransformBuilder#create()}
can be considered
-     * a good fit. If {@code true}, then {@link #create()} will return the linear transform
directly.
-     */
-    private boolean isLinear() {
-        for (final double c : linear.correlation()) {
-            if (c < 0.99) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
      * Creates a transform from the source points to the target points.
      * This method assumes that source points are precise and all uncertainty is in the target
points.
      * If this transform is close enough to an affine transform, then an instance of {@link
LinearTransform} is returned.
@@ -182,45 +215,75 @@ public class LocalizationGridBuilder ext
     @Override
     public MathTransform create(final MathTransformFactory factory) throws FactoryException
{
         final LinearTransform gridToCoord = linear.create(factory);
-        if (isLinear()) {
+        /*
+         * Make a first check about whether the result of above LinearTransformBuilder.create()
call
+         * can be considered a good fit. If true, then we may return the linear transform
directly.
+         */
+        boolean isExact  = true;
+        boolean isLinear = true;
+        for (final double c : linear.correlation()) {
+            isExact &= (c == 1);
+            if (c < 0.9999) {                               // Empirical threshold (may
need to be revisited).
+                isLinear = false;
+                break;
+            }
+        }
+        if (isExact) {
             return gridToCoord;
         }
-        final int      width  = linear.gridSize(0);
-        final int      height = linear.gridSize(1);
-        final int      tgtDim = gridToCoord.getTargetDimensions();
-        final double[] data   = new double[tgtDim * linear.gridLength];
-        final double[] point  = new double[tgtDim];
+        final int      width    = linear.gridSize(0);
+        final int      height   = linear.gridSize(1);
+        final int      tgtDim   = gridToCoord.getTargetDimensions();
+        final double[] residual = new double[tgtDim * linear.gridLength];
+        final double[] point    = new double[tgtDim + 1];
+        double gridPrecision    = precision;
         try {
+            /*
+             * If the user specified a precision, we need to convert it from source units
to grid units.
+             * We convert each dimension separately, then retain the largest magnitude of
vector results.
+             */
+            if (gridPrecision > 0 && !sourceToGrid.isIdentity()) {
+                final double[] vector = new double[sourceToGrid.getSourceDimensions()];
+                final double[] offset = new double[sourceToGrid.getTargetDimensions()];
+                double converted = 0;
+                for (int i=0; i<vector.length; i++) {
+                    vector[i] = precision;
+                    sourceToGrid.deltaTransform(vector, 0, offset, 0, 1);
+                    final double length = MathFunctions.magnitude(offset);
+                    if (length > converted) converted = length;
+                    vector[i] = 0;
+                }
+                gridPrecision = converted;
+            }
+            /*
+             * Compute the residuals, i.e. the differences between the coordinates that we
get by a linear
+             * transformation and the coordinates that we want to get. If at least one residual
is greater
+             * than the desired precision,  then the returned MathTransform will need to
apply corrections
+             * after linear transforms. Those corrections will be done by InterpolatedTransform.
+             */
+            final MatrixSIS coordToGrid = MatrixSIS.castOrCopy(gridToCoord.inverse().getMatrix());
             final DirectPosition2D src = new DirectPosition2D();
-            DirectPosition tgt = null;
+            point[tgtDim] = 1;
             for (int k=0,y=0; y<height; y++) {
                 src.y  = y;
                 tmp[1] = y;
                 for (int x=0; x<width; x++) {
                     src.x  = x;
                     tmp[0] = x;
-                    linear.getControlPoint2D(tmp, point);               // Expected position.
-                    tgt = gridToCoord.transform(src, tgt);              // Interpolated position.
-                    for (int i=0; i<tgtDim; i++) {
-                        data[k++] = point[i] - tgt.getOrdinate(i);      // Residual.
-                    }
+                    linear.getControlPoint2D(tmp, point);                           // Expected
position.
+                    double[] grid = coordToGrid.multiply(point);                    // As
grid coordinate.
+                    isLinear &= (residual[k++] = grid[0] - x) <= gridPrecision;
+                    isLinear &= (residual[k++] = grid[1] - y) <= gridPrecision;
                 }
             }
-            /*
-             * At this point, we computed the residual of all coordinate values.
-             * Now we need to express those residuals in grid units instead than
-             * "real world" unit, because InterpolatedTransform works that way.
-             */
-            final LinearTransform coordToGrid = gridToCoord.inverse();
-            if (tgtDim == 2) {
-                coordToGrid.deltaTransform(data, 0, data, 0, linear.gridLength);
-            } else {
-                throw new UnsupportedOperationException();          // TODO: use a fallback.
-            }
         } catch (TransformException e) {
-            throw new FactoryException(e);                          // Should never happen.
+            throw new FactoryException(e);                                          // Should
never happen.
+        }
+        if (isLinear) {
+            return gridToCoord;
         }
         return InterpolatedTransform.createGeodeticTransformation(nonNull(factory),
-                new ResidualGrid(sourceToGrid, gridToCoord, width, height, tgtDim, data));
+                new ResidualGrid(sourceToGrid, gridToCoord, width, height, tgtDim, residual,
+                (gridPrecision > 0) ? gridPrecision : DEFAULT_PRECISION));
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ResidualGrid.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ResidualGrid.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ResidualGrid.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ResidualGrid.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -35,6 +35,11 @@ import org.opengis.referencing.operation
  */
 final class ResidualGrid extends DatumShiftGridFile<Dimensionless,Dimensionless> {
     /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -6661539177698674636L;
+
+    /**
      * The parameter descriptors for the "Localization grid" operation.
      */
     private static final ParameterDescriptorGroup PARAMETERS;
@@ -70,13 +75,13 @@ final class ResidualGrid extends DatumSh
      * @param residuals     the residual data, as translations to apply on the result of
affine transform.
      */
     ResidualGrid(final LinearTransform sourceToGrid, final LinearTransform gridToTarget,
-            final int nx, final int ny, final int numDim, final double[] residuals)
+            final int nx, final int ny, final int numDim, final double[] residuals, final
double precision)
     {
         super(Units.UNITY, Units.UNITY, true, sourceToGrid, nx, ny, PARAMETERS);
         this.gridToTarget = gridToTarget;
         this.numDim       = numDim;
         this.offsets      = residuals;
-        this.accuracy     = 0.01;           // TODO
+        this.accuracy     = precision;
     }
 
     /**
@@ -125,6 +130,15 @@ final class ResidualGrid extends DatumSh
     }
 
     /**
+     * Returns the desired precision in iterative calculation performed by inverse transform.
+     * The returned value is in unit of grid cell.
+     */
+    @Override
+    public double getCellPrecision() {
+        return accuracy;
+    }
+
+    /**
      * Returns the cell value at the given dimension and grid index.
      */
     @Override

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -56,7 +56,7 @@ import org.apache.sis.util.resources.Err
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.7
+ * @version 0.8
  * @module
  *
  * @see Matrices
@@ -556,6 +556,46 @@ public abstract class MatrixSIS implemen
     }
 
     /**
+     * Returns a new vector which is the result of multiplying this matrix with the specified
vector.
+     * In other words, returns {@code this} × {@code vector}. The length of the given vector
must be
+     * equal to the number of columns in this matrix, and the length of the returned vector
will be
+     * equal to the number of rows in this matrix.
+     *
+     * <div class="section">Relationship with coordinate operations</div>
+     * In the context of coordinate operations, {@code Matrix.multiply(vector)} is related
to
+     * <code>{@linkplain AffineTransform#transform(double[], int, double[], int, int)
AffineTransform.transform}(…)</code>
+     * except that the last {@code vector} number is implicitly 1 in {@code AffineTransform}
operations.
+     * While this {@code multiply(double[])} method could be used for coordinate transformation,
it is not its purpose.
+     * This method is designed for occasional uses when accuracy is more important than performance.
+     *
+     * @param  vector  the vector to multiply to this matrix.
+     * @return the result of {@code this} × {@code vector}.
+     * @throws MismatchedMatrixSizeException if the length of the given vector is not equals
to the
+     *         number of columns in this matrix.
+     *
+     * @since 0.8
+     */
+    public double[] multiply(final double[] vector) {
+        final int numCol = getNumCol();
+        if (vector.length != numCol) {
+            throw new MismatchedMatrixSizeException(Errors.format(Errors.Keys.UnexpectedArrayLength_2,
 numCol, vector.length));
+        }
+        final double[] target = new double[getNumRow()];
+        final DoubleDouble ele = new DoubleDouble();
+        final DoubleDouble sum = new DoubleDouble();
+        for (int j=0; j<target.length; j++) {
+            for (int i=0; i<numCol; i++) {
+                get(j, i, ele);
+                ele.multiply(vector[i]);
+                sum.add(ele);
+            }
+            target[j] = sum.value;
+            sum.clear();
+        }
+        return target;
+    }
+
+    /**
      * Returns the value of <var>U</var> which solves {@code this} × <var>U</var>
= {@code matrix}.
      * This is equivalent to first computing the inverse of {@code this}, then multiplying
the result
      * by the given matrix.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -70,7 +70,7 @@
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 package org.apache.sis.referencing.operation.matrix;

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -123,8 +123,6 @@ public final strictfp class LinearTransf
      *
      * @throws FactoryException if the transform can not be created.
      *
-     * @see LocalizationGridBuilderTest#testSixPoints()
-     *
      * @since 0.8
      */
     @Test

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilderTest.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilderTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilderTest.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.referencing.operation.builder;
 
+import java.awt.geom.Point2D;
+import java.awt.geom.AffineTransform;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.test.referencing.TransformTestCase;
@@ -34,26 +36,70 @@ import org.junit.Test;
 @DependsOn(LinearTransformBuilderTest.class)
 public final strictfp class LocalizationGridBuilderTest extends TransformTestCase {
     /**
-     * Tests a small grid of 3 rows and 2 columns.
-     * This tests use the same point than {@link LinearTransformBuilderTest#testImplicitSource2D()}
+     * Creates a builder initialized with control points computed from the given affine transform.
+     * Some non-linear terms will be added to the coordinates computed by the given transform.
+     *
+     * @param  reference  the affine transform to use as a basis for generating a localization
grid.
+     * @param  width      number of columns in the localization grid to create.
+     * @param  height     number of rows in the localization grid to create.
+     * @return the builder to test.
+     */
+    @SuppressWarnings("UseOfSystemOutOrSystemErr")
+    private static LocalizationGridBuilder builder(final AffineTransform reference, final
int width, final int height) {
+        final LocalizationGridBuilder builder = new LocalizationGridBuilder(width, height);
+        Point2D pt = new Point2D.Double();
+        for (int gridY=0; gridY < height; gridY++) {
+            for (int gridX=0; gridX < width; gridX++) {
+                pt.setLocation(gridX, gridY);
+                pt = reference.transform(pt, pt);
+                final double gx2 = gridX * gridX;
+                final double gy2 = gridY * gridY;
+                final double x = pt.getX() + 0.4*gx2 + 0.7*gy2;
+                final double y = pt.getY() + 0.3*gx2 - 0.5*gy2;
+                builder.setControlPoint(gridX, gridY, x, y);
+                if (false) {
+                    // For generating verification code.
+                    System.out.printf("verifyTransform(new double[] {%d, %d}, new double[]
{%f, %f});%n", gridX, gridY, x, y);
+                }
+            }
+        }
+        return builder;
+    }
+
+    /**
+     * Tests a small grid built from an arbitrary affine transform with small quadratic terms
added to the control points.
      *
      * @throws FactoryException if an error occurred while computing the localization grid.
      * @throws TransformException if an error occurred while testing a transformation.
-     *
-     * @see LinearTransformBuilderTest#testImplicitSource2D()
      */
     @Test
-    public void testSixPoints() throws FactoryException, TransformException {
-        final LocalizationGridBuilder builder = new LocalizationGridBuilder(2, 3);
-        builder.setControlPoint(0, 0, 3, 9);
-        builder.setControlPoint(0, 1, 4, 7);
-        builder.setControlPoint(0, 2, 6, 6);
-        builder.setControlPoint(1, 0, 4, 8);
-        builder.setControlPoint(1, 1, 5, 4);
-        builder.setControlPoint(1, 2, 8, 2);
-
+    public void testQuadratic() throws FactoryException, TransformException {
+        final AffineTransform reference = new AffineTransform(20, -30, 5, -4, -20, 8);
+        final LocalizationGridBuilder builder = builder(reference, 5, 4);
         transform = builder.create(null);
-        tolerance = 1;                          // TODO: temporary high value while we debug.
-        verifyTransform(new double[] {0, 0}, new double[] {3, 9});
+
+        tolerance = 1E-13;
+        isInverseTransformSupported = false;
+        verifyQuadratic();
+        /*
+         * The tolerance value specified here should be approximatively equal to ResidualGrid.accuracy.
+         */
+        tolerance = LocalizationGridBuilder.DEFAULT_PRECISION;
+        isInverseTransformSupported = true;
+        verifyQuadratic();
+    }
+
+    /**
+     * Hard-coded verifications of some values for the transform built by {@link #testQuadratic()}.
+     * This verification is run twice: once without check for inverse transform, and a second
time
+     * with inverse transform enabled.
+     */
+    private void verifyQuadratic() throws TransformException {
+        verifyTransform(new double[] {0, 0}, new double[] {-20.0,    8.0});         // Translation
terms
+        verifyTransform(new double[] {1, 0}, new double[] {  0.4,  -21.7});         // Not
yet non-linear
+        verifyTransform(new double[] {0, 1}, new double[] {-14.3,    3.5});         // Not
yet non-linear
+        verifyTransform(new double[] {1, 1}, new double[] {  6.1,  -26.2});         // Not
yet non-linear
+        verifyTransform(new double[] {0, 3}, new double[] {  1.3,   -8.5});
+        verifyTransform(new double[] {4, 3}, new double[] { 87.7, -123.7});
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -28,7 +28,7 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 public final strictfp class GeneralMatrixTest extends MatrixTestCase {
@@ -117,4 +117,15 @@ public final strictfp class GeneralMatri
         testConvertAfter(new GeneralMatrix(3, 3, true, 1));    // Double precision
         testConvertAfter(new GeneralMatrix(3, 3, true, 2));    // Double-double precision
     }
+
+    /**
+     * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference
implementation.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testMultiplyVector() {
+        testMultiplyVector(new GeneralMatrix(3, 3, true, 1));    // Double precision
+        testMultiplyVector(new GeneralMatrix(3, 3, true, 2));    // Double-double precision
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -29,7 +29,7 @@ import static org.apache.sis.referencing
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 @DependsOn(SolverTest.class)
@@ -122,4 +122,14 @@ public final strictfp class Matrix3Test
     public void testConvertAfter() {
         testConvertAfter(new Matrix3());
     }
+
+    /**
+     * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference
implementation.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testMultiplyVector() {
+        testMultiplyVector(new Matrix3());
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java?rev=1787666&r1=1787665&r2=1787666&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
[UTF-8] Sun Mar 19 22:18:23 2017
@@ -46,7 +46,7 @@ import static org.apache.sis.test.Assert
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 public abstract strictfp class MatrixTestCase extends TestCase {
@@ -269,7 +269,7 @@ public abstract strictfp class MatrixTes
          * End of initialization - now perform the actual test.
          */
         assertEqualsJAMA(reference, matrix, STRICT);
-        for (int k=0; k<50; k++) {
+        for (int k=0; k<NUMBER_OF_REPETITIONS; k++) {
             final int    j = random.nextInt(numRow);
             final int    i = random.nextInt(numCol);
             final double e = random.nextDouble() * 100;
@@ -410,7 +410,7 @@ public abstract strictfp class MatrixTes
             matrix.setElement(0, 1, at.getShearX());
             matrix.setElement(1, 0, at.getShearY());
         }
-        for (int i=0; i<100; i++) {
+        for (int i=0; i<NUMBER_OF_REPETITIONS; i++) {
             /*
              * 1) For the first  30 iterations, test the result of applying only a scale.
              * 2) For the next   30 iterations, test the result of applying only a translation.
@@ -476,7 +476,7 @@ public abstract strictfp class MatrixTes
         final AffineTransform at = AffineTransform.getShearInstance(nextNonZeroRandom(),
nextNonZeroRandom());
         matrix.setElement(0, 1, at.getShearX());
         matrix.setElement(1, 0, at.getShearY());
-        for (int i=0; i<30; i++) {
+        for (int i=0; i<NUMBER_OF_REPETITIONS; i++) {
             final Number scale  = nextNonZeroRandom();
             final Number offset = nextNonZeroRandom();
             final int tgtDim = (i & 1);
@@ -496,6 +496,41 @@ public abstract strictfp class MatrixTes
         }
     }
 
+    /**
+     * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference
implementation.
+     * This test can be run only with matrices of size 3×3. Consequently it is sub-classes
responsibility to
+     * add a {@code testMultiplyVector()} method which invoke this method.
+     *
+     * @param  matrix  the matrix of size 3×3 to test.
+     *
+     * @since 0.8
+     */
+    final void testMultiplyVector(final MatrixSIS matrix) {
+        initialize(8433903323905121506L);
+        final AffineTransform at = new AffineTransform();
+        final double vector[] = new double[3];
+        for (int n=0; n<NUMBER_OF_REPETITIONS; n++) {
+            if ((n % 10) == 0) {
+                at.setToRotation(random.nextDouble() * StrictMath.PI);
+                at.scale(nextNonZeroRandom(), nextNonZeroRandom());
+                at.translate(random.nextDouble() * 100 - 50,
+                             random.nextDouble() * 100 - 50);
+                matrix.setElements(new double[] {
+                    at.getScaleX(), at.getShearX(), at.getTranslateX(),
+                    at.getShearY(), at.getScaleY(), at.getTranslateY(),
+                                 0,              0,                  1
+                });
+            }
+            vector[0] = random.nextDouble() * 50 - 25;
+            vector[1] = random.nextDouble() * 50 - 25;
+            vector[2] = 1;
+            final double[] result = matrix.multiply(vector);        // The result to verify.
+            at.transform(vector, 0, vector, 0, 1);                  // The expected result.
+            assertEquals("x", vector[0], result[0], TOLERANCE);
+            assertEquals("y", vector[1], result[1], TOLERANCE);
+        }
+    }
+
     /**
      * Tests {@link MatrixSIS#multiply(Matrix)}.
      */



Mime
View raw message