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 00f87381916ed315b27af3523e8f89ffad1b3830
Author: jsorel <[email protected]>
AuthorDate: Wed Sep 9 17:00:09 2026 +0200

    feat(Geometry): add Surface and Solid javadoc
---
 .../main/org/apache/sis/geometries/Solid.java      | 131 ++++++++++++--
 .../main/org/apache/sis/geometries/Surface.java    | 193 ++++++++++++++++++---
 .../sis/geometries/adapter/ShapeConverter.java     |   4 +-
 .../internal/shared/DefaultCurvePolygon.java       |   3 +-
 .../internal/shared/DefaultNurbSurface.java        |   5 +-
 .../geometries/internal/shared/DefaultPolygon.java |   7 +-
 .../internal/shared/DefaultPolyhedron.java         |   5 +-
 .../internal/shared/DefaultReversedSurface.java    |   3 +-
 .../sis/geometries/solid/ParametricCurveSolid.java |   3 +-
 .../org/apache/sis/geometries/solid/Sphere.java    |   5 +-
 .../sis/geometries/surface/BSplineSurface.java     |   3 +-
 .../sis/geometries/surface/MultiSurface.java       |  17 +-
 .../geometries/surface/ParametricCurveSurface.java |   2 +-
 .../sis/geometries/surface/PolyhedralSurface.java  |  23 ++-
 .../apache/sis/geometries/surface/Triangle.java    |   7 +-
 15 files changed, 351 insertions(+), 60 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Solid.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Solid.java
index 3b9f2f0848..e922560591 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Solid.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Solid.java
@@ -27,55 +27,162 @@ import org.opengis.geometry.DirectPosition;
 
 
 /**
+ * A 3-dimensional geometric primitive, bounded by a set of simple closed 
surfaces called shells.
  *
- * @author Johann Sorel (Geomatys
+ * <p>In a 3-dimensional space a solid is fully determined by its boundary, 
which is the usual
+ * boundary representation (B-REP). An internal {@linkplain 
#getInterpolation() interpolation} is
+ * only needed to describe a non-homogeneous interior, as found in coverages 
or in solid modelling.</p>
+ *
+ * <p>Constraints:</p>
+ * <ul>
+ *   <li>The topological dimension is 3, therefore a solid only exists in a 
coordinate system
+ *       having three spatial dimensions.</li>
+ *   <li>A solid is connected: any two of its interior positions can be joined 
by a curve which
+ *       stays entirely inside the solid.</li>
+ *   <li>A solid is always bounded: it has a finite envelope and contains no 
point at infinity.</li>
+ *   <li>The solid lies below every one of its shells, as given by the upward 
surface normal.</li>
+ *   <li>Every shell is simple, neither self-intersecting nor self-tangent, 
and closed.</li>
+ *   <li>Two shells of the same solid may be tangent to each other at a single 
position or along a
+ *       simple non-closed curve, lower side against lower side, meaning their 
upward normals point
+ *       in opposite directions at the contact.</li>
+ * </ul>
+ *
+ * <p>In a 3-dimensional coordinate system each shell splits the space in a 
bounded and an unbounded
+ * region per the Jordan-Schönflies theorem, so the shell with the largest 
envelope is the exterior
+ * one and the others are interior. Each shell defines the volume opposite to 
its upward normal.</p>
+ *
+ * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 6.4.28
  */
