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 0d9d0a783d feat(Geometry): add jts fallbacks for getlength, getarea 
and others
0d9d0a783d is described below

commit 0d9d0a783d5b6873784a3eb0a81e963c32d29bc7
Author: jsorel <[email protected]>
AuthorDate: Wed Oct 7 10:32:58 2026 +0200

    feat(Geometry): add jts fallbacks for getlength, getarea and others
---
 .../main/org/apache/sis/geometries/Geometries.java | 68 ++++++++++++++++++++
 .../main/org/apache/sis/geometries/Surface.java    | 10 +--
 .../internal/shared/AbstractGeometry.java          | 34 ++++++++++
 .../internal/shared/DefaultGeometryCollection.java | 44 +++++++++++++
 .../internal/shared/DefaultLineString.java         | 42 ++++++++++++
 .../internal/shared/DefaultLinearRing.java         | 10 +++
 .../internal/shared/DefaultMultiPoint.java         | 44 +++++++++++++
 .../internal/shared/DefaultMultiSurface.java       | 11 ++++
 .../geometries/internal/shared/DefaultPolygon.java | 74 +++++++++++++++++++++-
 .../geometries/operation/GeometryProcessor.java    | 27 ++++----
 .../sis/geometries/operation/BufferTest.java       | 42 ++++++++++--
 11 files changed, 376 insertions(+), 30 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
index 205bb281a4..bc4b9bd5f0 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
@@ -697,6 +697,74 @@ public final class Geometries {
         return primitive;
     }
 
