This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits 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 8cd3a85563 feat(Geometry): implement point and linestring transform 
operation
8cd3a85563 is described below

commit 8cd3a85563266f3a5cde45b84a65a3fa2bb5de1b
Author: jsorel <[email protected]>
AuthorDate: Wed Nov 4 09:53:43 2026 +0100

    feat(Geometry): implement point and linestring transform operation
---
 .../geometries/operation/GeometryProcessor.java    | 37 ++++++++++------
 .../apache/sis/geometries/operation/Transform.java | 32 ++++++++++++--
 .../sis/geometries/operation/TransformTest.java    | 49 +++++++++++++++++++---
 3 files changed, 95 insertions(+), 23 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
index 10cb6cdbda..c7cb6bc6a1 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
@@ -29,6 +29,7 @@ import static org.opengis.annotation.Specification.ISO_19107;
 import org.opengis.annotation.UML;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.MathTransform;
+import org.opengis.util.FactoryException;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.DE9IM;
 import org.apache.sis.geometries.DataPointsType;
@@ -58,6 +59,7 @@ import org.apache.sis.maths.NDArrays;
 import org.apache.sis.maths.SampleSystem;
 import org.apache.sis.maths.Vector;
 import org.apache.sis.measure.Quantities;
+import org.apache.sis.referencing.CRS;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.ArgumentChecks;
 