-@UML(identifier="Solid", specification=ISO_19107) // section 6.4.28
+@UML(identifier="Solid", specification=ISO_19107)
 public sealed interface Solid extends Primitive
         permits ParametricCurveSolid,
                 Polyhedron
 {
 
     /**
-     * Returns 3: a polyhedron bounds a volume.
+     * Returns 3: a solid bounds a volume.
+     *
+     * @see ISO 19107:2019 - 6.4.4.22
      */
     @Override
     public default int getTopologicDimension() {
         return 3;
     }
 
-    @UML(identifier="boundary", specification=ISO_19107) // section 6.4.28.2
+    /**
+     * Shells bounding this solid, each of them a closed surface without 
boundary.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>At least one shell.</li>
+     *   <li>Every shell is a cycle, therefore a closed composite surface 
having an empty boundary.</li>
+     *   <li>The shells are oriented outward: the upward normal of each of 
them faces away from the
+     *       interior of this solid.</li>
+     *   <li>The shell with the largest envelope is the exterior one, which is 
well defined only
+     *       because the enclosing coordinate space is a 3-dimensional 
Euclidean space.</li>
+     * </ul>
+     *
+     * @return boundary of this solid.
+     *
+     * @see ISO 19107:2019 - 6.4.28.2
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
     default Geometry getBoundary() {
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="area", specification=ISO_19107) // section 6.4.28.3
+    /**
+     * Sum of the areas of all the boundary surfaces of this solid.
+     *
+     * @return area of the boundary of this solid.
+     *
+     * @see ISO 19107:2019 - 6.4.28.3
+     */
+    @UML(identifier="area", specification=ISO_19107)
     default Area getArea() {
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="volume", specification=ISO_19107) // section 6.4.28.4
+    /**
+     * Volume enclosed by this solid, that is the volume interior to the 
exterior shell
+     * and exterior to any interior shell.
+     *
+     * @return volume of this solid.
+     *
+     * @see ISO 19107:2019 - 6.4.28.4
+     */
+    @UML(identifier="volume", specification=ISO_19107)
     default Volume getVolume() {
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="dataPoint", specification=ISO_19107) // section 6.4.28.5
-    default List<DirectPosition> getDataPoints() {
+    /**
+     * Sample positions on the interior and on the boundary of this solid, as 
a point cloud.
+     * Subtypes may add requirements on this collection.
+     *
+     * <p>Difference with ISO 19107: the type has been changed from a list of 
direct positions
+     * to {@link DataPoints}, in order to accommodate additional attributes 
like in GLTF or GPU models.</p>
+     *
+     * @return solid data points, possibly empty.
+     *
+     * @see ISO 19107:2019 - 6.4.28.5
+     */
+    @UML(identifier="dataPoint", specification=ISO_19107)
+    default DataPoints getDataPoints() {
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="controlPoint", specification=ISO_19107) // section 
6.4.28.6
+    /**
+     * Positions used to build the geometry of this solid, the way they are 
used depending on the interpolation.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>Control points need not lie inside this solid.</li>
+     *   <li>Interpolated values are only valid for the control points 
enclosed by the
+     *       {@linkplain #getBoundary() boundary} of this solid.</li>
+     * </ul>
+     *
+     * @return solid control points, possibly empty.
+     *
+     * @see ISO 19107:2019 - 6.4.28.6
+     */
+    @UML(identifier="controlPoint", specification=ISO_19107)
     default List<DirectPosition> getControlPoints() {
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="interpolation", specification=ISO_19107) // section 
6.4.28.7
+    /**
+     * Interpolation mechanism defining the internal parameterization of this 
solid.
+     * The default is a boundary representation, which leaves the interior 
unspecified.
+     *
+     * @return interpolation used by this solid.
+     *
+     * @see ISO 19107:2019 - 6.4.28.7, 6.4.30
+     */
+    @UML(identifier="interpolation", specification=ISO_19107)
     default SolidInterpolation getInterpolation() {
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="knot", specification=ISO_19107) // section 6.4.28.8
-    default double[] getKnots() {
+    /**
+     * Construction parameter values matching the {@linkplain #getDataPoints() 
data points},
+     * one sequence for each of the three solid parameters.
+     * Needed only by parametric solids, such as 3-dimensional b-splines.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>Three sequences, in the horizontal, vertical and depth parameter 
order.</li>
+     *   <li>Values in each sequence are monotonic.</li>
+     * </ul>
+     *
+     * @return knot values in the construction (knot) space, one sequence per 
solid parameter.
+     *
+     * @see ISO 19107:2019 - 6.4.28.8
+     */
+    @UML(identifier="knot", specification=ISO_19107)
+    default List<double[]> getKnots() {
         throw new UnsupportedOperationException();
     }
 
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 a5e6eaaa8e..d755209064 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
@@ -17,6 +17,7 @@
 package org.apache.sis.geometries;
 
 import java.util.List;
+import javax.measure.quantity.Area;
 import javax.measure.quantity.Length;
 import org.apache.sis.geometries.internal.shared.DefaultReversedSurface;
 import org.apache.sis.geometries.surface.CurvePolygon;
@@ -30,7 +31,35 @@ import org.opengis.geometry.DirectPosition;
 
 
 /**
- * A Surface is a 2-dimensional geometric object.
+ * A 2-dimensional geometric primitive, bounded by a set of simple closed 
curves called rings.
+ *
+ * <p>The orientation of a surface picks an <cite>up</cite> direction, given 
by the
+ * {@linkplain #upNormal(DirectPosition) up-normal}: the side from which the 
exterior boundary
+ * appears counter-clockwise. Reversing the orientation reverses every 
boundary curve and swaps
+ * <cite>up</cite> and <cite>down</cite>. When the surface bounds a solid, 
<cite>up</cite> is
+ * also <cite>outward</cite>.</p>
+ *
+ * <p>Constraints:</p>
+ * <ul>
+ *   <li>The topological dimension is 2.</li>
+ *   <li>A surface is connected: any two of its interior positions can be 
joined by a curve which
+ *       stays entirely inside the surface.</li>
+ *   <li>A surface is always bounded: it has a finite envelope and contains no 
point at infinity.</li>
+ *   <li>The surface lies on the left of every one of its rings.</li>
+ *   <li>Every ring is simple, neither self-intersecting nor self-tangent, and 
closed.</li>
+ *   <li>Two rings of the same surface may be tangent to each other, but only 
once per pair,
+ *       at a single position, and left side against left side.</li>
+ *   <li>A surface is orientable, therefore neither a Möbius strip nor a Klein 
bottle;
+ *       such shapes can only be built as a geometric complex.</li>
+ * </ul>
+ *
+ * <p>In a 2-dimensional coordinate system the interpolation is necessarily 
planar, each ring
+ * splits the space in a bounded and an unbounded region per the Jordan 
theorem, the ring with the
+ * largest envelope is the exterior one and the surface is the intersection of 
the surfaces defined
+ * by its rings. On a bounded reference surface such as a sphere, no ring is 
exterior.</p>
+ *
+ * <p>Note: the following describes the OGC Simple Feature Access point of 
view, where the only
+ * instantiable subtypes are {@link Polygon} and {@link PolyhedralSurface}.</p>
  *
  * A simple Surface may consists of a single “patch” that is associated with 
one “exterior boundary” and 0 or more
  * “interior” boundaries. A single such Surface patch in 3-dimensional space 
is isometric to planar Surfaces,
@@ -46,14 +75,15 @@ import org.opengis.geometry.DirectPosition;
  * The boundary of a simple Surface is the set of closed Curves corresponding 
to its “exterior” and “interior”
  * boundaries (Reference [1], section 3.12.9.4).
  *
- * The only instantiable subclasses of Surface defined in this standard are 
Polygon and PolyhedralSurface.
  * A Polygon is a simple Surface that is planar. A PolyhedralSurface is a 
simple surface, consisting of some number
  * of Polygon patches or facets. If a PolyhedralSurface is closed, then it 
bounds a solid.
  * A MultiSurface containing a set of closed PolyhedralSurfaces can be used to 
represent a Solid object with holes.
  *
  * @author Johann Sorel (Geomatys)
+ *
+ * @see ISO 19107:2019 - 6.4.25
  */
-@UML(identifier="Surface", specification=ISO_19107) // section 6.4.25
+@UML(identifier="Surface", specification=ISO_19107)
 public sealed interface Surface extends Orientable
         permits CurvePolygon,
                 ParametricCurveSurface,
@@ -65,20 +95,34 @@ public sealed interface Surface extends Orientable
     /**
      * The area of this Surface, as measured in the spatial reference system 
of this Surface.
      *
-     * Difference with ISO 19107 : should return an Area instance.
+     * <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>
      *
-     * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2
      * @return area of the surface.
+     *
+     * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2
+     * @see ISO 19107:2019 - 6.4.25.7
      */
-    @UML(identifier="area", specification=ISO_19107) // section 6.4.25.7
-    double getArea();
+    @UML(identifier="area", specification=ISO_19107)
+    Area getArea();
 
     /**
      * The mathematical centroid for this Surface as a Point.
      * The result is not guaranteed to be on this Surface.
      *
-     * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>The average is weighted by area.</li>
+     *   <li>The centroid may fall outside the domain of validity of the 
coordinate reference system.</li>
+     * </ul>
+     *
      * @return centroid for this Surface
+     *
+     * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2
+     * @see ISO 19107:2019 - 6.4.4.8
      */
     @Override
     default Point getCentroid() {
@@ -88,63 +132,172 @@ public sealed interface Surface extends Orientable
     /**
      * A Point guaranteed to be on this Surface.
      *
-     * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2
+     * <p>Difference with ISO 19107, which declares this operation on {@code 
Geometry}:
+     * see {@link Geometry#getRepresentativePoint()}.</p>
+     *
      * @return point guaranteed to be on this Surface.
+     *
+     * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2
+     * @see ISO 19107:2019 - 6.4.4.19
      */
     default Point getPointOnSurface() {
         throw new UnsupportedOperationException();
     }
 
-
-    @UML(identifier="boundary", specification=ISO_19107) // section 6.4.25.2
+    /**
+     * Rings bounding this surface, each of them a simple closed curve having 
this surface on its left.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>At least one ring.</li>
+     *   <li>Except on a plane, no ring is the exterior one, since the notion 
of unbounded exterior
+     *       does not apply.</li>
+     *   <li>In a 2-dimensional coordinate system the rings determine the 
surface completely,
+     *       and may therefore be used to build it.</li>
+     * </ul>
+     *
+     * @return boundary of this surface.
+     *
+     * @see ISO 19107:2019 - 6.4.25.2
+     */
+    @UML(identifier="boundary", specification=ISO_19107)
     default Geometry getBoundary() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="interpolation", specification=ISO_19107) // section 
6.4.25.3
+    /**
+     * Interpolation mechanisms used between the data points of this surface.
+     * The default is a polygonal interpolation.
+     *
+     * <p>The interpolation combines the {@linkplain #getDataPoints() data 
points},
+     * {@linkplain #getControlPoints() control points} and {@linkplain 
#getKnots() knots}
+     * to determine the positions of this surface.</p>
+     *
+     * @return interpolations used by this surface.
+     *
+     * @see ISO 19107:2019 - 6.4.25.3
+     */
+    @UML(identifier="interpolation", specification=ISO_19107)
     default List<SurfaceInterpolation> getInterpolation() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="numDerivativesBoundary", specification=ISO_19107) // 
section 6.4.25.4
+    /**
+     * Number of continuous derivatives guaranteed across the {@linkplain 
#getBoundary() boundary},
+     * therefore the continuity between this surface and the neighbours 
sharing a boundary curve with it.
+     * The default value 0 means simple continuity (C⁰), while a value 
<var>n</var> means that this
+     * surface and its <var>n</var> first derivatives are continuous (Cⁿ).
+     *
+     * @return number of continuous derivatives on the boundary, or {@code 
null} if unspecified.
+     *
+     * @see ISO 19107:2019 - 6.4.25.4
+     */
+    @UML(identifier="numDerivativesBoundary", specification=ISO_19107)
     default Integer getNumDerivativesBoundary() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="numDerivativeInterior", specification=ISO_19107) // 
section 6.4.25.5
+    /**
+     * Minimal level of continuity guaranteed within the interior of this 
surface.
+     * The default value 0 means simple continuity (C⁰).
+     *
+     * @return number of continuous derivatives in the interior, or {@code 
null} if unspecified.
+     *
+     * @see ISO 19107:2019 - 6.4.25.5
+     */
+    @UML(identifier="numDerivativeInterior", specification=ISO_19107)
     default Integer getNumDerivativeInterior() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="perimeter", specification=ISO_19107) // section 6.4.25.6