+    /**
+     * Returns the unit of measurement in which the coordinates of the given 
geometry are expressed,
+     * taken from the first axis of its coordinate system. This is the unit in 
which lengths computed
+     * on that geometry, such as a {@linkplain Curve#getLength() curve length} 
or a
+     * {@linkplain Surface#getPerimeter() perimeter}, are expressed.
+     *
+     * @param  geom  the geometry from which to get the coordinate unit.
+     * @return unit of the first coordinate system axis, or {@link 
Units#UNITY} if the geometry
+     *         has no coordinate reference system.
+     */
+    @SuppressWarnings("rawtypes")
+    public static Unit getLinearUnit(final Geometry geom) {
+        return productOfAxisUnits(geom, 1);
+    }
+
+    /**
+     * Returns the unit in which an {@linkplain Surface#getArea() area} 
computed on the given
+     * geometry is expressed, as the product of the units of the two first 
coordinate system axes.
+     *
+     * @param  geom  the geometry from which to get the area unit.
+     * @return product of the units of the two first axes, or {@link 
Units#UNITY} if the geometry
+     *         has no coordinate reference system or if that system is not at 
least 2-dimensional.
+     */
+    @SuppressWarnings("rawtypes")
+    public static Unit getAreaUnit(final Geometry geom) {
+        return productOfAxisUnits(geom, 2);
+    }
+
+    /**
+     * Returns the unit in which a {@linkplain Solid#getVolume() volume} 
computed on the given
+     * geometry is expressed, as the product of the units of the three first 
coordinate system axes.
+     *
+     * @param  geom  the geometry from which to get the volume unit.
+     * @return product of the units of the three first axes, or {@link 
Units#UNITY} if the geometry
+     *         has no coordinate reference system or if that system is not at 
least 3-dimensional.
+     */
+    @SuppressWarnings("rawtypes")
+    public static Unit getVolumeUnit(final Geometry geom) {
+        return productOfAxisUnits(geom, 3);
+    }
+
+    /**
+     * Returns the product of the units of the {@code n} first axes of the 
coordinate system of
+     * the given geometry. Each axis is read separately because nothing 
requires the axes of a
+     * coordinate system to share a unit.
+     *
+     * @param  geom  the geometry from which to get the units.
+     * @param  n     number of leading axes to multiply.
+     * @return product of the units of the {@code n} first axes, or {@link 
Units#UNITY} if the
+     *         geometry has no coordinate reference system or has less than 
{@code n} dimensions.
+     */
+    @SuppressWarnings("rawtypes")
+    private static Unit productOfAxisUnits(final Geometry geom, final int n) {
+        final CoordinateReferenceSystem crs = 
geom.getCoordinateReferenceSystem();
+        if (crs == null) {
+            return Units.UNITY;
+        }
+        final CoordinateSystem cs = crs.getCoordinateSystem();
+        if (cs.getDimension() < n) {
+            return Units.UNITY;
+        }
+        Unit unit = cs.getAxis(0).getUnit();
+        for (int i = 1; i < n; i++) {
+            unit = unit.multiply(cs.getAxis(i).getUnit());
+        }
+        return unit;
+    }
+
     /**
      * Returns the sum of the two given quantities, expressed in the unit of 
the first one,
      * or dimensionless if either operand is dimensionless.
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Surface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Surface.java
index c6bffd8bde..cf1db7bac4 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Surface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Surface.java
@@ -86,11 +86,11 @@ public sealed interface Surface extends Orientable
     /**
      * The area of this Surface, as measured in the spatial reference system 
of this Surface.
      *
-     * <p>TODO / Limitation: implementations label the returned quantity in 
square metres, but its
-     * magnitude is computed in the units of the coordinate system axes. On a 
geographic coordinate
-     * reference system that magnitude is therefore an amount of square 
degrees reported as square
-     * metres. Computing a true area on the reference surface, as required by 
ISO 19107 REQ. 11,
-     * remains to be done.</p>
+     * <p>TODO / Limitation: the area is computed as a planar area in the 
units of the coordinate
+     * system axes, and the returned quantity is labelled with the square of 
the unit of the first
+     * axis. On a geographic coordinate reference system the result is 
therefore an amount of square
+     * degrees, reported as such. Computing a true area on the reference 
surface, as required by
+     * ISO 19107 REQ. 11, remains to be done.</p>
      *
      * <p>Difference with ISO-19107, the Area type has been changed to 
Quantity to
      * handle temporal geometries and crs-less geometries.</p>
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/AbstractGeometry.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/AbstractGeometry.java
index 579e37c638..88d7c74fac 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/AbstractGeometry.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/AbstractGeometry.java
@@ -19,6 +19,7 @@ package org.apache.sis.geometries.internal.shared;
 import java.util.HashMap;
 import java.util.Map;
 import org.opengis.geometry.Envelope;
+import org.apache.sis.geometries.Geometries;
 import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometry.GeneralEnvelope;
 
@@ -45,6 +46,39 @@ public abstract non-sealed class AbstractGeometry implements 
Geometry {
         return asText();
     }
 
+    /**
+     * Returns a view of this geometry as a JTS geometry, for delegating to 
JTS an operation
+     * which is not yet implemented in this package. The view shares the 
coordinates of this
+     * geometry, no copy is performed.
+     *
+     * <p>Geometry types which have no JTS equivalent, such as the parametric 
curves and the
+     * solids, cannot be delegated this way. For them this method reports the 
operation as
+     * unsupported, which is the contract of the operations relying on this 
fallback.</p>
+     *
+     * @return this geometry seen as a JTS geometry.
+     * @throws UnsupportedOperationException if this geometry has no JTS 
equivalent.
+     */
+    protected final org.locationtech.jts.geom.Geometry asJTS() {
+        try {
+            return Geometries.asJTS(this, false, null);
+        } catch (IllegalArgumentException e) {
+            throw new UnsupportedOperationException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Converts back to a geometry of this package the result of an operation 
delegated to JTS.
+     * The JTS geometries produced by such an operation carry no reference 
system, therefore the
+     * system of this geometry is assigned to the result.
+     *
+     * @param  result  the geometry computed by JTS.
+     * @return the result as a geometry of this package.
+     */
+    protected final Geometry fromJTS(final org.locationtech.jts.geom.Geometry 
result) {
+        result.setUserData(getCoordinateReferenceSystem());
+        return Geometries.fromJTS(result, true);
+    }
+
     /**
      * Returns the union of the envelopes of the given geometries,
      * or {@code null} if there is nothing to compute a union of.
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java
index ed109a5bd9..518b81ed1b 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultGeometryCollection.java
@@ -19,6 +19,8 @@ package org.apache.sis.geometries.internal.shared;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryCollection;
+import org.apache.sis.geometries.GeometryFactory;
+import org.apache.sis.geometries.Point;
 
 
 /**
@@ -72,4 +74,46 @@ public non-sealed class DefaultGeometryCollection<T extends 
Geometry> extends Ab
         return geometries[n];
     }
 
+    @Override
+    public Point getCentroid() {
+        if (isEmpty()) {
+            // The centroid of the empty set is undefined.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getCentroid());
+    }
+
+    @Override
+    public Point getRepresentativePoint() {
+        if (isEmpty()) {
+            // The empty set has no interior position.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getInteriorPoint());
+    }
+
+    @Override
+    public Geometry boundary() {
+        if (isEmpty()) {
+            // The boundary of the empty set is empty.
+            return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+        }
+        //TODO : fallback on JTS until implemented
+        return fromJTS(asJTS().getBoundary());
+    }
+
+    @Override
+    public boolean isSimple() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isSimple();
+    }
+
+    @Override
+    public boolean isValid() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isValid();
+    }
+
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLineString.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLineString.java
index 2e4388bee2..762200d7e1 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLineString.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLineString.java
@@ -16,8 +16,12 @@
  */
 package org.apache.sis.geometries.internal.shared;
 
+import javax.measure.Quantity;
 import org.apache.sis.geometries.DataPoints;
+import org.apache.sis.geometries.Geometries;
+import org.apache.sis.geometries.Point;
 import org.apache.sis.geometries.curve.LineString;
+import org.apache.sis.measure.Quantities;
 
 
 /**
@@ -42,4 +46,42 @@ public non-sealed class DefaultLineString extends 
AbstractGeometry implements Li
         return points;
     }
 
+    @Override
+    public Quantity<?> getLength() {
+        //TODO : fallback on JTS until implemented
+        return Quantities.create(asJTS().getLength(), 
Geometries.getLinearUnit(this));
+    }
+
+    @Override
+    public Point getCentroid() {
+        if (isEmpty()) {
+            // The centroid of the empty set is undefined.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getCentroid());
+    }
+
+    @Override
+    public Point getRepresentativePoint() {
+        if (isEmpty()) {
+            // The empty set has no interior position.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getInteriorPoint());
+    }
+
+    @Override
+    public boolean isSimple() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isSimple();
+    }
+
+    @Override
+    public boolean isValid() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isValid();
+    }
+
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLinearRing.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLinearRing.java
index 4c2433550e..bbc405f4a6 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLinearRing.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultLinearRing.java
@@ -31,4 +31,14 @@ public non-sealed class DefaultLinearRing extends 
DefaultLineString implements L
         super(points);
     }
 
+    /**
+     * Returns {@code true}: a linear ring is simple by definition.
+     * This restores the value defined by {@link LinearRing#isSimple()}, which 
the
+     * JTS fallback inherited from {@link DefaultLineString} would otherwise 
hide.
+     */
+    @Override
+    public boolean isSimple() {
+        return true;
+    }
+
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java
index f082f0c1d5..7faad51e6b 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiPoint.java
@@ -20,6 +20,8 @@ import java.util.Objects;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.DataPoints;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.Point;
 import org.apache.sis.geometries.DataPointsType;
 import org.apache.sis.geometries.point.MultiPoint;
@@ -72,6 +74,48 @@ public non-sealed class DefaultMultiPoint extends 
AbstractGeometry implements Mu
         return points;
     }
 
+    @Override
+    public Point getCentroid() {
+        if (isEmpty()) {
+            // The centroid of the empty set is undefined.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getCentroid());
+    }
+
+    @Override
+    public Point getRepresentativePoint() {
+        if (isEmpty()) {
+            // The empty set has no interior position.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getInteriorPoint());
+    }
+
+    @Override
+    public Geometry boundary() {
+        if (isEmpty()) {
+            // The boundary of the empty set is empty.
+            return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+        }
+        //TODO : fallback on JTS until implemented
+        return fromJTS(asJTS().getBoundary());
+    }
+
+    @Override
+    public boolean isSimple() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isSimple();
+    }
+
+    @Override
+    public boolean isValid() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isValid();
+    }
+
     @Override
     public int hashCode() {
         return 13 * Objects.hashCode(points);
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiSurface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiSurface.java
index 94ae975413..6d66de5cc8 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiSurface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultMultiSurface.java
@@ -17,6 +17,7 @@
 package org.apache.sis.geometries.internal.shared;
 
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.geometries.Point;
 import org.apache.sis.geometries.Surface;
 import org.apache.sis.geometries.surface.MultiSurface;
 
@@ -35,4 +36,14 @@ public non-sealed class DefaultMultiSurface<T extends 
Surface> extends DefaultGe
         super(fallbackCRS, geometries);
     }
 
+    /**
+     * Returns the same point as {@link #getRepresentativePoint()}, which is 
the name
+     * given by OGC Simple Feature Access to the operation ISO 19107 calls the
+     * representative point.
+     */
+    @Override
+    public Point getPointOnSurface() {
+        return getRepresentativePoint();
+    }
+
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java
index f9e559f428..bef2c94d4f 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolygon.java
@@ -18,16 +18,17 @@ package org.apache.sis.geometries.internal.shared;
 
 import java.util.List;
 import java.util.Objects;
-import org.locationtech.jts.geom.GeometryFactory;
 import javax.measure.Quantity;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.Geometries;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryFactory;
+import org.apache.sis.geometries.Point;
 import org.apache.sis.geometries.curve.LinearRing;
 import org.apache.sis.geometries.surface.Polygon;
 import org.apache.sis.measure.Quantities;
-import org.apache.sis.measure.Units;
 
 
 /**
@@ -89,7 +90,74 @@ public non-sealed class DefaultPolygon extends 
AbstractGeometry implements Polyg
     @Override
     public Quantity<?> getArea() {
         //TODO : fallback on JTS until implemented
-        return Quantities.create(Geometries.asJTS(this, false, new 
GeometryFactory()).getArea(), Units.SQUARE_METRE);
+        return Quantities.create(asJTS().getArea(), 
Geometries.getAreaUnit(this));
+    }
+
+    @Override
+    public Quantity<?> getPerimeter() {
+        //TODO : fallback on JTS until implemented
+        return Quantities.create(asJTS().getLength(), 
Geometries.getLinearUnit(this));
+    }
+
+    @Override
+    public Point getCentroid() {
+        if (isEmpty()) {
+            // The centroid of the empty set is undefined.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getCentroid());
+    }
+
+    @Override
+    public Point getPointOnSurface() {
+        if (isEmpty()) {
+            // The empty set has no interior position.
+            return null;
+        }
+        //TODO : fallback on JTS until implemented
+        return (Point) fromJTS(asJTS().getInteriorPoint());
+    }
+
+    /**
+     * Returns the same point as {@link #getPointOnSurface()}, which is the 
name
+     * given by OGC Simple Feature Access to the operation ISO 19107 calls the
+     * representative point.
+     */
+    @Override
+    public Point getRepresentativePoint() {
+        return getPointOnSurface();
+    }
+
+    @Override
+    public Geometry getBoundary() {
+        if (isEmpty()) {
+            // The boundary of the empty set is empty.
+            return GeometryFactory.createEmpty(getCoordinateReferenceSystem());
+        }
+        //TODO : fallback on JTS until implemented
+        return fromJTS(asJTS().getBoundary());
+    }
+
+    /**
+     * Returns the same geometry as {@link #getBoundary()}, which is the name 
given by
+     * {@link org.apache.sis.geometries.Surface} to the same ISO 19107 
operation.
+     */
+    @Override
+    public Geometry boundary() {
+        return getBoundary();
+    }
+
+    @Override
+    public boolean isSimple() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isSimple();
+    }
+
+    @Override
+    public boolean isValid() {
+        //TODO : fallback on JTS until implemented
+        return asJTS().isValid();
     }
 
 }
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 1ddc1a0fdf..7aa551d26a 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
@@ -25,7 +25,6 @@ import java.util.Map.Entry;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import javax.measure.Quantity;
-import javax.measure.Unit;
 import static org.opengis.annotation.Specification.ISO_19107;
 import org.opengis.annotation.UML;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -82,7 +81,9 @@ public final class GeometryProcessor {
             // There is no position to grow a buffer around, whatever the 
radius.
             return geom;
         }
