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

commit 48ec4dd86222c7a0c03b0ef2eab9507904310b86
Author: jsorel <[email protected]>
AuthorDate: Wed Oct 14 11:00:22 2026 +0200

    feat(Geometry): implement closed surfaces boundary method
---
 .../main/org/apache/sis/geometries/Geometry.java   |   6 +-
 .../main/org/apache/sis/geometries/HyperPlane.java |   5 +-
 .../main/org/apache/sis/geometries/Plane.java      |   5 +-
 .../main/org/apache/sis/geometries/Primitive.java  |   6 +-
 .../geometries/internal/shared/DefaultCapsule.java |   6 --
 .../internal/shared/DefaultCylinder.java           |  19 +++-
 .../internal/shared/DefaultEllipsoid.java          |   6 --
 .../geometries/internal/shared/DefaultSphere.java  |   6 --
 .../org/apache/sis/geometries/surface/Capsule.java |  10 ++
 .../apache/sis/geometries/surface/Cylinder.java    | 112 ++++++++++++++++++++-
 .../apache/sis/geometries/surface/Ellipsoid.java   |  10 ++
 .../org/apache/sis/geometries/surface/Sphere.java  |  10 ++
 12 files changed, 171 insertions(+), 30 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometry.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometry.java
index 150c5239b5..5d5717c340 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometry.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometry.java
@@ -276,14 +276,16 @@ public sealed interface Geometry
      *       boundary, and in the interior those lying on more than one.</li>
      * </ul>
      *
+     * <p>The default implementation returns {@link BoundaryType#MOD_2}, the 
rule of OGC Simple Feature
+     * Access. The three rules agree on geometries which are not 
aggregates.</p>
+     *
      * @return rule used to compute the boundary of this geometry.
      *
      * @see ISO 19107:2019 - 6.4.3, 10.8.3
      */
     @UML(identifier="boundaryType", specification=ISO_19107)
     default BoundaryType getBoundaryType() {
-        //TODO remove this method default when all classes implement it.
-        throw new UnsupportedOperationException();
+        return BoundaryType.MOD_2;
     }
 
     /**
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
index 74627f4640..ecff5d2b03 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
@@ -149,9 +149,12 @@ public final class HyperPlane extends AbstractGeometry{
         return points.getCoordinateReferenceSystem();
     }
 
+    /**
+     * Returns the empty geometry: a hyperplane extends to infinity in all its 
directions, so it has no edge.
+     */
     @Override
     public Geometry getBoundary() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return 
GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
     }
 
     @Override
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
index 62cdc24f30..3bd323154a 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
@@ -210,9 +210,12 @@ public final class Plane extends AbstractGeometry{
         return points.getCoordinateReferenceSystem();
     }
 
+    /**
+     * Returns the empty geometry: a plane extends to infinity in all its 
directions, so it has no edge.
+     */
     @Override
     public Geometry getBoundary() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return 
GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
     }
 
     @Override
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Primitive.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Primitive.java
index b4bac83149..8b1d49a277 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Primitive.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Primitive.java
@@ -95,12 +95,14 @@ public sealed interface Primitive extends Geometry
      *   <li>For a surface or a solid, the order may be ignored.</li>
      * </ul>
      *
