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 8b2e294570 When concatenating a change of coordinate system type together with an uniform scale factor, move the scale factor from the Cartesian CS side to the spherical, cylindrical or polar CS side. The rational is that the latter will need an affine transform anyway for the conversion between radians and degrees. 8b2e294570 is described below commit 8b2e29457057f3385a875d3f2d22e7fe80deec87 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu Jan 18 13:17:26 2024 +0100 When concatenating a change of coordinate system type together with an uniform scale factor, move the scale factor from the Cartesian CS side to the spherical, cylindrical or polar CS side. The rational is that the latter will need an affine transform anyway for the conversion between radians and degrees. --- .../referencing/operation/matrix/MatrixSIS.java | 2 + .../operation/transform/AbstractMathTransform.java | 4 +- .../operation/transform/CartesianToPolar.java | 2 +- .../operation/transform/CartesianToSpherical.java | 2 +- .../transform/CoordinateSystemTransform.java | 100 ++++++++++++++++++--- .../operation/transform/PolarToCartesian.java | 2 +- .../operation/transform/SphericalToCartesian.java | 2 +- .../referencing/util/ExtendedPrecisionMatrix.java | 27 ++++++ .../operation/transform/CartesianToPolarTest.java | 12 +-- .../transform/CartesianToSphericalTest.java | 49 +++++++--- .../operation/transform/PolarToCartesianTest.java | 20 ++--- .../transform/SphericalToCartesianTest.java | 64 ++++++++++--- 12 files changed, 225 insertions(+), 61 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/MatrixSIS.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/MatrixSIS.java index 5f1eeb26cc..abd0e85050 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/MatrixSIS.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/MatrixSIS.java @@ -145,6 +145,8 @@ public abstract class MatrixSIS implements Matrix, LenientComparable, Cloneable, /** * Returns the given matrix as an extended precision matrix. + * + * @see ExtendedPrecisionMatrix#castOrWrap(Matrix) */ static ExtendedPrecisionMatrix asExtendedPrecision(final Matrix matrix) { if (matrix instanceof UnmodifiableMatrix) { diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java index a01eeb41d1..fa70064ec1 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java @@ -889,8 +889,8 @@ public abstract class AbstractMathTransform extends FormattableObject * <p>The default implementation returns the identity transform if the other transform is the inverse * of this transform, or returns {@code null} otherwise. This method is ought to be overridden * by subclasses capable of concatenating some combination of transforms in a special way. - * {@link LinearTransform} implementations do not need to override this method since matrix multiplications - * will be handled automatically, and this method does not need to handle the {@link #isIdentity()} case.</p> + * {@link LinearTransform} implementations do not need to override this method because matrix multiplications + * will be handled automatically. This method does not need to handle the {@link #isIdentity()} case neither.</p> * * @param applyOtherFirst {@code true} if the transformation order is {@code other} followed by {@code this}, or * {@code false} if the transformation order is {@code this} followed by {@code other}. diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToPolar.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToPolar.java index 103506b116..22b40110d4 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToPolar.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToPolar.java @@ -65,7 +65,7 @@ final class CartesianToPolar extends CoordinateSystemTransform implements Serial * Output coordinates are in radians. */ private CartesianToPolar() { - super("Cartesian to polar", "Cartesian to cylindrical", 2); + super("Cartesian to polar", "Cartesian to cylindrical", 2, new int[1], false); context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION) .convertAfter(1, DoubleDouble.RADIANS_TO_DEGREES, null); } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToSpherical.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToSpherical.java index 9e41fd1f30..74a5c420aa 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToSpherical.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CartesianToSpherical.java @@ -58,7 +58,7 @@ final class CartesianToSpherical extends CoordinateSystemTransform implements Se * Output coordinates are in radians. */ private CartesianToSpherical() { - super("Cartesian to spherical", null, 3); + super("Cartesian to spherical", null, 3, new int[] {2}, false); context.denormalizeGeographicOutputs(0); // Convert (θ,Ω) from radians to degrees. } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java index 95d51daa4d..4d471062cd 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java @@ -32,16 +32,20 @@ import org.opengis.referencing.operation.MathTransformFactory; import org.opengis.referencing.operation.OperationNotFoundException; import org.opengis.referencing.operation.OperationMethod; import org.apache.sis.referencing.ImmutableIdentifier; -import org.apache.sis.referencing.internal.Resources; -import org.apache.sis.referencing.util.WKTUtilities; -import org.apache.sis.referencing.util.CoordinateOperations; -import org.apache.sis.util.internal.Constants; -import org.apache.sis.metadata.iso.citation.Citations; -import org.apache.sis.parameter.DefaultParameterDescriptorGroup; import org.apache.sis.referencing.cs.AxesConvention; import org.apache.sis.referencing.cs.CoordinateSystems; import org.apache.sis.referencing.cs.DefaultCompoundCS; import org.apache.sis.referencing.operation.DefaultOperationMethod; +import org.apache.sis.referencing.operation.matrix.MatrixSIS; +import org.apache.sis.referencing.operation.matrix.Matrices; +import org.apache.sis.referencing.internal.Resources; +import org.apache.sis.referencing.util.WKTUtilities; +import org.apache.sis.referencing.util.CoordinateOperations; +import org.apache.sis.referencing.util.ExtendedPrecisionMatrix; +import org.apache.sis.referencing.util.MathTransformsOrFactory; +import org.apache.sis.parameter.DefaultParameterDescriptorGroup; +import org.apache.sis.metadata.iso.citation.Citations; +import org.apache.sis.util.internal.Constants; /** @@ -53,9 +57,27 @@ import org.apache.sis.referencing.operation.DefaultOperationMethod; abstract class CoordinateSystemTransform extends AbstractMathTransform { /** * Number of input and output dimensions. + * + * @see #getSourceDimensions() + * @see #getTargetDimensions() */ private final int dimension; + /** + * Index of dimensions having linear units in the coordinate system identified by {@link #angularIsInput}. + * This is used for optimizing the concatenation of this transform by an affine transform. + * + * @see #tryConcatenate(boolean, MathTransform, MathTransformFactory) + */ + private final int[] linearDimensions; + + /** + * Whether the coordinate system having some angular units is the input coordinate system. + * If {@code false}, then the coordinate system having some angular units is the output CS. + * That coordinate system may also have linear units identified by {@link #linearDimensions}. + */ + private final boolean angularIsInput; + /** * An operation method that describe this coordinate system conversion. * This is used for providing a value in {@link DefaultMathTransformFactory#getLastMethodUsed()}. @@ -100,11 +122,15 @@ abstract class CoordinateSystemTransform extends AbstractMathTransform { * Subclasses may need to invoke {@link ContextualParameters#normalizeGeographicInputs(double)} * or {@link ContextualParameters#denormalizeGeographicOutputs(double)} after this constructor. */ - CoordinateSystemTransform(final String method, final String method3D, final int dimension) { - this.dimension = dimension; - this.method = method(method); - this.method3D = (method3D != null) ? method(method3D) : this.method; - this.context = new ContextualParameters(this.method.getParameters(), dimension, dimension); + CoordinateSystemTransform(final String method, final String method3D, final int dimension, + final int[] linearDimensions, final boolean angularIsInput) + { + this.dimension = dimension; + this.linearDimensions = linearDimensions; + this.angularIsInput = angularIsInput; + this.method = method(method); + this.method3D = (method3D != null) ? method(method3D) : this.method; + this.context = new ContextualParameters(this.method.getParameters(), dimension, dimension); } /** @@ -184,6 +210,58 @@ abstract class CoordinateSystemTransform extends AbstractMathTransform { return context; } + /** + * Optimizes concatenation by transferring scale factors from the Cartesian CS side to the spherical, + * cylindrical or polar CS side. The rational is that the affine transform on the latter side will be + * needed anyway for the conversions between radians and degrees. + */ + @Override + protected final MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other, + final MathTransformFactory factory) throws FactoryException + { +concat: if (applyOtherFirst != angularIsInput) { + final ExtendedPrecisionMatrix linear = ExtendedPrecisionMatrix.castOrWrap(MathTransforms.getMatrix(other)); + if (linear != null) { + final int n = linear.getNumRow(); + if (n == linear.getNumCol()) { + Number scale = null; + for (int j=0; j<n; j++) { + for (int i=0; i<n; i++) { + final Number e = linear.getElementOrNull(j,i); + if ((e == null) == (i == j)) break concat; // Abort if matrix is not diagonal. + if (e != null) { + if (i < n-1) { + if (scale == null) scale = e; + else if (!scale.equals(e)) break concat; // Abort if non-uniform scale. + } else if (e.doubleValue() != 1) break concat; // Abort if transform is not affine. + } + } + } + /* + * The transform is affine and applies an uniform scale in all dimensions. + * Replace it by the same scale in all output dimensions having a linear unit. + * + */ + if (scale != null) { + final MatrixSIS angular = Matrices.createIdentity(n); + for (int j : linearDimensions) { + angular.setNumber(j, j, scale); + } + final var w = MathTransformsOrFactory.wrap(factory); + MathTransform step1 = w.linear(angular); + MathTransform step2 = this; + if (applyOtherFirst) { + step2 = step1; + step1 = this; + } + return w.concatenate(step1, step2); + } + } + } + } + return super.tryConcatenate(applyOtherFirst, other, factory); + } + /** * Adds the components of the given coordinate system in the specified list. * This method may invoke itself recursively if there is nested compound CS. diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PolarToCartesian.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PolarToCartesian.java index 03074049dd..d8ae167572 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PolarToCartesian.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PolarToCartesian.java @@ -78,7 +78,7 @@ final class PolarToCartesian extends CoordinateSystemTransform implements Serial * Input coordinates are in radians. */ private PolarToCartesian() { - super("Polar to Cartesian", "Cylindrical to Cartesian", 2); + super("Polar to Cartesian", "Cylindrical to Cartesian", 2, new int[1], true); context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION) .convertBefore(1, DoubleDouble.DEGREES_TO_RADIANS, null); } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/SphericalToCartesian.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/SphericalToCartesian.java index 79a37e6fa2..ddb0093bf9 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/SphericalToCartesian.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/SphericalToCartesian.java @@ -76,7 +76,7 @@ final class SphericalToCartesian extends CoordinateSystemTransform implements Se * Input coordinates are in radians. */ private SphericalToCartesian() { - super("Spherical to Cartesian", null, 3); + super("Spherical to Cartesian", null, 3, new int[] {2}, true); context.normalizeGeographicInputs(0); // Convert (θ,Ω) from degrees to radians. } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/ExtendedPrecisionMatrix.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/ExtendedPrecisionMatrix.java index d43d4dca62..dd64ab41ca 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/ExtendedPrecisionMatrix.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/ExtendedPrecisionMatrix.java @@ -54,6 +54,33 @@ public interface ExtendedPrecisionMatrix extends Matrix { return (element == null) || element.doubleValue() == 0; } + /** + * {@return an extended-precision view of the given matrix}. + * The returned matrix should be assumed read-only. + * + * @param m the matrix to cast or wrap. + * + * @see org.apache.sis.referencing.operation.matrix.MatrixSIS#asExtendedPrecision(Matrix) + */ + @SuppressWarnings("CloneDoesntCallSuperClone") + static ExtendedPrecisionMatrix castOrWrap(final Matrix m) { + if (m == null || m instanceof ExtendedPrecisionMatrix) { + return (ExtendedPrecisionMatrix) m; + } + return new ExtendedPrecisionMatrix() { + @Override public Number getElementOrNull(int j, int i) { + final double v = m.getElement(j, i); + return (v != 0) ? v : null; + } + + @Override public double getElement(int j, int i) {return m.getElement(j, i);} + @Override public int getNumRow() {return m.getNumRow();} + @Override public int getNumCol() {return m.getNumCol();} + @Override public String toString() {return m.toString();} + @Override public Matrix clone() {return m.clone();} + }; + } + /** * Returns all matrix elements in a flat, row-major (column indices vary fastest) array. * The array length is <code>{@linkplain #getNumRow()} * {@linkplain #getNumCol()}</code>. diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java index eff8457bab..87a8493159 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java @@ -50,7 +50,7 @@ public final class CartesianToPolarTest extends TransformTestCase { */ @Test public void testConversion() throws FactoryException, TransformException { - transform = CartesianToPolar.INSTANCE.completeTransform(PolarToCartesianTest.factory()); + transform = CartesianToPolar.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); tolerance = 1E-12; final double[][] data = PolarToCartesianTest.testData(false); verifyTransform(data[1], data[0]); @@ -65,7 +65,7 @@ public final class CartesianToPolarTest extends TransformTestCase { @Test @DependsOnMethod("testConversion") public void testCylindricalConversion() throws FactoryException, TransformException { - transform = CartesianToPolar.INSTANCE.passthrough(PolarToCartesianTest.factory()); + transform = CartesianToPolar.INSTANCE.passthrough(DefaultMathTransformFactory.provider()); tolerance = 1E-12; final double[][] data = PolarToCartesianTest.testData(true); verifyTransform(data[1], data[0]); @@ -80,7 +80,7 @@ public final class CartesianToPolarTest extends TransformTestCase { @Test @DependsOnMethod("testConversion") public void testDerivative() throws FactoryException, TransformException { - transform = CartesianToPolar.INSTANCE.completeTransform(PolarToCartesianTest.factory()); + transform = CartesianToPolar.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6}; tolerance = 1E-7; verifyDerivative(30, 60); @@ -95,7 +95,7 @@ public final class CartesianToPolarTest extends TransformTestCase { @Test @DependsOnMethod("testDerivative") public void testCylindricalDerivative() throws FactoryException, TransformException { - transform = CartesianToPolar.INSTANCE.passthrough(PolarToCartesianTest.factory()); + transform = CartesianToPolar.INSTANCE.passthrough(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 1E-7; verifyDerivative(30, 60, 100); @@ -110,7 +110,7 @@ public final class CartesianToPolarTest extends TransformTestCase { @Test @DependsOnMethod("testDerivative") public void testConsistency() throws FactoryException, TransformException { - transform = CartesianToPolar.INSTANCE.completeTransform(PolarToCartesianTest.factory()); + transform = CartesianToPolar.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6}; tolerance = 2E-7; verifyInDomain(new double[] {-100, -100}, // Minimal coordinates @@ -128,7 +128,7 @@ public final class CartesianToPolarTest extends TransformTestCase { @Test @DependsOnMethod("testCylindricalDerivative") public void testCylindricalConsistency() throws FactoryException, TransformException { - transform = CartesianToPolar.INSTANCE.passthrough(PolarToCartesianTest.factory()); + transform = CartesianToPolar.INSTANCE.passthrough(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 2E-7; verifyInDomain(new double[] {-100, -100, -100}, // Minimal coordinates diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java index 802c8f671d..203db29cda 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java @@ -16,11 +16,15 @@ */ package org.apache.sis.referencing.operation.transform; +import java.util.List; import org.opengis.util.FactoryException; +import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; // Test dependencies import org.junit.Test; +import org.junit.Before; +import static org.junit.jupiter.api.Assertions.*; import org.apache.sis.test.DependsOn; import org.apache.sis.test.DependsOnMethod; import org.apache.sis.test.TestUtilities; @@ -43,15 +47,23 @@ public final class CartesianToSphericalTest extends TransformTestCase { } /** - * Tests coordinate conversions. + * Creates the transform instance to test. * * @throws FactoryException if the transform cannot be created. + */ + @Before + public void createInstance() throws FactoryException { + transform = CartesianToSpherical.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); + } + + /** + * Tests coordinate conversions. + * * @throws TransformException if a coordinate cannot be transformed. */ @Test - public void testConversion() throws FactoryException, TransformException { - transform = CartesianToSpherical.INSTANCE.completeTransform(SphericalToCartesianTest.factory()); - tolerance = 1E-12; + public void testConversion() throws TransformException { + tolerance = SphericalToCartesianTest.TOLERANCE; final double[][] data = SphericalToCartesianTest.testData(); verifyTransform(data[1], data[0]); } @@ -59,12 +71,10 @@ public final class CartesianToSphericalTest extends TransformTestCase { /** * Tests calculation of a transform derivative. * - * @throws FactoryException if the transform cannot be created. * @throws TransformException if a coordinate cannot be transformed. */ @Test - public void testDerivative() throws FactoryException, TransformException { - transform = CartesianToSpherical.INSTANCE.completeTransform(SphericalToCartesianTest.factory()); + public void testDerivative() throws TransformException { derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 1E-7; verifyDerivative(30, 60, 100); @@ -73,13 +83,11 @@ public final class CartesianToSphericalTest extends TransformTestCase { /** * Tests calculation of a transform derivative. * - * @throws FactoryException if the transform cannot be created. * @throws TransformException if a coordinate cannot be transformed. */ @Test @DependsOnMethod({"testConversion", "testDerivative"}) - public void testConsistency() throws FactoryException, TransformException { - transform = CartesianToSpherical.INSTANCE.completeTransform(SphericalToCartesianTest.factory()); + public void testConsistency() throws TransformException { derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 1E-5; verifyInDomain(new double[] {-100, -100, -100}, // Minimal coordinates @@ -87,4 +95,25 @@ public final class CartesianToSphericalTest extends TransformTestCase { new int[] { 10, 10, 10}, TestUtilities.createRandomNumberGenerator()); } + + /** + * Tests concatenation. + * + * @throws TransformException if a coordinate cannot be transformed. + */ + @Test + @DependsOnMethod("testConversion") + public void testConcatenation() throws TransformException { + final double scale = 1000; + transform = MathTransforms.concatenate(MathTransforms.scale(scale, scale, scale), transform); + List<MathTransform> steps = MathTransforms.getSteps(transform); + assertEquals(2, steps.size()); + assertSame(CartesianToSpherical.INSTANCE, steps.get(0)); + assertTrue(steps.get(1) instanceof LinearTransform); + + double[][] data = SphericalToCartesianTest.testData(); + SphericalToCartesianTest.multiply(data[1], 1/scale); + tolerance = SphericalToCartesianTest.TOLERANCE * scale; + verifyTransform(data[1], data[0]); + } } diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java index d87b2a09e6..25ef0e410e 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java @@ -19,7 +19,6 @@ package org.apache.sis.referencing.operation.transform; import static java.lang.StrictMath.*; import org.opengis.util.FactoryException; import org.opengis.referencing.operation.TransformException; -import org.opengis.referencing.operation.MathTransformFactory; // Test dependencies import org.junit.Test; @@ -84,13 +83,6 @@ public final class PolarToCartesianTest extends TransformTestCase { return data; } - /** - * Returns the factory to use for testing purpose. - */ - static MathTransformFactory factory() { - return DefaultMathTransformFactory.provider(); - } - /** * Tests coordinate conversions in the polar case. * @@ -99,7 +91,7 @@ public final class PolarToCartesianTest extends TransformTestCase { */ @Test public void testConversion() throws FactoryException, TransformException { - transform = PolarToCartesian.INSTANCE.completeTransform(factory()); + transform = PolarToCartesian.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); tolerance = 1E-12; final double[][] data = testData(false); verifyTransform(data[0], data[1]); @@ -114,7 +106,7 @@ public final class PolarToCartesianTest extends TransformTestCase { @Test @DependsOnMethod("testConversion") public void testCylindricalConversion() throws FactoryException, TransformException { - transform = PolarToCartesian.INSTANCE.passthrough(factory()); + transform = PolarToCartesian.INSTANCE.passthrough(DefaultMathTransformFactory.provider()); tolerance = 1E-12; final double[][] data = testData(true); verifyTransform(data[0], data[1]); @@ -129,7 +121,7 @@ public final class PolarToCartesianTest extends TransformTestCase { @Test @DependsOnMethod("testConversion") public void testDerivative() throws FactoryException, TransformException { - transform = PolarToCartesian.INSTANCE.completeTransform(factory()); + transform = PolarToCartesian.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6}; tolerance = 1E-7; verifyDerivative(100, 60); @@ -144,7 +136,7 @@ public final class PolarToCartesianTest extends TransformTestCase { @Test @DependsOnMethod("testDerivative") public void testCylindricalDerivative() throws FactoryException, TransformException { - transform = PolarToCartesian.INSTANCE.passthrough(factory()); + transform = PolarToCartesian.INSTANCE.passthrough(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 1E-7; verifyDerivative(100, 60, 25); @@ -159,7 +151,7 @@ public final class PolarToCartesianTest extends TransformTestCase { @Test @DependsOnMethod("testDerivative") public void testConsistency() throws FactoryException, TransformException { - transform = PolarToCartesian.INSTANCE.completeTransform(factory()); + transform = PolarToCartesian.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6}; tolerance = 1E-7; verifyInDomain(new double[] { 0, -180}, // Minimal coordinates @@ -177,7 +169,7 @@ public final class PolarToCartesianTest extends TransformTestCase { @Test @DependsOnMethod("testCylindricalDerivative") public void testCylindricalConsistency() throws FactoryException, TransformException { - transform = PolarToCartesian.INSTANCE.passthrough(factory()); + transform = PolarToCartesian.INSTANCE.passthrough(DefaultMathTransformFactory.provider()); derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 1E-7; verifyInDomain(new double[] { 0, -180, -100}, // Minimal coordinates diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java index 77405de7bb..45095dc9cc 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java @@ -16,13 +16,16 @@ */ package org.apache.sis.referencing.operation.transform; +import java.util.List; import static java.lang.StrictMath.*; import org.opengis.util.FactoryException; +import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; -import org.opengis.referencing.operation.MathTransformFactory; // Test dependencies import org.junit.Test; +import org.junit.Before; +import static org.junit.jupiter.api.Assertions.*; import org.apache.sis.test.DependsOnMethod; import org.apache.sis.test.TestUtilities; @@ -42,6 +45,11 @@ public final class SphericalToCartesianTest extends TransformTestCase { public SphericalToCartesianTest() { } + /** + * Tolerance factor for verifying the conversion results. + */ + static final double TOLERANCE = 1E-12; + /** * Returns coordinate tuples in spherical coordinates and their equivalent in Cartesian coordinates. */ @@ -79,22 +87,33 @@ public final class SphericalToCartesianTest extends TransformTestCase { } /** - * Returns the factory to use for testing purpose. + * Multiples all elements of the given array by the given scale factor. + * This is used when the test data are modified for testing concatenation. */ - static MathTransformFactory factory() { - return DefaultMathTransformFactory.provider(); + static void multiply(final double[] data, final double scale) { + for (int i=0; i<data.length; i++) { + data[i] *= scale; + } } /** - * Tests coordinate conversions. + * Creates the transform instance to test. * * @throws FactoryException if the transform cannot be created. + */ + @Before + public void createInstance() throws FactoryException { + transform = SphericalToCartesian.INSTANCE.completeTransform(DefaultMathTransformFactory.provider()); + } + + /** + * Tests coordinate conversions. + * * @throws TransformException if a coordinate cannot be transformed. */ @Test - public void testConversion() throws FactoryException, TransformException { - transform = SphericalToCartesian.INSTANCE.completeTransform(factory()); - tolerance = 1E-12; + public void testConversion() throws TransformException { + tolerance = TOLERANCE; final double[][] data = testData(); verifyTransform(data[0], data[1]); } @@ -102,12 +121,10 @@ public final class SphericalToCartesianTest extends TransformTestCase { /** * Tests calculation of a transform derivative. * - * @throws FactoryException if the transform cannot be created. * @throws TransformException if a coordinate cannot be transformed. */ @Test - public void testDerivative() throws FactoryException, TransformException { - transform = SphericalToCartesian.INSTANCE.completeTransform(factory()); + public void testDerivative() throws TransformException { derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 1E-7; verifyDerivative(30, 60, 100); @@ -116,13 +133,11 @@ public final class SphericalToCartesianTest extends TransformTestCase { /** * Tests calculation of a transform derivative. * - * @throws FactoryException if the transform cannot be created. * @throws TransformException if a coordinate cannot be transformed. */ @Test @DependsOnMethod({"testConversion", "testDerivative"}) - public void testConsistency() throws FactoryException, TransformException { - transform = SphericalToCartesian.INSTANCE.completeTransform(factory()); + public void testConsistency() throws TransformException { derivativeDeltas = new double[] {1E-6, 1E-6, 1E-6}; tolerance = 1E-7; verifyInDomain(new double[] {-180, -90, 0}, // Minimal coordinates @@ -130,4 +145,25 @@ public final class SphericalToCartesianTest extends TransformTestCase { new int[] { 10, 10, 10}, TestUtilities.createRandomNumberGenerator()); } + + /** + * Tests concatenation. + * + * @throws TransformException if a coordinate cannot be transformed. + */ + @Test + @DependsOnMethod("testConversion") + public void testConcatenation() throws TransformException { + final double scale = 1000; + transform = MathTransforms.concatenate(transform, MathTransforms.scale(scale, scale, scale)); + List<MathTransform> steps = MathTransforms.getSteps(transform); + assertEquals(2, steps.size()); + assertTrue(steps.get(0) instanceof LinearTransform); + assertSame(SphericalToCartesian.INSTANCE, steps.get(1)); + + double[][] data = testData(); + multiply(data[1], scale); + tolerance = TOLERANCE * scale; + verifyTransform(data[0], data[1]); + } }