-        throw new UnsupportedOperationException();
+
+        //TODO : fallback on JTS until implemented, this loss the attributes !
+        return fromJTS(jts(geom).buffer(radius.getValue().doubleValue()), 
geom);
     }
 
     /**
@@ -122,11 +123,11 @@ public final class GeometryProcessor {
      * Because the geometries are closed, it is possible to find a point on 
each geometric object involved, such that
      * the distance between these 2 points is the returned distance between 
their geometric objects.
      *
-     * <p>TODO / Limitation: the returned quantity is labelled in metres, but 
its magnitude is the plain
-     * Pythagorean distance computed in the units of the coordinate system 
axes. On a geographic
-     * coordinate reference system that magnitude is therefore an amount of 
degrees reported as
-     * metres. Computing a true geodesic distance on the reference surface, as 
required by
-     * ISO 19107 REQ. 11, remains to be done.</p>
+     * <p>TODO / Limitation: the magnitude is the plain Pythagorean distance 
computed in the units
+     * of the coordinate system axes, and the returned quantity is labelled 
with the unit of the
+     * first axis. On a geographic coordinate reference system the result is 
therefore an amount
+     * of degrees, reported as such. Computing a true geodesic distance on the 
reference surface,
+     * as required by ISO 19107 REQ. 11, remains to be done.</p>
      *
      * <p>Difference with ISO-19107, the Length type has been changed to 
Quantity to
      * handle temporal geometries and crs-less geometries.</p>
@@ -143,11 +144,12 @@ public final class GeometryProcessor {
         }
         if (geom1 instanceof Point pt1) {
             if (geom2 instanceof Point pt2) {
-                return Quantities.create(Distance.distance(pt1, pt2), 
getUnit(pt1));
+                return Quantities.create(Distance.distance(pt1, pt2), 
Geometries.getLinearUnit(pt1));
             }
         }
 
-        throw new UnsupportedOperationException();
+        //TODO : fallback on JTS until implemented
+        return Quantities.create(jts(geom1).distance(jts(geom2)), 
Geometries.getLinearUnit(geom1));
     }
 
     /**
@@ -615,11 +617,4 @@ public final class GeometryProcessor {
         return Geometries.fromJTS(result, true);
     }
 
-    private static Unit getUnit(Geometry geometry) {
-        return getUnit(geometry.getCoordinateReferenceSystem());
-    }
-
-    private static Unit getUnit(CoordinateReferenceSystem crs) {
-        return crs.getCoordinateSystem().getAxis(0).getUnit();
-    }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/BufferTest.java
 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/BufferTest.java
index 6342e20221..ab33f01b8f 100644
--- 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/BufferTest.java
+++ 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/BufferTest.java
@@ -18,6 +18,7 @@ package org.apache.sis.geometries.operation;
 
 import javax.measure.Quantity;
 import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.Surface;
 import org.apache.sis.measure.Quantities;
 import org.apache.sis.measure.Units;
 import static org.apache.sis.geometries.operation.TestData.EMPTY_1;
@@ -25,7 +26,10 @@ import static 
org.apache.sis.geometries.operation.TestData.POINT_A;
 
 // Test dependencies
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import org.junit.jupiter.api.Test;
 
 
@@ -62,12 +66,7 @@ public class BufferTest {
         new TestCase(EMPTY_1, Quantities.create( 10, Units.METRE), EMPTY_1, 
null),
         new TestCase(EMPTY_1, Quantities.create(  0, Units.METRE), EMPTY_1, 
null),
         new TestCase(EMPTY_1, Quantities.create(-10, Units.METRE), EMPTY_1, 
null),
-        new TestCase(EMPTY_1, Quantities.create( 10, Units.UNITY), EMPTY_1, 
null),
-        /*
-         * TODO
-         */
-        new TestCase(POINT_A, Quantities.create( 10, Units.METRE), null, 
UnsupportedOperationException.class),
-        new TestCase(POINT_A, Quantities.create(  0, Units.METRE), null, 
UnsupportedOperationException.class)
+        new TestCase(EMPTY_1, Quantities.create( 10, Units.UNITY), EMPTY_1, 
null)
     };
 
     /**
@@ -87,4 +86,35 @@ public class BufferTest {
             }
         }
     }
+
+    /**
+     * Tests that growing a buffer around a point gives a surface 
approximating a disk.
+     * The operation is delegated to JTS, which approximates the disk by a 
polygon inscribed
+     * in it. The area of that polygon is therefore slightly less than the 
area of the disk,
+     * by an amount which depends on the number of segments used by JTS for 
each quadrant.
+     * This test verifies only that the result is close to the disk, not the 
exact number
+     * of segments.
+     */
+    @Test
+    public void testBufferOfPoint() {
+        final double radius = 10;
+        final Geometry result = new GeometryProcessor().buffer(POINT_A, 
Quantities.create(radius, Units.METRE));
+        assertFalse(result.isEmpty(), "The buffer of a point with a positive 
radius is not empty.");
+
+        final Surface surface = assertInstanceOf(Surface.class, result, "The 
buffer of a point is a surface.");
+        final double area = surface.getArea().getValue().doubleValue();
+        final double disk = Math.PI * radius * radius;
+        assertTrue(area <= disk, () -> "Inscribed polygon area " + area + " 
cannot exceed disk area " + disk);
+        assertTrue(area >= 0.95 * disk, () -> "Area " + area + " is too far 
from the disk area " + disk);
+    }
+
+    /**
+     * Tests that a buffer of radius zero around a point gives an empty 
geometry:
+     * a point has no surface to preserve.
+     */
+    @Test
+    public void testBufferOfPointWithZeroRadius() {
+        final Geometry result = new GeometryProcessor().buffer(POINT_A, 
Quantities.create(0, Units.METRE));
+        assertTrue(result.isEmpty(), "The buffer of a point with a radius of 
zero is empty.");
+    }
 }

Reply via email to