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 2023/04/24 09:56:33 UTC
[sis] branch geoapi-4.0 updated: `MathTransforms.linear(MathTransform, DirectPosition)` and `tangent(…)` where duplicating functionality. Deprecate the former in favor of the latter.
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 f6509802be `MathTransforms.linear(MathTransform, DirectPosition)` and `tangent(…)` where duplicating functionality. Deprecate the former in favor of the latter.
f6509802be is described below
commit f6509802be691dadc2110be818d56dd2016596b3
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Mon Apr 24 11:55:46 2023 +0200
`MathTransforms.linear(MathTransform, DirectPosition)` and `tangent(…)` where duplicating functionality.
Deprecate the former in favor of the latter.
---
.../org/apache/sis/portrayal/CanvasFollower.java | 2 +-
.../sis/referencing/operation/matrix/Matrices.java | 8 +-
.../operation/transform/MathTransforms.java | 193 +++++++++------------
.../operation/transform/MathTransformsTest.java | 71 ++++----
4 files changed, 124 insertions(+), 150 deletions(-)
diff --git a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java
index c568e78384..fab7d849c6 100644
--- a/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java
+++ b/core/sis-portrayal/src/main/java/org/apache/sis/portrayal/CanvasFollower.java
@@ -365,7 +365,7 @@ public class CanvasFollower implements PropertyChangeListener, Disposable {
*/
if (objectiveTransform != null) {
DirectPosition poi = getSourceObjectivePOI();
- AffineTransform t = AffineTransforms2D.castOrCopy(MathTransforms.linear(objectiveTransform, poi));
+ AffineTransform t = AffineTransforms2D.castOrCopy(MathTransforms.tangent(objectiveTransform, poi));
AffineTransform c = t.createInverse();
c.preConcatenate(before);
c.preConcatenate(t);
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 2fed5db647..69e26da43d 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
@@ -714,10 +714,10 @@ public final class Matrices extends Static {
* is non-null, all its coordinate values are copied in the last column of the returned matrix.
*
* <h4>Relationship with {@code MathTransform}</h4>
- * When used together with {@link MathTransforms#derivativeAndTransform MathTransforms.derivativeAndTransform(…)},
- * the {@code derivative} argument is the derivative computed by {@code derivativeAndTransform(…)} and the
- * {@code translation} vector is the position computed by that method. The result is an approximation of the
- * transform in the vicinity of the position given to {@code derivativeAndTransform(…)}.
+ * When used together with {@link MathTransforms#derivativeAndTransform MathTransforms.derivativeAndTransform(…)}
+ * with source coordinates all set to zero, the {@code derivative} and {@code translation} arguments can be
+ * respectively the return value and destination coordinates computed by {@code derivativeAndTransform(…)}.
+ * The {@code createAffine(…)} result is then an approximation of the transform in the vicinity of the origin.
*
* @param derivative the scale, shear and rotation of the affine transform.
* @param translation the translation vector (the last column) of the affine transform.
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 9b7cbae31f..a153122df3 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
@@ -220,11 +220,34 @@ public final class MathTransforms extends Static {
return new ProjectiveTransform(matrix).optimize();
}
+ /**
+ * Returns a linear (usually affine) transform which approximates the given transform in the vicinity of the given position.
+ *
+ * @param transform the transform to approximate by an affine transform.
+ * @param position position in source CRS around which to get the an affine transform approximation.
+ * @return a transform approximating the given transform around the given position.
+ * @throws TransformException if an error occurred while transforming the given position
+ * or computing the derivative at that position.
+ *
+ * @since 1.0
+ *
+ * @deprecated This method duplicates {@link #tangent(MathTransform, DirectPosition)}.
+ */
+ @Deprecated(since="1.4", forRemoval=true)
+ public static LinearTransform linear(MathTransform transform, DirectPosition position) throws TransformException {
+ return tangent(transform, position);
+ }
+
/**
* Returns a linear (usually affine) transform which approximates the given transform in the vicinity of the given position.
* If the given transform is already an instance of {@link LinearTransform}, then it is returned as-is.
* Otherwise an approximation for the given position is created using the
- * {@linkplain MathTransform#derivative(DirectPosition) transform derivative} at that position.
+ * {@linkplain MathTransform#derivative(DirectPosition) transform derivative} at that given position.
+ * 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 line at the given position.
+ * The same computation is generalized to any number of dimensions (tangent plane if the given transform is two-dimensional,
+ * <i>etc.</i>).</p>
*
* <h4>Invariant</h4>
* Transforming the given {@code position} using the given {@code transform} produces the same result
@@ -232,23 +255,23 @@ public final class MathTransforms extends Static {
* This invariant holds only for that particular position; the transformation of any other positions
* may produce different results.
*
- * @param transform the transform to approximate by an affine transform.
- * @param position position in source CRS around which to get the an affine transform approximation.
+ * @param toApproximate the potentially non-linear transform to approximate by a linear transform.
+ * @param tangentPoint position in source CRS around which to get the an line approximation.
* @return a transform approximating the given transform around the given position.
* @throws TransformException if an error occurred while transforming the given position
* or computing the derivative at that position.
*
- * @since 1.0
+ * @since 1.1
*
* @see #getMatrix(MathTransform, DirectPosition)
*/
- public static LinearTransform linear(final MathTransform transform, final DirectPosition position) throws TransformException {
- if (transform instanceof LinearTransform) {
+ public static LinearTransform tangent(final MathTransform toApproximate, final DirectPosition tangentPoint) throws TransformException {
+ if (toApproximate instanceof LinearTransform) {
// We accept null position here for consistency with MathTransform.derivative(DirectPosition).
- ArgumentChecks.ensureDimensionMatches("position", transform.getSourceDimensions(), position);
- return (LinearTransform) transform;
+ ArgumentChecks.ensureDimensionMatches("tangentPoint", toApproximate.getSourceDimensions(), tangentPoint);
+ return (LinearTransform) toApproximate;
} else {
- return linear(getMatrix(transform, position));
+ return linear(getMatrix(toApproximate, tangentPoint));
}
}
@@ -679,51 +702,71 @@ public final class MathTransforms extends Static {
* Otherwise the returned matrix can be used for {@linkplain #linear(Matrix) building a linear transform} which can be
* used as an approximation of the given transform for short distances around the given position.
*
- * @param transform the transform to approximate by an affine transform.
- * @param position position in source CRS around which to get the coefficients of an affine transform approximation.
- * @return the matrix of the given transform around the given position.
- * @throws TransformException if an error occurred while transforming the given position or computing the derivative at
- * that position.
+ * @param toApproximate the potentially non-linear transform to approximate by an affine transform.
+ * @param tangentPoint position in source CRS around which to get the coefficients of an affine transform approximation.
+ * @return the matrix representation of the affine approximation of the given transform around the given position.
+ * @throws TransformException if an error occurred while transforming the given position
+ * or computing the derivative at that position.
*
* @since 1.0
*
- * @see #linear(MathTransform, DirectPosition)
+ * @see #tangent(MathTransform, DirectPosition)
*/
- public static Matrix getMatrix(final MathTransform transform, final DirectPosition position) throws TransformException {
- ArgumentChecks.ensureNonNull("transform", transform);
- final int srcDim = transform.getSourceDimensions();
- ArgumentChecks.ensureDimensionMatches("position", srcDim, position); // Null position is okay for now.
- final Matrix affine = getMatrix(transform);
+ public static Matrix getMatrix(final MathTransform toApproximate, final DirectPosition tangentPoint) throws TransformException {
+ ArgumentChecks.ensureNonNull("toApproximate", toApproximate);
+ final int srcDim = toApproximate.getSourceDimensions();
+ ArgumentChecks.ensureDimensionMatches("tangentPoint", srcDim, tangentPoint); // Null position is okay for now.
+ final Matrix affine = getMatrix(toApproximate);
if (affine != null) {
return affine;
// We accept null position here for consistency with MathTransform.derivative(DirectPosition).
}
- ArgumentChecks.ensureNonNull("position", position);
- final int tgtDim = transform.getTargetDimensions();
- double[] pts = new double[Math.max(srcDim + 1, tgtDim)];
+ ArgumentChecks.ensureNonNull("tangentPoint", tangentPoint);
+ final int tgtDim = toApproximate.getTargetDimensions();
+ double[] coordinates = new double[Math.max(tgtDim, srcDim + 1)];
for (int i=0; i<srcDim; i++) {
- pts[i] = position.getOrdinate(i);
- }
- final Matrix d = derivativeAndTransform(transform, pts, 0, pts, 0);
- final MatrixSIS a = Matrices.createZero(tgtDim + 1, srcDim + 1);
- for (int j=0; j<tgtDim; j++) {
- for (int i=0; i<srcDim; i++) {
- a.setElement(j, i, d.getElement(j, i));
- }
- a.setElement(j, srcDim, pts[j]);
- pts[j] = -position.getOrdinate(j); // To be used by a.translate(pts) later.
+ coordinates[i] = tangentPoint.getOrdinate(i);
}
- a.setElement(tgtDim, srcDim, 1);
+ final Matrix derivative = derivativeAndTransform(toApproximate, coordinates, 0, coordinates, 0);
+ final MatrixSIS m = Matrices.createAffine(derivative, new DirectPositionView.Double(coordinates, 0, tgtDim));
/*
* At this point, the translation column in the matrix is set as if the coordinate system origin
* was at the given position. We want to keep the original coordinate system origin. We do that
- * be applying a translation in the opposite direction before the affine transform. Translation
- * terms were opportunistically set in the previous loop.
+ * be applying a translation in the opposite direction before the affine transform.
*/
- pts = ArraysExt.resize(pts, srcDim + 1);
- pts[srcDim] = 1;
- a.translate(pts);
- return a;
+ coordinates = ArraysExt.resize(coordinates, srcDim + 1);
+ for (int i=0; i<srcDim; i++) {
+ coordinates[i] = -tangentPoint.getOrdinate(i);
+ }
+ coordinates[srcDim] = 1;
+ m.translate(coordinates);
+ return m;
+ }
+
+ /**
+ * Returns source coordinate values where the transform is mathematically and numerically applicable.
+ * This is <em>not</em> the domain of validity for which a coordinate reference system has been defined,
+ * because this method ignores "real world" considerations such as datum and country boundaries.
+ * This method is for allowing callers to crop their data for removing areas that may cause numerical problems,
+ * for example latitudes too close to a pole before Mercator projection.
+ *
+ * <p>See {@link AbstractMathTransform#getDomain(DomainDefinition)} for more information.
+ * This static method delegates to above-cited method if possible, or returns an empty value otherwise.</p>
+ *
+ * @param evaluated transform for which to evaluate a domain, or {@code null}.
+ * @return estimation of a domain where this transform is considered numerically applicable.
+ * @throws TransformException if the domain cannot be estimated.
+ *
+ * @see AbstractMathTransform#getDomain(DomainDefinition)
+ * @see org.opengis.referencing.operation.CoordinateOperation#getDomainOfValidity()
+ *
+ * @since 1.3
+ */
+ public static Optional<Envelope> getDomain(final MathTransform evaluated) throws TransformException {
+ if (evaluated instanceof AbstractMathTransform) {
+ return ((AbstractMathTransform) evaluated).getDomain(new DomainDefinition());
+ }
+ return Optional.empty();
}
/**
@@ -768,74 +811,4 @@ 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 cannot 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
- {
- ArgumentChecks.ensureNonNull("toApproximate", toApproximate);
- if (toApproximate instanceof LinearTransform) {
- return (LinearTransform) 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;
- }
-
- /**
- * Returns source coordinate values where the transform is mathematically and numerically applicable.
- * This is <em>not</em> the domain of validity for which a coordinate reference system has been defined,
- * because this method ignores "real world" considerations such as datum and country boundaries.
- * This method is for allowing callers to crop their data for removing areas that may cause numerical problems,
- * for example latitudes too close to a pole before Mercator projection.
- *
- * <p>See {@link AbstractMathTransform#getDomain(DomainDefinition)} for more information.
- * This static method delegates to above-cited method if possible, or returns an empty value otherwise.</p>
- *
- * @param evaluated transform for which to evaluate a domain, or {@code null}.
- * @return estimation of a domain where this transform is considered numerically applicable.
- * @throws TransformException if the domain cannot be estimated.
- *
- * @see AbstractMathTransform#getDomain(DomainDefinition)
- * @see org.opengis.referencing.operation.CoordinateOperation#getDomainOfValidity()
- *
- * @since 1.3
- */
- public static Optional<Envelope> getDomain(final MathTransform evaluated) throws TransformException {
- if (evaluated instanceof AbstractMathTransform) {
- return ((AbstractMathTransform) evaluated).getDomain(new DomainDefinition());
- }
- return Optional.empty();
- }
}
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 d8c0274821..974071affb 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
@@ -171,13 +171,44 @@ public final class MathTransformsTest extends TestCase {
}
/**
- * Tests {@link MathTransforms#linear(MathTransform, DirectPosition)}.
+ * Tests {@link MathTransforms#tangent(MathTransform, DirectPosition)} of a linear transform.
*
- * @throws TransformException if an error occurred while computing the derivative.
+ * @throws TransformException should never happen since this test uses a linear transform.
*/
@Test
@DependsOnMethod("testGetMatrix")
- public void testLinearUsingPosition() throws TransformException {
+ public void testTangentOfLinear() 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);
+ }
+
+ /**
+ * Tests {@link MathTransforms#tangent(MathTransform, DirectPosition)} of a non-linear transform.
+ *
+ * @throws TransformException if an error occurred while computing the derivative.
+ */
+ @Test
+ @DependsOnMethod("testTangentOfLinear")
+ public void testTangent() throws TransformException {
final DirectPosition pos = new GeneralDirectPosition(3, 1.5, 6);
MathTransform tr = MathTransforms.linear(new Matrix4(
0, 5, 0, 9,
@@ -185,11 +216,11 @@ public final class MathTransformsTest extends TestCase {
0, 0, 12, -3,
0, 0, 0, 1));
- LinearTransform linear = MathTransforms.linear(tr, pos);
+ LinearTransform linear = MathTransforms.tangent(tr, pos);
assertSame("Linear transform shall be returned unchanged.", tr, linear);
tr = MathTransforms.concatenate(nonLinear3D(), tr);
- linear = MathTransforms.linear(tr, pos);
+ linear = MathTransforms.tangent(tr, pos);
assertNotSame(tr, linear);
/*
* Transformation using above approximation shall produce the same result than the original
@@ -213,34 +244,4 @@ public final 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);
- }
}