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

jsorel 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 57c0ccde4a Start geometry wrapper classes for incubator geometry api
57c0ccde4a is described below

commit 57c0ccde4af07cc77157f8a286f931139f6e4103
Author: jsorel <[email protected]>
AuthorDate: Tue Jul 22 14:28:52 2025 +0200

    Start geometry wrapper classes for incubator geometry api
---
 .../org.apache.sis.feature/main/module-info.java   |   3 +
 .../main/org/apache/sis/setup/GeometryLibrary.java |  16 +
 .../org/apache/sis/geometries/GeometryFactory.java | 160 ++++++-
 .../main/org/apache/sis/geometries/Wrapper.java    | 469 +++++++++++++++++++++
 4 files changed, 644 insertions(+), 4 deletions(-)

diff --git a/endorsed/src/org.apache.sis.feature/main/module-info.java 
b/endorsed/src/org.apache.sis.feature/main/module-info.java
index e3cb0e993c..e557fb23e2 100644
--- a/endorsed/src/org.apache.sis.feature/main/module-info.java
+++ b/endorsed/src/org.apache.sis.feature/main/module-info.java
@@ -48,6 +48,9 @@ module org.apache.sis.feature {
             org.apache.sis.cql,                     // In the "incubator" 
sub-project.
             org.apache.sis.portrayal.map;           // In the "incubator" 
sub-project.
 
+    exports org.apache.sis.filter.sqlmm to
+            org.apache.sis.geometry;                // In the "incubator" 
sub-project.
+
     exports org.apache.sis.feature.privy to
             org.apache.sis.storage,
             org.apache.sis.storage.xml,
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/GeometryLibrary.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/GeometryLibrary.java
index acc07cbf18..ca8bb48274 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/GeometryLibrary.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/GeometryLibrary.java
@@ -92,6 +92,22 @@ public enum GeometryLibrary {
      */
     JTS("JTS"),
 
+    /**
+     * The SIS library. This open source library provides an object model
+     * for a large set of geometry types but has limited geometric functions.
+     * The library is available under Apache 2 license.
+     *
+     * <table class="sis">
+     *   <caption>Implementation classes</caption>
+     *   <tr><th>Geometry type</th>               <th>Class name</th></tr>
+     *   <tr><td>Root geometry class</td>         <td>{@code 
org.apache.sis.geometries.Geometry}</td></tr>
+     *   <tr><td>{@link GeometryType#POINT}</td>  <td>{@code 
org.apache.sis.geometries.Point}</td></tr>
+     *   <tr><td>{@link GeometryType#LINEAR}</td> <td>{@code 
org.apache.sis.geometries.LineString}</td></tr>
+     *   <tr><td>{@link GeometryType#AREAL}</td>  <td>{@code 
org.apache.sis.geometries.Polygon}</td></tr>
+     * </table>
+     */
+    SIS("SIS"),
+
     /**
      * The GeoAPI geometry interfaces.
      * Since GeoAPI interfaces are implementation neutral, the actual 
implementation is currently unspecified
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java
index c173a8cf8c..50dcab95f6 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryFactory.java
@@ -16,12 +16,16 @@
  */
 package org.apache.sis.geometries;
 
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.geometries.conics.Circle;
+import org.apache.sis.geometries.conics.CircularString;
 import org.apache.sis.geometries.math.SampleSystem;
 import org.apache.sis.geometries.math.TupleArray;
+import org.apache.sis.geometries.math.TupleArrays;
 import org.apache.sis.geometries.privy.ArraySequence;
 import org.apache.sis.geometries.privy.DefaultGeometryCollection;
 import org.apache.sis.geometries.privy.DefaultLineString;
@@ -33,15 +37,25 @@ import org.apache.sis.geometries.privy.DefaultMultiSurface;
 import org.apache.sis.geometries.privy.DefaultPoint;
 import org.apache.sis.geometries.privy.DefaultPolygon;
 import org.apache.sis.geometries.privy.DefaultTriangle;
-
+import org.apache.sis.geometries.spirals.Clothoid;
+import org.apache.sis.geometry.wrapper.Capability;
+import org.apache.sis.geometry.wrapper.Dimensions;
+import org.apache.sis.geometry.wrapper.GeometryType;
+import org.apache.sis.geometry.wrapper.GeometryWrapper;
+import org.apache.sis.setup.GeometryLibrary;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
 
 /**
  *
  * @author Johann Sorel (Geomatys)
  */
-public final class GeometryFactory {
+public final class GeometryFactory extends 
org.apache.sis.geometry.wrapper.Geometries<Geometry>{
 
-    private GeometryFactory(){}
+    public static GeometryFactory INSTANCE = new GeometryFactory();
+
+    private GeometryFactory(){
+        super(GeometryLibrary.SIS, Geometry.class, Point.class);
+    }
 
     public static Point createPoint(CoordinateReferenceSystem crs) {
         return new DefaultPoint(crs);
@@ -103,4 +117,142 @@ public final class GeometryFactory {
         return new ArraySequence(attributes);
     }
 
+    // ////////////////////////////////////////////////////////////////////////
+    // org.apache.sis.geometry.wrapper.Geometries methods /////////////////////
+    // ////////////////////////////////////////////////////////////////////////
+
+
+    @Override
+    public Class<?> getGeometryClass(GeometryType type) {
+        switch (type) {
+            case CIRCLE : return Circle.class;
+            case CIRCULARSTRING : return CircularString.class;
+            case CLOTHOID : return Clothoid.class;
+            case COMPOUNDCURVE : return CompoundCurve.class;
+            case CURVE : return Curve.class;
+            case GEOMETRY : return Geometry.class;
+            case GEOMETRYCOLLECTION : return GeometryCollection.class;
+            case LINESTRING : return LineString.class;
+            case MULTICURVE : return MultiCurve.class;
+            case MULTILINESTRING : return MultiLineString.class;
+            case MULTIPOINT : return MultiPoint.class;
+            case MULTIPOLYGON : return MultiPolygon.class;
+            case MULTISURFACE : return MultiSurface.class;
+            case POINT : return Point.class;
+            case POLYGON : return Polygon.class;
+            case POLYHEDRALSURFACE : return PolyhedralSurface.class;
+            case SURFACE : return Surface.class;
+            case TIN : return TIN.class;
+            case TRIANGLE : return Triangle.class;
+            //todo
+            case BREPSOLID :
+            case COMPOUNDSURFACE :
+            case CURVEPOLYGON :
+            case ELLIPTICALCURVE :
+            case GEODESICSTRING :
+            case NURBSCURVE :
+            case SPIRALCURVE :
+            default: return Geometry.class;
+        }
+    }
+
+    @Override
+    public GeometryType getGeometryType(Class<?> type) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public GeometryWrapper castOrWrap(Object geometry) {
+        if (geometry instanceof Wrapper) return (GeometryWrapper) geometry;
+        return new Wrapper((Geometry) geometry);
+    }
+
+    @Override
+    public GeometryWrapper parseWKT(String wkt) throws Exception {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public GeometryWrapper parseWKB(ByteBuffer data) throws Exception {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public boolean supports(Capability feature) {
+        switch (feature) {
+            case Z_COORDINATE : return true;
+            case M_COORDINATE : return true;
+            case SINGLE_PRECISION : return true;
+            default: return false;
+        }
+    }
+
+    @Override
+    public Point createPoint(double x, double y) {
+        return new DefaultPoint(SampleSystem.ofSize(2), x, y);
+    }
+
+    @Override
+    public Point createPoint(double x, double y, double z) {
+        return new DefaultPoint(SampleSystem.ofSize(3), x ,y, z);
+    }
+
+    @Override
+    public Point createPoint(boolean isFloat, Dimensions dimensions, 
DoubleBuffer coordinates) {
+        final ArraySequence points;
+
+        if (!dimensions.hasZ) {
+            final SampleSystem ss = SampleSystem.ofSize(2);
+            if (isFloat) {
+                points = new ArraySequence(TupleArrays.of(ss, (float) 
coordinates.get(0), (float) coordinates.get(1)));
+            } else {
+                points = new ArraySequence(TupleArrays.of(ss, 
coordinates.get(0), coordinates.get(1)));
+            }
+        } else {
+            final SampleSystem ss = SampleSystem.ofSize(3);
+            if (isFloat) {
+                points = new ArraySequence(TupleArrays.of(ss, (float) 
coordinates.get(0), (float) coordinates.get(1), (float) coordinates.get(2)));
+            } else {
+                points = new ArraySequence(TupleArrays.of(ss, 
coordinates.get(0), coordinates.get(1), coordinates.get(2)));
+            }
+        }
+
+        if (dimensions.hasM) {
+            final TupleArray marray;
+            if (isFloat) {
+                marray = TupleArrays.of(SampleSystem.ofSize(1), (float) 
coordinates.get(dimensions.hasZ ? 3 : 2));
+            } else {
+                marray = TupleArrays.of(SampleSystem.ofSize(1), 
coordinates.get(dimensions.hasZ ? 3 : 2));
+            }
+            points.setAttribute("m", marray);
+        }
+
+        return new DefaultPoint(points);
+    }
+
+    @Override
+    public MultiPoint<?> createMultiPoint(boolean isFloat, Dimensions 
dimensions, DoubleBuffer coordinates) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public Geometry createPolyline(boolean polygon, boolean isFloat, 
Dimensions dimensions, DoubleBuffer... coordinates) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public GeometryWrapper createMultiPolygon(Object[] geometries) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public GeometryWrapper createFromComponents(GeometryType type, Object 
components) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    protected GeometryWrapper createWrapper(Geometry geometry) {
+        return new Wrapper(geometry);
+    }
+
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Wrapper.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Wrapper.java
new file mode 100644
index 0000000000..e902842bad
--- /dev/null
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Wrapper.java
@@ -0,0 +1,469 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries;
+
+import java.awt.Shape;
+import java.util.Iterator;
+import java.util.OptionalInt;
+import org.apache.sis.filter.sqlmm.SQLMM;
+import org.apache.sis.geometries.math.Tuple;
+import org.apache.sis.geometries.privy.ArraySequence;
+import org.opengis.util.FactoryException;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.geometry.wrapper.Geometries;
+import org.apache.sis.geometry.wrapper.GeometryType;
+import org.apache.sis.geometry.wrapper.GeometryWrapper;
+import org.apache.sis.util.Debug;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.CoordinateSequence;
+import org.locationtech.jts.geom.Envelope;
+
+// Specific to the geoapi-3.1 and geoapi-4.0 branches:
+import org.opengis.filter.SpatialOperatorName;
+import org.opengis.filter.DistanceOperatorName;
+
+
+/**
+ * The wrapper of SIS geometries.
+ *
+ * @author  Johann Sorel (Geomatys)
+ */
+public final class Wrapper extends GeometryWrapper {
+    /**
+     * The wrapped implementation.
+     */
+    private final Geometry geometry;
+
+    /**
+     * Creates a new wrapper around the given geometry.
+     *
+     * @param  geometry  the geometry to wrap.
+     */
+    Wrapper(final Geometry geometry) {
+        this.geometry = geometry;
+        crs = geometry.getCoordinateReferenceSystem();
+    }
+
+    /**
+     * Creates a new wrapper with the same <abbr>CRS</abbr> than the given 
wrapper.
+     *
+     * @param  source    the source wrapper from which is derived the geometry.
+     * @param  geometry  the geometry to wrap.
+     */
+    private Wrapper(final Wrapper source, final Geometry geometry) {
+        this.geometry = geometry;
+        this.crs = source.crs;
+    }
+
+    /**
+     * Returns the implementation-dependent factory of geometric object.
+     */
+    @Override
+    protected Geometries<Geometry> factory() {
+        return GeometryFactory.INSTANCE;
+    }
+
+    /**
+     * Returns the geometry specified at construction time.
+     */
+    @Override
+    protected Object implementation() {
+        return geometry;
+    }
+
+    /**
+     * Returns the Spatial Reference System Identifier (SRID) if available.
+     * This is <em>not</em> necessarily an EPSG code, even it is common 
practice to use
+     * the same numerical values as EPSG. Note that the absence of SRID does 
not mean
+     * that {@link #getCoordinateReferenceSystem()} would return no CRS.
+     */
+    @Override
+    public OptionalInt getSRID() {
+        return OptionalInt.empty();
+    }
+
+    /**
+     * Sets the coordinate reference system. This method overwrites any 
previous user object.
+     * This is okay for the context in which Apache SIS uses this method, 
which is only for
+     * newly created geometries.
+     */
+    @Override
+    public void setCoordinateReferenceSystem(final CoordinateReferenceSystem 
crs) {
+        super.setCoordinateReferenceSystem(crs);
+        geometry.setCoordinateReferenceSystem(crs);
+    }
+
+    /**
+     * Returns the dimension of the coordinates that define this geometry.
+     */
+    @Override
+    public int getCoordinateDimension() {
+        return getCoordinatesDimension(geometry);
+    }
+
+    /**
+     * Gets the number of dimensions of geometry vertex (sequence of 
coordinate tuples), which can be 2 or 3.
+     *
+     * @param  geometry  the geometry for which to get <em>vertex</em> (not 
topological) dimension.
+     * @return vertex dimension of the given geometry.
+     */
+    private static int getCoordinatesDimension(final Geometry geometry) {
+        return 
geometry.getCoordinateReferenceSystem().getCoordinateSystem().getDimension();
+    }
+
+    /**
+     * Returns the envelope of SIS geometry. Never null, but may be empty.
+     */
+    @Override
+    public GeneralEnvelope getEnvelope() {
+        return new GeneralEnvelope(geometry.getEnvelope());
+    }
+
+    /**
+     * Returns the centroid of the wrapped geometry as a direct position.
+     */
+    @Override
+    public DirectPosition getCentroid() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * If the wrapped geometry is a point, returns its coordinates. Otherwise 
returns {@code null}.
+     * If non-null, the returned array may have a length of 2 or 3.
+     */
+    @Override
+    public double[] getPointCoordinates() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Returns all coordinate tuples in the wrapped geometry.
+     * This method is currently used for testing purpose only.
+     */
+    @Debug
+    @Override
+    public double[] getAllCoordinates() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Merges a sequence of points or paths after the wrapped geometry.
+     *
+     * @throws ClassCastException if an element in the iterator is not a SIS 
geometry.
+     */
+    @Override
+    public Geometry mergePolylines(final Iterator<?> polylines) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Applies a filter predicate between this geometry and another geometry.
+     * This method assumes that the two geometries are in the same CRS (this 
is not verified).
+     *
+     * <p><b>Note:</b> No operations are supported at this time.</p>
+     *
+     * @throws ClassCastException if the given wrapper is not for the same 
geometry library.
+     */
+    @Override
+    protected boolean predicateSameCRS(final SpatialOperatorName type, final 
GeometryWrapper other) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Applies a filter predicate between this geometry and another geometry 
within a given distance.
+     * This method assumes that the two geometries are in the same CRS and 
that the unit of measurement
+     * is the same for {@code distance} than for axes (this is not verified).
+     *
+     * @throws ClassCastException if the given wrapper is not for the same 
geometry library.
+     */
+    @Override
+    protected boolean predicateSameCRS(final DistanceOperatorName type,
+                    final GeometryWrapper other, final double distance)
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Applies a SQLMM operation on this geometry.
+     *
+     * @param  operation  the SQLMM operation to apply.
+     * @param  other      the other geometry, or {@code null} if the operation 
requires only one geometry.
+     * @param  argument   an operation-specific argument, or {@code null} if 
not applicable.
+     * @return result of the specified operation.
+     * @throws ClassCastException if the operation can only be executed on 
some specific argument types
+     *         (for example geometries that are polylines) and one of the 
argument is not of that type.
+     */
+    @Override
+    protected Object operationSameCRS(final SQLMM operation, final 
GeometryWrapper other, final Object argument) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Converts the wrapped geometry to the specified type.
+     * If the geometry is already of that type, it is returned unchanged.
+     * Otherwise coordinates are copied in a new geometry of the requested 
type.
+     *
+     * <p>The following conversions are illegal and will cause an {@link 
IllegalArgumentException} to be thrown:</p>
+     * <ul>
+     *   <li>From point to polyline or polygon.</li>
+     *   <li>From geometry collection (except multi-point) to polyline.</li>
+     *   <li>From geometry collection (except multi-point and multi-line 
string) to polygon.</li>
+     *   <li>From geometry collection containing nested collections.</li>
+     * </ul>
+     *
+     * The conversion from {@link MultiLineString} to {@link Polygon} is 
defined as following:
+     * the first {@link LineString} is taken as the exterior {@link 
LinearRing} and all others
+     * {@link LineString}s are interior {@link LinearRing}s.
+     * This rule is defined by some SQLMM operations.
+     *
+     * @param  target  the desired type.
+     * @return the converted geometry.
+     * @throws IllegalArgumentException if the geometry cannot be converted to 
the specified type.
+     */
+    @Override
+    public GeometryWrapper toGeometryType(final GeometryType target) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Transforms this geometry using the given coordinate operation.
+     * If the operation is {@code null}, then the geometry is returned 
unchanged.
+     * If the geometry uses a different CRS than the source CRS of the given 
operation
+     * and {@code validate} is {@code true},
+     * then a new operation to the target CRS will be automatically computed.
+     *
+     * @param  operation  the coordinate operation to apply, or {@code null}.
+     * @param  validate   whether to validate the operation source CRS.
+     * @throws FactoryException if transformation to the target CRS cannot be 
found.
+     * @throws TransformException if the geometry cannot be transformed.
+     */
+    @Override
+    public GeometryWrapper transform(final CoordinateOperation operation, 
final boolean validate)
+            throws FactoryException, TransformException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Transforms this geometry to the specified Coordinate Reference System 
(CRS).
+     * If the given CRS is null or is the same CRS as current one, the 
geometry is returned unchanged.
+     *
+     * @param  targetCRS  the target coordinate reference system, or {@code 
null}.
+     * @return the transformed geometry (may be the same geometry instance), 
or {@code null}.
+     * @throws TransformException if this geometry cannot be transformed.
+     */
+    @Override
+    public GeometryWrapper transform(final CoordinateReferenceSystem 
targetCRS) throws TransformException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Transforms this geometry using the given transform.
+     * If the transform is {@code null}, then the geometry is returned 
unchanged.
+     *
+     * @param  transform  the math transform to apply, or {@code null}.
+     * @return the transformed geometry (may be the same geometry instance, 
but never {@code null}).
+     * @throws TransformException if the geometry cannot be transformed.
+     */
+    @Override
+    public GeometryWrapper transform(final MathTransform transform) throws 
FactoryException, TransformException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Returns a view over the SIS geometry as a Java2D shape. Changes in the 
SIS geometry
+     * after this method call may be reflected in the returned shape in an 
unspecified way.
+     *
+     * @return a view over the geometry as a Java2D shape.
+     */
+    @Override
+    public Shape toJava2D() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    /**
+     * Returns the WKT representation of the wrapped geometry.
+     */
+    @Override
+    public String formatWKT(final double flatness) {
+        return geometry.asText();
+    }
+
+    /**
+     * View SIS Geometry as a JTS Geometry.
+     * Only the matching JTS geometry types are supported.
+     * The created geometry references the original geometry PointSequences, 
so modifications
+     * are forwarded to the original but all metadata change, like the CRS, 
will not be preserved if changed
+     * after the JTS view has been made.
+     *
+     * @param gf optional creation factory.
+     * @return JTS geometry view of the given geometry
+     */
+    public org.locationtech.jts.geom.Geometry 
asJTS(org.locationtech.jts.geom.GeometryFactory gf) {
+        return asJTS(geometry, gf);
+    }
+
+    /**
+     * View SIS Geometry as a JTS Geometry.
+     * Only the matching JTS geometry types are supported.
+     * The created geometry references the original geometry PointSequences, 
so modifications
+     * are forwarded to the original but all metadata change, like the CRS, 
will not be preserved if changed
+     * after the JTS view has been made.
+     *
+     * @param geometry to convert
+     * @param gf optional creation factory.
+     * @return JTS geometry view of the given geometry
+     */
+    public static org.locationtech.jts.geom.Geometry asJTS(Geometry geometry, 
org.locationtech.jts.geom.GeometryFactory gf) {
+        if (gf == null) gf = new org.locationtech.jts.geom.GeometryFactory();
+        final org.locationtech.jts.geom.Geometry jts;
+
+        if (geometry instanceof Point cdt){
+            jts = gf.createPoint(new JTSSequence(cdt.asPointSequence()));
+        } else if (geometry instanceof LinearRing cdt) {
+            jts = gf.createLinearRing(new JTSSequence(cdt.getPoints()));
+        } else if (geometry instanceof LineString cdt) {
+            jts = gf.createLineString(new JTSSequence(cdt.getPoints()));
+        } else if (geometry instanceof Polygon cdt) {
+            final org.locationtech.jts.geom.LinearRing exterior = 
(org.locationtech.jts.geom.LinearRing) asJTS(cdt.getExteriorRing(), gf);
+            final org.locationtech.jts.geom.LinearRing[] inners = new 
org.locationtech.jts.geom.LinearRing[cdt.getNumInteriorRing()];
+            for (int i = 0; i < inners.length; i++) {
+                inners[i] = (org.locationtech.jts.geom.LinearRing) 
asJTS(cdt.getInteriorRingN(i), gf);
+            }
+            jts = gf.createPolygon(exterior, inners);
+        } else if (geometry instanceof MultiPoint<?> cdt) {
+            jts = gf.createMultiPoint(new JTSSequence(cdt.asPointSequence()));
+        } else if (geometry instanceof MultiLineString cdt) {
+            final org.locationtech.jts.geom.LineString[] children = new 
org.locationtech.jts.geom.LineString[cdt.getNumGeometries()];
+            for (int i = 0; i < children.length; i++) {
+                children[i] = (org.locationtech.jts.geom.LineString) 
asJTS(cdt.getGeometryN(i), gf);
+            }
+            jts = gf.createMultiLineString(children);
+        } else if (geometry instanceof MultiPolygon cdt) {
+            final org.locationtech.jts.geom.Polygon[] children = new 
org.locationtech.jts.geom.Polygon[cdt.getNumGeometries()];
+            for (int i = 0; i < children.length; i++) {
+                children[i] = (org.locationtech.jts.geom.Polygon) 
asJTS(cdt.getGeometryN(i), gf);
+            }
+            jts = gf.createMultiPolygon(children);
+        } else if (geometry instanceof MultiPolygon cdt) {
+            final org.locationtech.jts.geom.Geometry[] children = new 
org.locationtech.jts.geom.Geometry[cdt.getNumGeometries()];
+            for (int i = 0; i < children.length; i++) {
+                children[i] = (org.locationtech.jts.geom.Geometry) 
asJTS(cdt.getGeometryN(i), gf);
+            }
+            jts = gf.createGeometryCollection(children);
+        } else {
+            throw new UnsupportedOperationException("Geometry type " + 
geometry.getClass().getName() + " has no match in JTS library");
+        }
+
+        jts.setUserData(geometry.getCoordinateReferenceSystem());
+        return jts;
+    }
+    /**
+     * Decorate a PointSequence as a JTS CoordinateSequence
+     */
+    private static class JTSSequence implements CoordinateSequence {
+
+        private final PointSequence ps;
+
+        public JTSSequence(PointSequence ps) {
+            this.ps = ps;
+        }
+
+        @Override
+        public int getDimension() {
+            return ps.getDimension();
+        }
+
+        @Override
+        public Coordinate getCoordinate(int i) {
+            return getCoordinateCopy(i);
+        }
+
+        @Override
+        public Coordinate getCoordinateCopy(int i) {
+            final Coordinate crd = createCoordinate();
+            getCoordinate(i, crd);
+            return crd;
+        }
+
+        @Override
+        public void getCoordinate(int idx, Coordinate crdnt) {
+            Tuple tuple = ps.getPosition(idx);
+            for (int i = 0; i < tuple.getDimension(); i++) {
+                crdnt.setOrdinate(i, tuple.get(i));
+            }
+        }
+
+        @Override
+        public double getX(int i) {
+            return ps.getPosition(i).get(0);
+        }
+
+        @Override
+        public double getY(int i) {
+            return ps.getPosition(i).get(1);
+        }
+
+        @Override
+        public double getOrdinate(int i, int i1) {
+            return ps.getPosition(i).get(i1);
+        }
+
+        @Override
+        public int size() {
+            return ps.size();
+        }
+
+        @Override
+        public void setOrdinate(int i, int i1, double d) {
+            Tuple position = ps.getPosition(i);
+            position.set(i1, d);
+            ps.setPosition(i, position);
+        }
+
+        @Override
+        public Coordinate[] toCoordinateArray() {
+            final Coordinate[] coords = new Coordinate[ps.size()];
+            for (int i = 0;  i < coords.length; i++) {
+                coords[i] = getCoordinateCopy(i);
+            }
+            return coords;
+        }
+
+        @Override
+        public Envelope expandEnvelope(Envelope envlp) {
+            final org.opengis.geometry.Envelope env = ps.getEnvelope();
+            envlp.expandToInclude(new Envelope(env.getMinimum(0), 
env.getMaximum(0), env.getMinimum(1), env.getMaximum(1)));
+            return envlp;
+        }
+
+        @Override
+        public CoordinateSequence copy() {
+            final PointSequence cp = new 
ArraySequence(ps.getAttributeArray(AttributesType.ATT_POSITION));
+            return new JTSSequence(cp);
+        }
+
+        public Object clone(){
+            return copy();
+        }
+    }
+
+}

Reply via email to