+    /**
+     * Sum of the lengths of all the boundary curves of this surface.
+     *
+     * @return perimeter of this surface.
+     *
+     * @see ISO 19107:2019 - 6.4.25.6
+     */
+    @UML(identifier="perimeter", specification=ISO_19107)
     default Length getPerimeter() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="dataPoint", specification=ISO_19107) // section 6.4.25.8
+    /**
+     * Points lying on this surface.
+     *
+     * <p>Difference with ISO 19107: the type has been changed from a list of 
direct positions
+     * to {@link DataPoints}, in order to accommodate additional attributes 
like in GLTF or GPU models.</p>
+     *
+     * @return surface data points.
+     *
+     * @see ISO 19107:2019 - 6.4.25.8
+     */
+    @UML(identifier="dataPoint", specification=ISO_19107)
     default DataPoints getDataPoints() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="controlPoint", specification=ISO_19107) // section 
6.4.25.9
+    /**
+     * Positions used to build the geometry of this surface, the way they are 
used depending on the interpolation.
+     * Control points do not necessarily lie on the surface.
+     *
+     * @return surface control points, possibly empty.
+     *
+     * @see ISO 19107:2019 - 6.4.25.9
+     */
+    @UML(identifier="controlPoint", specification=ISO_19107)
     default List<DirectPosition> getControlPoints() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="knot", specification=ISO_19107) // section 6.4.25.10
