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 d301c9395865cab5cdc8d000c905c6a9128850e0
Author: jsorel <[email protected]>
AuthorDate: Wed Oct 14 11:36:19 2026 +0200

    feat(Geometry): implement surface perimeter and area on several classes
---
 .../main/org/apache/sis/geometries/Surface.java    | 14 ++++++--
 .../internal/shared/DefaultNurbSurface.java        |  5 ++-
 .../internal/shared/DefaultPolyhedron.java         | 10 +++++-
 .../geometries/internal/shared/DefaultSolid.java   |  5 ++-
 .../geometries/internal/shared/DefaultSphere.java  |  6 ----
 .../solid/polyhedron/AbstractPolyhedron.java       | 40 ++++++++++++++++++----
 .../org/apache/sis/geometries/surface/Sphere.java  | 26 ++++++++++++++
 .../main/org/apache/sis/maths/ArrayFactory.java    |  2 +-
 8 files changed, 90 insertions(+), 18 deletions(-)

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 50cbba7829..00f3850044 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
@@ -29,6 +29,7 @@ import 
org.apache.sis.geometries.surface.ParametricCurveSurface;
 import org.apache.sis.geometries.surface.Polygon;
 import org.apache.sis.geometries.surface.PolyhedralSurface;
 import org.apache.sis.maths.Vector;
+import org.apache.sis.measure.Quantities;
 
 
 /**
@@ -234,8 +235,17 @@ public sealed interface Surface extends Orientable
      */
     @UML(identifier="perimeter", specification=ISO_19107)
     default Quantity<?> getPerimeter() {
-        //TODO
-        throw new UnsupportedOperationException();
+        final Geometry boundary = getBoundary();
+        if (boundary instanceof Curve c) {
+            return c.getLength();
+        }
+        if (boundary instanceof GeometryCollection<?> c && 
c.getNumGeometries() != 0) {
+            return c.getLength();
+        }
+        if (boundary.isEmpty()) {
+            return Quantities.create(0, Geometries.getLinearUnit(this));
+        }
+        throw new UnsupportedOperationException("Unsupported boundary type: " 
+ boundary.getGeometryType());
     }
 
     /**
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultNurbSurface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultNurbSurface.java
index 85a86dd6ad..e541aad4bb 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultNurbSurface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultNurbSurface.java
@@ -399,9 +399,12 @@ public non-sealed class DefaultNurbSurface extends 
AbstractGeometry implements N
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
+    /**
+     * Returns the position of this surface at the given parameters, computed 
by {@link #evaluate(double, double)}.
+     */
     @Override
     public DirectPosition getSurface(double u, double v) {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return Vectors.asDirectPostion(evaluate(u, v));
     }
 
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedron.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedron.java
index dfc2e9da58..e850cfe4b9 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedron.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedron.java
@@ -21,6 +21,7 @@ import java.util.Objects;
 import javax.measure.Quantity;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.geometries.Geometries;
 import org.apache.sis.geometries.GeometryCollection;
 import org.apache.sis.geometries.Surface;
 import org.apache.sis.geometries.solid.Polyhedron;
@@ -88,9 +89,16 @@ public non-sealed class DefaultPolyhedron extends 
AbstractGeometry implements Po
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
+    /**
+     * Returns the sum of the areas of the polygons of the exterior and 
interior shells.
+     */
     @Override
     public Quantity<?> getArea() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        Quantity<?> area = exterior.getArea();
+        for (final GeometryCollection<Polygon> interior : interiors) {
+            area = Geometries.add(area, interior.getArea());
+        }
+        return area;
     }
 
     @Override
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSolid.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSolid.java
index 7c6c4acebc..4c8b444488 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSolid.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultSolid.java
@@ -109,9 +109,12 @@ public non-sealed class DefaultSolid extends 
AbstractGeometry implements Solid {
         return 
GeometryFactory.DEFAULT.createGeometryCollection(GeometryType.SURFACE, 
getCoordinateReferenceSystem(), boundaries.toArray(Surface[]::new));
     }
 
+    /**
+     * Returns the sum of the areas of the boundary surfaces.
+     */
     @Override
     public Quantity<?> getArea() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return getBoundary().getArea();
     }
 
     @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 3d298d699d..90a9c7d109 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
@@ -17,7 +17,6 @@
 package org.apache.sis.geometries.internal.shared;
 
 import java.util.List;
-import javax.measure.Quantity;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.Curve;
@@ -104,11 +103,6 @@ public non-sealed class DefaultSphere extends 
AbstractGeometry implements Sphere
         this.radius = radius;
     }
 
-    @Override
-    public Quantity<?> getArea() {
-        throw new UnsupportedOperationException("Not supported.");
-    }
-
     @Override
     public double getRadius() {
         return radius;
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java
index 3d24496ada..c4830db71d 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/polyhedron/AbstractPolyhedron.java
@@ -18,6 +18,7 @@ package org.apache.sis.geometries.solid.polyhedron;
 
 import java.util.List;
 import org.apache.sis.geometries.DataPoints;
+import org.apache.sis.geometries.Geometries;
 import org.apache.sis.geometries.GeometryCollection;
 import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.Surface;
@@ -33,6 +34,7 @@ import org.apache.sis.maths.NDArrays;
 import org.apache.sis.maths.ReadOnly;
 import org.apache.sis.maths.SampleSystem;
 import org.apache.sis.maths.Vector3D;
+import org.apache.sis.util.ArgumentChecks;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 
@@ -84,19 +86,39 @@ public abstract sealed class AbstractPolyhedron extends 
AbstractGeometry impleme
      */
     protected static final double ATAN_INV_PHI2 = Math.PI/2 - ATAN_PHI2;
 
+    /**
+     * Reference system of the faces of this polyhedron. The vertices are 
constants shared by every
+     * instance, expressed in an undefined 3-dimensional Cartesian system; 
this system gives them a
+     * meaning for this instance only.
+     */
+    private CoordinateReferenceSystem crs = Geometries.getUndefinedCRS(3);
+
     @Override
     public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-        throw new UnsupportedOperationException("Not supported yet."); // 
Generated from 
nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
+        return crs;
     }
 
