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 bb9e3560ebb5cfb695219dca73f8762629bd2aa9 Author: jsorel <[email protected]> AuthorDate: Wed Oct 14 14:46:55 2026 +0200 feat(Geometry): implements getDimension(coord) on several geometry types --- .../main/org/apache/sis/geometries/Geometry.java | 10 ++++-- .../apache/sis/geometries/GeometryCollection.java | 40 ++++++++++++++++++++++ .../org/apache/sis/geometries/curve/NurbCurve.java | 16 ++++++++- .../apache/sis/geometries/curve/ProductCurve.java | 10 ++++++ .../internal/shared/DefaultCompoundCurve.java | 34 ++++++++++++++++-- .../internal/shared/DefaultGeometryCollection.java | 2 +- .../internal/shared/DefaultPolyhedralSurface.java | 2 +- 7 files changed, 106 insertions(+), 8 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 5d5717c340..b90ce9e620 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 @@ -215,7 +215,12 @@ public sealed interface Geometry */ return getTopologicDimension(); } - throw new UnsupportedOperationException(); + /* + * A geometry which is not an aggregate is homogeneous: it has the same dimension at every + * interior position. Aggregates, which may mix components of different dimensions, + * override this method. + */ + return getTopologicDimension(); } /** @@ -525,8 +530,7 @@ public sealed interface Geometry */ @UML(identifier="isCycle", specification=ISO_19107) default boolean isCycle() { - //TODO remove this method default when all classes implement it. - throw new UnsupportedOperationException(); + return getBoundary().isEmpty(); } /** diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java index 7da33ab2e7..8e3ddf3a56 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java @@ -19,6 +19,7 @@ package org.apache.sis.geometries; import javax.measure.Quantity; import static org.opengis.annotation.Specification.ISO_19107; import org.opengis.annotation.UML; +import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Envelope; import org.apache.sis.geometries.curve.ProductCurve; import org.apache.sis.geometries.internal.shared.ConcatenatedDataPoints; @@ -143,6 +144,45 @@ public sealed interface GeometryCollection<T extends Geometry> extends Geometry return getNumGeometries() == 0; } + /** + * Returns the largest topological dimension among the elements of this collection which contain + * the given position, or −1 if none of them contains it. If the given position is null, returns + * the {@linkplain #getTopologicDimension() largest dimension} among all elements. + * + * <p>Containment is tested with {@link Geometry#intersects(Geometry)}, which may be unsupported + * for some element types.</p> + * + * @param point position where to evaluate the dimension, or null for the whole collection. + * @return topological dimension at the given position. + * + * @see ISO 19107:2019 - 6.4.4.25 + */ + @Override + default int getDimension(DirectPosition point) { + if (point == null) { + return getTopologicDimension(); + } + Point position = null; + int dimension = -1; + for (int i = 0, n = getNumGeometries(); i < n; i++) { + final Geometry element = getGeometryN(i); + if (element.getTopologicDimension() <= dimension) { + continue; // Cannot increase the result, no need to test containment. + } + if (element instanceof GeometryCollection<?> aggregate) { + dimension = Math.max(dimension, aggregate.getDimension(point)); + } else { + if (position == null) { + position = GeometryFactory.DEFAULT.createPoint(getCoordinateReferenceSystem(), point.getCoordinates()); + } + if (element.intersects(position)) { + dimension = element.getTopologicDimension(); + } + } + } + return dimension; + } + /** * Returns the largest topological dimension among the elements of this collection, * or −1 if this collection is empty. diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/NurbCurve.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/NurbCurve.java index 076e18414b..45b1017c0e 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/NurbCurve.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/NurbCurve.java @@ -126,9 +126,23 @@ public sealed interface NurbCurve extends BSplineCurve return true; } + /** + * Returns the number of non-empty knot spans in the domain of this curve, each of them being a + * polynomial arc. The domain extends from the knot at index <var>degree</var> to the knot at index + * <var>n</var>, where <var>n</var> is the number of control points. The knots are repeated + * according to their multiplicity, so repeated knots delimit empty spans which are not counted. + */ @Override default Integer getNumArc() { - throw new UnsupportedOperationException("Not supported yet."); + final double[] knots = getKnots(); + final int degree = getDegree(); + int count = 0; + for (int i = degree, n = knots.length - degree - 1; i < n; i++) { + if (knots[i + 1] > knots[i]) { + count++; + } + } + return count; } @Override diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/ProductCurve.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/ProductCurve.java index 66df4564a1..f4d2f43272 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/ProductCurve.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/curve/ProductCurve.java @@ -20,6 +20,7 @@ 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.DirectPosition; import org.apache.sis.geometries.Curve; import org.apache.sis.geometries.CurveInterpolation; import org.apache.sis.geometries.DataPoints; @@ -156,5 +157,14 @@ public sealed interface ProductCurve extends Curve, GeometryCollection<Curve> return Curve.super.isClosed(); } + /** + * Returns 1 whatever the position: a product curve is a curve, which has the same + * dimension at every interior position, even if it is also a collection of curves. + */ + @Override + default int getDimension(DirectPosition point) { + return Curve.super.getDimension(point); + } + } diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCompoundCurve.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCompoundCurve.java index 6b55998f98..facd052bdb 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCompoundCurve.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultCompoundCurve.java @@ -16,6 +16,7 @@ */ package org.apache.sis.geometries.internal.shared; +import java.util.ArrayList; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.geometries.Curve; @@ -23,6 +24,8 @@ import org.apache.sis.geometries.DataPointsType; import org.apache.sis.geometries.curve.CompoundCurve; import org.apache.sis.geometries.Geometries; import org.apache.sis.maths.Array; +import org.apache.sis.maths.DataType; +import org.apache.sis.maths.NDArrays; import org.apache.sis.util.ArgumentChecks; @@ -37,7 +40,7 @@ public non-sealed class DefaultCompoundCurve extends AbstractGeometry implements /** * The coordinate reference system to report when this curve has no component. - * Ignored otherwise, in which case the first component is authoritative. May be {@code null}. + * Ignored otherwise, in which case the first component is authoritative. Never null. */ private CoordinateReferenceSystem fallbackCRS; @@ -98,9 +101,36 @@ public non-sealed class DefaultCompoundCurve extends AbstractGeometry implements return envUnion(curves); } + /** + * Returns the control points of the components, in the order of the components. + * A component without control points, such as a line string, contributes none. + * + * @return control points of the components, or {@code null} if none of them has control points. + */ @Override public Array getControlPoints() { - throw new UnsupportedOperationException("Not supported yet."); + final var arrays = new ArrayList<Array>(curves.length); + DataType dataType = null; + boolean mixed = false; + for (final Curve curve : curves) { + final Array array = curve.getControlPoints(); + if (array != null && array.getLength() != 0) { + arrays.add(array); + if (dataType == null) { + dataType = array.getDataType(); + } else { + mixed |= (dataType != array.getDataType()); + } + } + } + switch (arrays.size()) { + case 0: return null; + case 1: return arrays.get(0); + } + if (mixed) { + arrays.replaceAll((array) -> array.retype(DataType.DOUBLE)); + } + return NDArrays.concatenate(arrays.toArray(Array[]::new)); } } 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 1fbe40671a..79f35bb6bf 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 @@ -38,7 +38,7 @@ public non-sealed class DefaultGeometryCollection<T extends Geometry> extends Ab /** * The coordinate reference system to report when this collection is empty. * Ignored when at least one geometry is present, in which case the first - * geometry is authoritative. May be {@code null}. + * geometry is authoritative. Never null. */ private CoordinateReferenceSystem fallbackCRS; diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedralSurface.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedralSurface.java index 2834bae517..f28773790e 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedralSurface.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultPolyhedralSurface.java @@ -38,7 +38,7 @@ public non-sealed class DefaultPolyhedralSurface<T extends Polygon> extends Abst /** * The coordinate reference system to report when this surface has no patch. - * Ignored otherwise, in which case the first patch is authoritative. May be {@code null}. + * Ignored otherwise, in which case the first patch is authoritative. Never null. */ private CoordinateReferenceSystem fallbackCRS;