-    default double[] getKnots() {
+    /**
+     * Construction parameter values matching the {@linkplain #getDataPoints() 
data points},
+     * one sequence for each of the two surface parameters.
+     * Needed only when the construction parameter space is not the default 
one.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>Two sequences, the first one for the horizontal parameter and the 
second one for
+     *       the vertical parameter.</li>
+     *   <li>Values in each sequence are monotonic.</li>
+     * </ul>
+     *
+     * @return knot values in the construction (knot) space, one sequence per 
surface parameter.
+     *
+     * @see ISO 19107:2019 - 6.4.25.10
+     */
+    @UML(identifier="knot", specification=ISO_19107)
+    default List<double[]> getKnots() {
         //TODO
         throw new UnsupportedOperationException();
     }
 
-    @UML(identifier="upNormal", specification=ISO_19107) // section 6.4.25.11
+    /**
+     * Returns the vector perpendicular to this surface at the given position, 
pointing upward.
+     *
+     * <p>Constraints:</p>
+     * <ul>
+     *   <li>Normals are consistent over the whole surface, which therefore 
has two faces.</li>
+     *   <li>In a 3-dimensional coordinate system, the returned vector is 
perpendicular to the
+     *       tangent plane of this surface at the given position.</li>
+     *   <li>In a 2-dimensional coordinate system, the returned vector lies in 
the enclosing
+     *       3-dimensional Cartesian space of the geometric reference 
surface.</li>
+     *   <li>When this surface bounds a solid, the returned vector points away 
from that solid.</li>
+     * </ul>
+     *
+     * @param  point  position on this surface where to evaluate the normal.
+     * @return upward normal at the given position.
+     *
+     * @see ISO 19107:2019 - 6.4.25.11
+     */
+    @UML(identifier="upNormal", specification=ISO_19107)
     default Vector upNormal(DirectPosition point) {
         //TODO
         throw new UnsupportedOperationException();
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java
index 0541eb6939..1bb7135d8e 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/ShapeConverter.java
@@ -286,8 +286,8 @@ public abstract class ShapeConverter {
          */
         // Sort by area, bigger geometries are the outter rings.
         geometries.sort((Geometry o1, Geometry o2) -> {
-                double area1 = (o1 instanceof Surface s) ? s.getArea() : 0.0;
-                double area2 = (o2 instanceof Surface s) ? s.getArea() : 0.0;
+                double area1 = (o1 instanceof Surface s) ? 
s.getArea().getValue().doubleValue() : 0.0;
+                double area2 = (o2 instanceof Surface s) ? 
s.getArea().getValue().doubleValue() : 0.0;
                 return java.lang.Double.compare(area2, area1);
             });
 
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCurvePolygon.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCurvePolygon.java
index fc3c20fe44..dd808cbac7 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCurvePolygon.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCurvePolygon.java
@@ -18,6 +18,7 @@ package org.apache.sis.geometries.internal.shared;
 
 import java.util.List;
 import java.util.Objects;
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.Geometries;
 import org.apache.sis.geometries.surface.CurvePolygon;
@@ -82,7 +83,7 @@ public non-sealed class DefaultCurvePolygon extends 
AbstractGeometry implements
     }
 
     @Override
-    public double getArea() {
+    public Area getArea() {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
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 03caaed6f9..60c1b45172 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
@@ -18,6 +18,7 @@ package org.apache.sis.geometries.internal.shared;
 
 import java.util.Arrays;
 import java.util.List;
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.DataPoints;
@@ -316,7 +317,7 @@ public non-sealed class DefaultNurbSurface extends 
AbstractGeometry implements N
     }
 
     @Override
-    public double[] getKnots() {
+    public List<double[]> getKnots() {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
@@ -336,7 +337,7 @@ public non-sealed class DefaultNurbSurface extends 
AbstractGeometry implements N
     }
 
     @Override
-    public double getArea() {
+    public Area getArea() {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
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 e491ac34cb..9530a19ebc 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,10 +18,13 @@ package org.apache.sis.geometries.internal.shared;
 
 import java.util.List;
 import java.util.Objects;
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.Curve;
 import org.apache.sis.geometries.Geometries;
 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;
 import org.locationtech.jts.geom.GeometryFactory;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -84,9 +87,9 @@ public non-sealed class DefaultPolygon extends 
AbstractGeometry implements Polyg
     }
 
     @Override
-    public double getArea() {
+    public Area getArea() {
         //TODO : fallback on JTS until implemented
-        return Geometries.asJTS(this, false, new GeometryFactory()).getArea();
+        return Quantities.create(Geometries.asJTS(this, false, new 
GeometryFactory()).getArea(), Units.SQUARE_METRE);
     }
 
 }
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 2eb69335a8..90bb2bd4b8 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.List;
 import java.util.Objects;
 import javax.measure.quantity.Area;
 import javax.measure.quantity.Volume;
+import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.Geometry;
 import org.apache.sis.geometries.SolidInterpolation;
 import org.apache.sis.geometries.solid.Polyhedron;
@@ -115,7 +116,7 @@ public non-sealed class DefaultPolyhedron extends 
AbstractGeometry implements Po
     }
 
     @Override
-    public List<DirectPosition> getDataPoints() {
+    public DataPoints getDataPoints() {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
@@ -130,7 +131,7 @@ public non-sealed class DefaultPolyhedron extends 
AbstractGeometry implements Po
     }
 
     @Override
-    public double[] getKnots() {
+    public List<double[]> getKnots() {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultReversedSurface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultReversedSurface.java
index 6ad59cf4a2..b89cca5147 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultReversedSurface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultReversedSurface.java
@@ -17,6 +17,7 @@
 package org.apache.sis.geometries.internal.shared;
 
 import java.util.Objects;
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.AttributesType;
 import org.apache.sis.geometries.Orientable;
 import org.apache.sis.geometries.Primitive;
@@ -71,7 +72,7 @@ public non-sealed class DefaultReversedSurface extends 
AbstractGeometry implemen
      * Returns the area of the base surface. Area is unsigned, so the 
orientation does not affect it.
      */
     @Override
-    public double getArea() {
+    public Area getArea() {
         return base.getArea();
     }
 
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/ParametricCurveSolid.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/ParametricCurveSolid.java
index 6440e45875..27fea22757 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/ParametricCurveSolid.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/ParametricCurveSolid.java
@@ -18,6 +18,7 @@ package org.apache.sis.geometries.solid;
 
 import java.util.List;
 import org.apache.sis.geometries.Curve;
+import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.Solid;
 import static org.opengis.annotation.Specification.ISO_19107;
@@ -54,7 +55,7 @@ public sealed interface ParametricCurveSolid extends Solid
 
     @UML(identifier="dataPoints", specification=ISO_19107) // section 9.3.1.3
     @Override
-    List<DirectPosition> getDataPoints();
+    DataPoints getDataPoints();
 
     @UML(identifier="controlPoints", specification=ISO_19107) // section 
9.3.1.3
     @Override
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java
index 01e14f3a24..d3aa71a31f 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Sphere.java
@@ -17,6 +17,7 @@
 package org.apache.sis.geometries.solid;
 
 import java.util.List;
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.AttributesType;
 import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.Curve;
@@ -93,7 +94,7 @@ public final class Sphere extends AbstractGeometry implements 
ParametricCurveSur
     }
 
     @Override
-    public double getArea() {
+    public Area getArea() {
         throw new UnsupportedOperationException("Not supported.");
     }
 
@@ -189,7 +190,7 @@ public final class Sphere extends AbstractGeometry 
implements ParametricCurveSur
     }
 
     @Override
-    public double[] getKnots() {
+    public List<double[]> getKnots() {
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/BSplineSurface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/BSplineSurface.java
index 03a5569419..adb0eed96b 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/BSplineSurface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/BSplineSurface.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.geometries.surface;
 
+import java.util.List;
 import org.apache.sis.geometries.AttributesType;
 import org.apache.sis.geometries.GeometryType;
 import org.apache.sis.geometries.curve.KnotType;
@@ -38,7 +39,7 @@ public sealed interface BSplineSurface extends 
ParametricCurveSurface
 
     @UML(identifier="knot", specification=ISO_19107) // section 8.7.2.3
     @Override
-    double[] getKnots();
+    List<double[]> getKnots();
 
     @UML(identifier="knotSpec", specification=ISO_19107) // section 8.7.2.5
     KnotType getKnotSpec();
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/MultiSurface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/MultiSurface.java
index 11b4dbcec9..f5718adb2b 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/MultiSurface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/MultiSurface.java
@@ -16,10 +16,13 @@
  */
 package org.apache.sis.geometries.surface;
 
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.GeometryCollection;
 import org.apache.sis.geometries.Point;
 import org.apache.sis.geometries.Surface;
 import org.apache.sis.geometries.internal.shared.DefaultMultiSurface;
+import org.apache.sis.measure.Quantities;
+import org.apache.sis.measure.Units;
 
 
 /**
@@ -57,10 +60,14 @@ public sealed interface MultiSurface<T extends Surface> 
extends GeometryCollecti
      * @see OGC Simple Feature Access 1.2.1 - 6.1.13.2
      * @return area of the surface.
      */
-    default double getArea() {
-        double area = 0.0;
-        for (int i = 0, n = getNumGeometries(); i < n; i++) {
-            area += getGeometryN(i).getArea();
+    default Area getArea() {
+        final int n = getNumGeometries();
+        if (n == 0) {
+            return Quantities.create(0, Units.SQUARE_METRE);
+        }
+        Area area = getGeometryN(0).getArea();
+        for (int i = 1; i < n; i++) {
+            area = Quantities.castOrCopy(area.add(getGeometryN(i).getArea()));
         }
         return area;
     }
@@ -83,7 +90,7 @@ public sealed interface MultiSurface<T extends Surface> 
extends GeometryCollecti
      * @see OGC Simple Feature Access 1.2.1 - 6.1.13.2
      * @return point guaranteed to be on this MultiSurface.
      */
-    default double getPointOnSurface() {
+    default Point getPointOnSurface() {
         throw new UnsupportedOperationException();
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java
index ec48f336a2..31c24b00f4 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/ParametricCurveSurface.java
@@ -60,7 +60,7 @@ public sealed interface ParametricCurveSurface extends 
Surface, ReferenceSystem
     GeometryType getVerticalCurveType();
 
     @Override
-    double[] getKnots();
+    List<double[]> getKnots();
 
     @UML(identifier="horizontalCurve", specification=ISO_19107) // section 
8.3.2.9
     Curve getHorizontalCurve(double v);
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/PolyhedralSurface.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/PolyhedralSurface.java
index 68b8b262d6..3963395e96 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/PolyhedralSurface.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/PolyhedralSurface.java
@@ -16,11 +16,11 @@
  */
 package org.apache.sis.geometries.surface;
 
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.Surface;
 import org.apache.sis.geometries.internal.shared.DefaultPolyhedralSurface;
+import org.apache.sis.measure.Quantities;
+import org.apache.sis.measure.Units;
 import static org.opengis.annotation.Specification.ISO_19107;
 import org.opengis.annotation.UML;
 
@@ -81,11 +81,22 @@ public sealed interface PolyhedralSurface<T extends 
Polygon> extends /*GeometryC
      */
     T getPatchN(int n);
 
+    /**
+     * Returns the sum of the areas of the patches.
+     * The unit of measurement is the one of the first patch,
+     * or square metres if this surface has no patch.
+     */
     @Override
-    public default double getArea() {
-        try (Stream<Surface> stream = IntStream.range(0, 
getNumPatches()).mapToObj(this::getPatchN)) {
-            return stream.collect(Collectors.summingDouble(Surface::getArea));
+    public default Area getArea() {
+        final int n = getNumPatches();
+        if (n == 0) {
+            return Quantities.create(0, Units.SQUARE_METRE);
+        }
+        Area area = getPatchN(0).getArea();
+        for (int i = 1; i < n; i++) {
+            area = Quantities.castOrCopy(area.add(getPatchN(i).getArea()));
         }
+        return area;
     }
 
     /**
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Triangle.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Triangle.java
index 5716a45f3d..7fc24edb41 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Triangle.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/surface/Triangle.java
@@ -18,6 +18,7 @@ package org.apache.sis.geometries.surface;
 
 import java.util.Collections;
 import java.util.List;
+import javax.measure.quantity.Area;
 import org.apache.sis.geometries.AttributesType;
 import org.apache.sis.geometries.BBox;
 import org.apache.sis.geometries.DataPoints;
@@ -33,6 +34,8 @@ import org.apache.sis.maths.Vector;
 import org.apache.sis.maths.Vector2D;
 import org.apache.sis.maths.Vector3D;
 import org.apache.sis.maths.Vectors;
+import org.apache.sis.measure.Quantities;
+import org.apache.sis.measure.Units;
 import static org.opengis.annotation.Specification.ISO_19107;
 import org.opengis.annotation.UML;
 import org.opengis.geometry.Envelope;
@@ -94,7 +97,7 @@ public sealed interface Triangle extends Polygon
     }
 
     @Override
-    default double getArea() {
+    default Area getArea() {
         final DataPoints points = getExteriorRing().getDataPoints();
         final Tuple<?> a = points.getPosition(0);
         final Tuple<?> b = points.getPosition(1);
@@ -104,7 +107,7 @@ public sealed interface Triangle extends Polygon
                     + b.get(0) * (c.get(1) - a.get(1))
                     + c.get(0) * (a.get(1) - b.get(1))
                     ) / 2.0;
-        return Math.abs(area);
+        return Quantities.create(Math.abs(area), Units.SQUARE_METRE);
     }
 
     /**

Reply via email to