+    /**
+     * Sets the reference system in which the vertices of this polyhedron are 
expressed.
+     * The coordinates are not transformed.
+     *
+     * @throws IllegalArgumentException if the given reference system is not 
3-dimensional.
+     */
     @Override
     public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) 
throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Not supported yet."); // 
Generated from 
nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
+        ArgumentChecks.ensureNonNull("crs", crs);
+        if (crs.getCoordinateSystem().getDimension() != 3) {
+            throw new IllegalArgumentException("New CRS must be 
3-dimensional");
+        }
+        this.crs = crs;
     }
 
+    /**
+     * Returns the union of the envelopes of the faces.
+     */
     @Override
     public Envelope getEnvelope() {
-        throw new UnsupportedOperationException("Not supported yet."); // 
Generated from 
nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
+        return getExteriorShell().getEnvelope();
     }
 
     /**
@@ -209,14 +231,20 @@ public abstract sealed class AbstractPolyhedron extends 
AbstractGeometry impleme
     }
 
     /**
-     * Build the polygon of one face.
+     * Build the polygon of one face, in the {@linkplain 
#getCoordinateReferenceSystem() reference system}
+     * of this polyhedron.
      *
      * @param vertices polyhedron vertices
      * @param face face vertex indices into {@code vertices}, in CCW order 
viewed from outside
      * @return face polygon
      */
-    protected static Polygon toPolygon(Array vertices, int[] face) {
-        final Array positions = NDArrays.subset(vertices, face);
+    protected Polygon toPolygon(Array vertices, int[] face) {
+        Array positions = NDArrays.subset(vertices, face);
+        if (!crs.equals(positions.getCoordinateReferenceSystem())) {
+            // The subset is a view, and the vertices are shared by every 
instance: change a copy.
+            positions = positions.copy();
+            positions.setSampleSystem(SampleSystem.of(crs));
+        }
         final LinearRing ring = 
GeometryFactory.DEFAULT.createLinearRing(GeometryFactory.DEFAULT.createDataPoints(positions));
         return GeometryFactory.DEFAULT.createPolygon(ring, null);
     }
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 f8c5ac2d05..7fcc4743c8 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
@@ -17,12 +17,14 @@
 package org.apache.sis.geometries.surface;
 
 import java.util.List;
+import javax.measure.Quantity;
 import static org.opengis.annotation.Specification.ISO_19107;
 import org.opengis.annotation.UML;
 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.Geometries;
 import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.GeometryFactory;
 import org.apache.sis.geometries.GeometryType;
@@ -30,6 +32,7 @@ import org.apache.sis.geometries.SurfaceInterpolation;
 import org.apache.sis.geometries.internal.shared.DefaultSphere;
 import org.apache.sis.maths.ReadOnly;
 import org.apache.sis.maths.Vector;
+import org.apache.sis.measure.Quantities;
 
 
 /**
@@ -109,6 +112,29 @@ public sealed interface Sphere extends 
ParametricCurveSurface
         return GeometryType.CIRCLE;
     }
 
+    /**
+     * Returns the area of this sphere, which is 4πr² in a 3-dimensional space.
+     *
+     * <p>In an <var>n</var>-dimensional space, this is the measure of the 
(<var>n</var>−1)-sphere,
+     * 
2π<sup><var>n</var>/2</sup>∕Γ(<var>n</var>/2)⋅r<sup><var>n</var>−1</sup>, 
expressed in the
+     * linear unit raised to the power <var>n</var>−1. In a 2-dimensional 
space, it is therefore
+     * the perimeter 2πr of the circle.</p>
+     */
+    @Override
+    default Quantity<?> getArea() {
+        final int n = getDimension();
+        /*
+         * Measure of the unit (n−1)-sphere, from S(1) = 2 and S(2) = 2π with 
the recurrence
+         * S(n+2) = 2π⋅S(n)/n, which avoids computing the Gamma function.
+         */
+        int k = (n % 2 == 0) ? 2 : 1;
+        double measure = (k == 2) ? 2*Math.PI : 2;
+        for (; k + 2 <= n; k += 2) {
+            measure *= 2*Math.PI / k;
+        }
+        return Quantities.create(measure * Math.pow(getRadius(), n - 1), 
Geometries.getLinearUnit(this).pow(n - 1));
+    }
+
     /**
      * @return radius of the sphere.
      */
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ArrayFactory.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ArrayFactory.java
index b49df5dfa1..7a63fbfc36 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ArrayFactory.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/maths/ArrayFactory.java
@@ -257,7 +257,7 @@ public interface ArrayFactory {
                         final Cursor cursor = target.cursor();
                         while (cursor.next()) {
                             final Vector tuple = cursor.samples();
-                            tuple.set((ReadOnly.Vector) 
java.lang.reflect.Array.get(values, idx));
+                            tuple.set((ReadOnly.Vector) 
java.lang.reflect.Array.get(values, idx++));
                         }
                     } else {
                         int idx = 0;

Reply via email to