+     * <p>The default implementation returns an empty list, for a primitive 
which is not
+     * decomposed in smaller ones.</p>
+     *
      * @return segments of this primitive, possibly empty.
      *
      * @see ISO 19107:2019 - 6.4.11.2
      */
     default List<Primitive> getSegments() {
-        //TODO
-        throw new UnsupportedOperationException();
+        return List.of();
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCapsule.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCapsule.java
index 1ffdcb304e..d33f5c06e2 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCapsule.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCapsule.java
@@ -19,7 +19,6 @@ package org.apache.sis.geometries.internal.shared;
 import java.util.Objects;
 import javax.measure.Quantity;
 import org.apache.sis.geometries.DataPoints;
-import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.surface.Capsule;
 import org.apache.sis.maths.NDArrays;
@@ -121,11 +120,6 @@ public non-sealed class DefaultCapsule extends 
AbstractGeometry implements Capsu
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
-    @Override
-    public Geometry getBoundary() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
     @Override
     public boolean equals(Object obj) {
         if (obj == null) {
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCylinder.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCylinder.java
index b7405ea923..cffd3f385f 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCylinder.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCylinder.java
@@ -19,7 +19,6 @@ package org.apache.sis.geometries.internal.shared;
 import java.util.Objects;
 import javax.measure.Quantity;
 import org.apache.sis.geometries.DataPoints;
-import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.surface.Cylinder;
 import org.apache.sis.maths.NDArrays;
@@ -43,6 +42,11 @@ public non-sealed class DefaultCylinder extends 
AbstractGeometry implements Cyli
     private double radiusTop = 1.0;
     private double radiusBottom = 1.0;
 
+    /**
+     * Whether the ends are closed by disks.
+     */
+    private boolean closed = true;
+
     /**
      * Creates a cylinder along the axis joining the two given positions.
      * The reference system of the cylinder is the one of those positions.
@@ -122,8 +126,13 @@ public non-sealed class DefaultCylinder extends 
AbstractGeometry implements Cyli
     }
 
     @Override
-    public Geometry getBoundary() {
-        throw new UnsupportedOperationException("Not supported yet.");
+    public boolean isClosed() {
+        return closed;
+    }
+
+    @Override
+    public void setClosed(boolean closed) {
+        this.closed = closed;
     }
 
     @Override
@@ -139,7 +148,8 @@ public non-sealed class DefaultCylinder extends 
AbstractGeometry implements Cyli
             return false;
         }
         return Double.doubleToLongBits(this.radiusTop) == 
Double.doubleToLongBits(other.radiusTop)
-            && Double.doubleToLongBits(this.radiusBottom) == 
Double.doubleToLongBits(other.radiusBottom);
+            && Double.doubleToLongBits(this.radiusBottom) == 
Double.doubleToLongBits(other.radiusBottom)
+            && this.closed == other.closed;
     }
 
     @Override
@@ -148,6 +158,7 @@ public non-sealed class DefaultCylinder extends 
AbstractGeometry implements Cyli
         hash = 89 * hash + Objects.hashCode(this.points);
         hash = 89 * hash + Double.hashCode(this.radiusTop);
         hash = 89 * hash + Double.hashCode(this.radiusBottom);
+        hash = 89 * hash + Boolean.hashCode(this.closed);
         return hash;
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultEllipsoid.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultEllipsoid.java
index 9c15c172b5..40b491e35b 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultEllipsoid.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultEllipsoid.java
@@ -24,7 +24,6 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.Geometries;
-import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.surface.Ellipsoid;
 import org.apache.sis.maths.DataType;
@@ -193,11 +192,6 @@ public non-sealed class DefaultEllipsoid extends 
AbstractGeometry implements Ell
         points.setPosition(0, position);
     }
 
-    @Override
-    public Geometry getBoundary() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
     // methods from ParametricCurveSurface
 
     @Override
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSphere.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSphere.java
index 70223e83d6..3d298d699d 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSphere.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSphere.java
@@ -23,7 +23,6 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.Geometries;
-import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.surface.Sphere;
 import org.apache.sis.maths.DataType;
@@ -131,11 +130,6 @@ public non-sealed class DefaultSphere extends 
AbstractGeometry implements Sphere
         points.setPosition(0, position);
     }
 
-    @Override
-    public Geometry getBoundary() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
     // methods from ParametricCurveSurface
 
     @Override
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Capsule.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Capsule.java
index d7ddb0f81b..edc2769956 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Capsule.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Capsule.java
@@ -22,6 +22,8 @@ import org.opengis.annotation.UML;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.DataPointsType;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.Surface;
 import org.apache.sis.geometries.SurfaceInterpolation;
@@ -155,6 +157,14 @@ public sealed interface Capsule extends Surface
         return bbox;
     }
 
+    /**
+     * Returns the empty geometry: a capsule is a closed surface, so it has no 
edge.
+     */
+    @Override
+    default Geometry getBoundary() {
+        return 
GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
+    }
+
     @Override
     default CoordinateReferenceSystem getCoordinateReferenceSystem() {
         return getDataPoints().getCoordinateReferenceSystem();
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Cylinder.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Cylinder.java
index c36befb43b..73b4b4d232 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Cylinder.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Cylinder.java
@@ -16,17 +16,22 @@
  */
 package org.apache.sis.geometries.surface;
 
+import java.util.ArrayList;
 import java.util.List;
 import static org.opengis.annotation.Specification.ISO_12113;
 import org.opengis.annotation.UML;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.DataPointsType;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.Surface;
 import org.apache.sis.geometries.SurfaceInterpolation;
+import org.apache.sis.geometries.curve.Circle;
 import org.apache.sis.geometries.internal.shared.DefaultCylinder;
 import org.apache.sis.maths.DataType;
+import org.apache.sis.maths.NDArrays;
 import org.apache.sis.maths.ReadOnly;
 import org.apache.sis.maths.Vectors;
 import org.apache.sis.maths.Vector;
@@ -41,6 +46,10 @@ import org.apache.sis.maths.Vector;
  *
  * ISO 19107 : classified as a conic surface
  *
+ * <p>A cylinder is either {@linkplain #isClosed() closed} by two disks at its 
ends, which makes it
+ * the boundary of a volume as in the KHR_implicit_shapes extension, or open, 
in which case it is
+ * only the lateral surface that ISO 19107 defines.</p>
+ *
  * <p>Constraints:</p>
  * <ul>
  *   <li>The {@linkplain #getDataPoints() data points} hold exactly two 
positions:
@@ -66,15 +75,33 @@ public sealed interface Cylinder extends Surface
     }
 
     /**
-     * Returns {@link SurfaceInterpolation#CONIC}: ISO 19107 classifies 
cylinders and cones as conic surfaces.
+     * Returns {@link SurfaceInterpolation#CONIC}, since ISO 19107 classifies 
cylinders and cones
+     * as conic surfaces, followed by {@link SurfaceInterpolation#PLANAR} for 
the end disks if this
+     * cylinder is {@linkplain #isClosed() closed}.
      *
      * @see ISO 19107:2019 - 8.5.3, 8.5.4
      */
     @Override
     default List<SurfaceInterpolation> getInterpolation() {
-        return List.of(SurfaceInterpolation.CONIC);
+        return isClosed() ? List.of(SurfaceInterpolation.CONIC, 
SurfaceInterpolation.PLANAR)
+                          : List.of(SurfaceInterpolation.CONIC);
     }
 
+    /**
+     * Returns whether this cylinder is closed by a disk at each of its ends.
+     * An end whose radius is zero, the apex of a cone, needs no disk.
+     *
+     * @return {@code true} if the ends are closed by disks, or {@code false} 
for the lateral surface only.
+     */
+    boolean isClosed();
+
+    /**
+     * Sets whether this cylinder is closed by a disk at each of its ends.
+     *
+     * @param closed {@code true} to close the ends by disks, or {@code false} 
for the lateral surface only.
+     */
+    void setClosed(boolean closed);
+
     /**
      * Returns {@code false}: a cylinder always has its two circle centers.
      */
@@ -191,6 +218,87 @@ public sealed interface Cylinder extends Surface
         return bbox;
     }
 
+    /**
+     * Returns the empty geometry if this cylinder is {@linkplain #isClosed() 
closed},
+     * or the circles at its ends otherwise.
+     *
+     * <p>The circles of an open cylinder are oriented so that the lateral 
surface is on their left
+     * when seen from its outward normal: the bottom circle turns 
counterclockwise around the axis
+     * going from the bottom to the top, and the top circle clockwise. An end 
whose radius is zero,
+     * the apex of a cone, is a single point which bounds nothing, so it has 
no circle.</p>
+     *
+     * @return the empty geometry, or a collection of the end circles.
+     * @throws UnsupportedOperationException if this cylinder is open and not 
3-dimensional.
+     * @throws IllegalStateException if this cylinder is open and its two 
positions are the same.
+     */
+    @Override
+    default Geometry getBoundary() {
+        final CoordinateReferenceSystem crs = getCoordinateReferenceSystem();
+        if (isClosed()) {
+            return GeometryFactory.DEFAULT.createEmpty(crs);
+        }
+        if (getDataPoints().getDimension() != 3) {
+            throw new UnsupportedOperationException("The boundary of an open 
cylinder is computed in 3 dimensions only.");
+        }
+        final Vector<?> axis = getAxis();
+        final double height = axis.length();
+        if (!(height > 0)) {
+            throw new IllegalStateException("The cylinder has no axis, its two 
positions are the same.");
+        }
+        axis.scale(1 / height);
+        /*
+         * Builds (u, w, axis) as a right-handed orthonormal basis. The vector 
`u` is derived from the
+         * coordinate axis which is the most perpendicular to the cylinder 
axis, for numerical stability.
+         */
+        int k = 0;
+        for (int i = 1; i < 3; i++) {
+            if (Math.abs(axis.get(i)) < Math.abs(axis.get(k))) k = i;
+        }
+        final Vector<?> u = Vectors.create(axis.getSampleSystem(), 
DataType.DOUBLE);
+        u.set(k, 1);
+        u.subtract(axis.copy().scale(axis.get(k)));
+        u.normalize();
+        final Vector<?> w = axis.cross(u);
+        final var circles = new ArrayList<Circle>(2);
+        final double radiusBottom = getRadiusBottom();
+        final double radiusTop = getRadiusTop();
+        if (radiusBottom > 0) {
+            circles.add(circle(getBottom(), radiusBottom, u, w));
+        }
+        if (radiusTop > 0) {
+            circles.add(circle(getTop(), radiusTop, u, w.copy().scale(-1)));
+        }
+        return GeometryFactory.DEFAULT.createMultiCurve(crs, 
circles.toArray(Circle[]::new));
+    }
+
+    /**
+     * Returns the circle of the given center and radius in the plane of the 
two given unit vectors,
+     * turning from {@code u} toward {@code w}. The circle is made of four 
quarter arcs, since a
+     * single arc of a circle shall stay below a half turn.
+     */
+    private static Circle circle(final ReadOnly.Vector<?> center, final double 
radius,
+                                 final ReadOnly.Vector<?> u, final 
ReadOnly.Vector<?> w)
+    {
+        final var points  = new ArrayList<Vector<?>>(5);
+        final var centers = new ArrayList<Vector<?>>(4);
+        final ReadOnly.Vector<?>[] directions = {u, w, u.copy().scale(-1), 
w.copy().scale(-1), u};
+        for (final ReadOnly.Vector<?> direction : directions) {
+            final Vector<?> p = Vectors.create(center.getSampleSystem(), 
DataType.DOUBLE);
+            p.set(center);
+            p.add(direction.copy().scale(radius));
+            points.add(p);
+        }
+        for (int i = 0; i < 4; i++) {
+            final Vector<?> c = Vectors.create(center.getSampleSystem(), 
DataType.DOUBLE);
+            c.set(center);
+            centers.add(c);
+        }
+        final GeometryFactory factory = GeometryFactory.DEFAULT;
+        return factory.createCircle(
+                factory.createDataPoints(NDArrays.of(points, 
center.getSampleSystem(), DataType.DOUBLE)),
+                NDArrays.of(centers, center.getSampleSystem(), 
DataType.DOUBLE), null);
+    }
+
     @Override
     default CoordinateReferenceSystem getCoordinateReferenceSystem() {
         return getDataPoints().getCoordinateReferenceSystem();
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Ellipsoid.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Ellipsoid.java
index 254686b012..1c8639c6f7 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Ellipsoid.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Ellipsoid.java
@@ -23,6 +23,8 @@ import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.DataPointsType;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.SurfaceInterpolation;
 import org.apache.sis.geometries.internal.shared.DefaultEllipsoid;
@@ -139,6 +141,14 @@ public sealed interface Ellipsoid extends 
ParametricCurveSurface
      */
     void setCenter(ReadOnly.Vector<?> position);
 
+    /**
+     * Returns the empty geometry: an ellipsoid is a closed surface, so it has 
no edge.
+     */
+    @Override
+    default Geometry getBoundary() {
+        return 
GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
+    }
+
     @Override
     default CoordinateReferenceSystem getCoordinateReferenceSystem() {
         return getDataPoints().getCoordinateReferenceSystem();
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Sphere.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Sphere.java
index 8e8218958d..f8c5ac2d05 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Sphere.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Sphere.java
@@ -23,6 +23,8 @@ import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.DataPointsType;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.SurfaceInterpolation;
 import org.apache.sis.geometries.internal.shared.DefaultSphere;
@@ -130,6 +132,14 @@ public sealed interface Sphere extends 
ParametricCurveSurface
      */
     void setCenter(ReadOnly.Vector<?> position);
 
+    /**
+     * Returns the empty geometry: a sphere is a closed surface, so it has no 
edge.
+     */
+    @Override
+    default Geometry getBoundary() {
+        return 
GeometryFactory.DEFAULT.createEmpty(getCoordinateReferenceSystem());
+    }
+
     @Override
     default CoordinateReferenceSystem getCoordinateReferenceSystem() {
         return getDataPoints().getCoordinateReferenceSystem();

Reply via email to