@@ -571,21 +573,30 @@ public final class GeometryProcessor {
         if (crs == null) {
             crs = geom.getCoordinateReferenceSystem();
         }
-
-        if (geom instanceof LinearRing cdt) {
-            return Transform.transform(cdt, crs, transform);
-        } else if (geom instanceof Triangle cdt) {
-            return Transform.transform(cdt, crs, transform);
-        } else if (geom instanceof Polygon cdt) {
-            return Transform.transform(cdt, crs, transform);
-        } else if (geom instanceof MeshPrimitive cdt) {
-            return Transform.transform(cdt, crs, transform);
-        } else if (geom instanceof GeometryCollection<?> cdt) {
-            // Checked after mesh primitives because the points and lines 
primitives are also collections.
-            return Transform.transform(cdt, crs, transform);
+        if (transform == null) {
+            try {
+                transform = 
CRS.findOperation(geom.getCoordinateReferenceSystem(), crs, 
null).getMathTransform();
+            } catch (FactoryException ex) {
+                throw new OperationException(ex.getMessage(), ex);
+            }
         }
 
-        throw new UnsupportedOperationException();
+        /*
+         * Case order matters: the first matching case is selected.
+         * Mesh primitives are checked before line strings and collections
+         * because the points and lines primitives are also of those types.
+         */
+        return switch (geom) {
+            case LinearRing            cdt -> Transform.transform(cdt, crs, 
transform);
+            case Triangle              cdt -> Transform.transform(cdt, crs, 
transform);
+            case Polygon               cdt -> Transform.transform(cdt, crs, 
transform);
+            case MeshPrimitive         cdt -> Transform.transform(cdt, crs, 
transform);
+            case LineString            cdt -> Transform.transform(cdt, crs, 
transform);
+            case Point                 cdt -> Transform.transform(cdt, crs, 
transform);
+            case GeometryCollection<?> cdt -> Transform.transform(cdt, crs, 
transform);
+            default -> throw new UnsupportedOperationException(
+                    "Transform of " + geom.getGeometryType() + " geometries is 
not supported yet.");
+        };
     }
 
     /**
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
index bbfd21e2a3..d3f8173bde 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
@@ -27,7 +27,9 @@ import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryCollection;
 import org.apache.sis.geometries.GeometryFactory;
+import org.apache.sis.geometries.Point;
 import org.apache.sis.geometries.DataPointsType;
+import org.apache.sis.geometries.curve.LineString;
 import org.apache.sis.geometries.curve.LinearRing;
 import org.apache.sis.geometries.internal.shared.ArrayDataPoints;
 import org.apache.sis.geometries.mesh.MeshPrimitive;
@@ -78,9 +80,11 @@ public final class Transform {
         }
     }
 
-    public static LinearRing transform(LinearRing r, CoordinateReferenceSystem 
crs, MathTransform transform) throws OperationException {
-
-        DataPoints ps = r.getDataPoints();
+    /**
+     * Transforms the positions of the given data points.
+     * Note : this method will copy all other attributes untransformed.
+     */
+    private static ArrayDataPoints transform(DataPoints ps, 
CoordinateReferenceSystem crs, MathTransform transform) throws 
OperationException {
         final Array reference = 
ps.getAttributeArray(DataPointsType.ATT_POSITION);
         final Array positions = transform(reference, crs, transform);
         final ArrayDataPoints cp = new ArrayDataPoints(positions);
@@ -89,7 +93,27 @@ public final class Transform {
                 cp.setAttribute(name, ps.getAttributeArray(name).copy());
             }
         }
-        return GeometryFactory.DEFAULT.createLinearRing(cp);
+        return cp;
+    }
+
+    /**
+     * Transform point to a new CoordinateReferenceSystem.
+     * Note : this method will copy all other attributes untransformed.
+     */
+    public static Point transform(Point p, CoordinateReferenceSystem crs, 
MathTransform transform) throws OperationException {
+        return GeometryFactory.DEFAULT.createPoint((DataPoints) 
transform(p.getDataPoints(), crs, transform));
+    }
+
+    /**
+     * Transform line string to a new CoordinateReferenceSystem.
+     * Note : this method will copy all other attributes untransformed.
+     */
+    public static LineString transform(LineString l, CoordinateReferenceSystem 
crs, MathTransform transform) throws OperationException {
+        return 
GeometryFactory.DEFAULT.createLineString(transform(l.getDataPoints(), crs, 
transform));
+    }
+
+    public static LinearRing transform(LinearRing r, CoordinateReferenceSystem 
crs, MathTransform transform) throws OperationException {
+        return 
GeometryFactory.DEFAULT.createLinearRing(transform(r.getDataPoints(), crs, 
transform));
     }
 
     public static Polygon transform(Polygon p, CoordinateReferenceSystem crs, 
MathTransform transform) throws OperationException {
diff --git 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
index f9a27ae8fc..c4da19d966 100644
--- 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
+++ 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
@@ -23,10 +23,15 @@ import org.opengis.util.FactoryException;
 import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryCollection;
 import org.apache.sis.geometries.GeometryFactory;
+import org.apache.sis.geometries.Point;
+import org.apache.sis.geometries.curve.LineString;
+import org.apache.sis.geometries.curve.LinearRing;
 import org.apache.sis.geometries.mesh.MeshPrimitive;
 import org.apache.sis.maths.NDArrays;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.operation.matrix.Matrix3;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
 
 // Test dependencies
 import static org.junit.jupiter.api.Assertions.*;
@@ -149,15 +154,47 @@ public class TransformTest extends AbstractD9IMTest {
      */
     private static final TestCase[] ENTRIES = {
         /*
-         * TODO: `GeometryProcessor.transform(...)` handles only the mesh 
primitives and the
-         * surfaces built on linear rings. The transform of an empty geometry 
should be that
-         * geometry in the target reference system, and the transform of a 
point should be its
-         * position converted to that system.
+         * TODO: the transform of an empty geometry should be that geometry in 
the target reference system.
          */
-        new TestCase(EMPTY_1, CRS_TARGET, null, 
UnsupportedOperationException.class),
-        new TestCase(POINT_A, CRS_TARGET, null, 
UnsupportedOperationException.class)
+        new TestCase(EMPTY_1, CRS_TARGET, null, 
UnsupportedOperationException.class)
     };
 
+    /**
+     * Tests the transform of a point when no math transform is given:
+     * the operation from the point CRS to the target CRS must be used.
+     */
+    @Test
+    public void testPointWithoutMathTransform() {
+        final CoordinateReferenceSystem target = 
CommonCRS.WGS84.normalizedGeographic();
+        final Geometry result = new GeometryProcessor().transform(POINT_A, 
target, null);
+        final Point pt = assertInstanceOf(Point.class, result);
+        assertEquals(target, pt.getCoordinateReferenceSystem());
+        assertEquals(5.0,  pt.getPosition().get(0), 1e-9);
+        assertEquals(10.0, pt.getPosition().get(1), 1e-9);
+    }
+
+    /**
+     * Tests the transform of a line string with an explicit math transform.
+     */
+    @Test
+    public void testLineString() {
+        final CoordinateReferenceSystem crs = 
CommonCRS.WGS84.normalizedGeographic();
+        final LineString line = GeometryFactory.DEFAULT.createLineString(
+                GeometryFactory.DEFAULT.createDataPoints(crs, 1.0, 2.0,  3.0, 
4.0,  5.0, 6.0));
+        final MathTransform mt = MathTransforms.linear(new Matrix3(2, 0, 10,
+                                                                   0, 3, 20,
+                                                                   0, 0,  1));
+        final Geometry result = new GeometryProcessor().transform(line, crs, 
mt);
+        final LineString ls = assertInstanceOf(LineString.class, result);
+        assertFalse(ls instanceof LinearRing);
+        assertEquals(3, ls.getNumPoints());
+        final double[] expected = {12, 26,  16, 32,  20, 38};
+        for (int i = 0; i < 3; i++) {
+            assertEquals(expected[i*2],   
ls.getPointN(i).getPosition().get(0), 1e-9);
+            assertEquals(expected[i*2+1], 
ls.getPointN(i).getPosition().get(1), 1e-9);
+        }
+    }
+
     /**
      * Tests {@code transform(Geometry, CoordinateReferenceSystem, 
MathTransform)} on all declared test cases.
      */

Reply via email to