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.
*/