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 400f9bd950bcd1835ec3369ed85d0efc6ee086c3 Author: jsorel <[email protected]> AuthorDate: Thu Oct 15 10:05:51 2026 +0200 feat(Geometry): add GeometryEnvelope to work with Vector instead of DirectPosition, simplifying algorithms --- .../main/org/apache/sis/geometries/BBox.java | 34 +--- .../main/org/apache/sis/geometries/Geometries.java | 6 +- .../internal/shared/AbstractGeometry.java | 41 ++--- .../internal/shared/DefaultArcByCenterPoint.java | 27 ++- .../internal/shared/DefaultBSplineCurve.java | 2 +- .../internal/shared/DefaultBSplineSolid.java | 6 +- .../internal/shared/DefaultBSplineSurface.java | 6 +- .../internal/shared/DefaultBilinearGrid.java | 4 +- .../geometries/internal/shared/DefaultConic.java | 7 +- .../internal/shared/DefaultEllipsoid.java | 4 +- .../internal/shared/DefaultNurbSurface.java | 5 +- .../geometries/internal/shared/DefaultSphere.java | 4 +- .../internal/shared/GeometryEnvelope.java | 188 +++++++++++++++++++++ .../sis/geometries/solid/ParametricCurveSolid.java | 4 +- .../geometries/surface/ParametricCurveSurface.java | 3 +- .../internal/shared/GeometryEnvelopeTest.java | 92 ++++++++++ 16 files changed, 336 insertions(+), 97 deletions(-) diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/BBox.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/BBox.java index 873d348f15..63cee96c84 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/BBox.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/BBox.java @@ -19,12 +19,11 @@ package org.apache.sis.geometries; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import org.opengis.coordinate.MismatchedDimensionException; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.apache.sis.geometries.internal.shared.GeometryEnvelope; import org.apache.sis.geometries.internal.shared.IndexedPoint; import org.apache.sis.geometries.surface.Polygon; -import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.maths.DataType; import org.apache.sis.maths.NDArrays; import org.apache.sis.maths.ReadOnly; @@ -39,7 +38,7 @@ import org.apache.sis.maths.Vector; * * @author Johann Sorel (Geomatys) */ -public final class BBox extends GeneralEnvelope implements Geometry { +public final class BBox extends GeometryEnvelope implements Geometry { private Map<String,Object> properties; @@ -63,8 +62,8 @@ public final class BBox extends GeneralEnvelope implements Geometry { * @param lower lower corner * @param upper upper corner */ - public BBox(Vector lower, Vector upper) { - super(Vectors.asDirectPostion(lower), Vectors.asDirectPostion(upper)); + public BBox(ReadOnly.Vector<?> lower, ReadOnly.Vector<?> upper) { + super(lower, upper); ensureCRS(); } @@ -125,24 +124,6 @@ public final class BBox extends GeneralEnvelope implements Geometry { return isEmpty() ? -1 : getDimension(); } - public void add(Vector<?> position) throws MismatchedDimensionException { - add(Vectors.asDirectPostion(position)); - } - - /** - * {@inheritDoc } - */ - public Vector<?> getLower() { - return Vectors.castOrWrap(super.getLowerCorner()); - } - - /** - * {@inheritDoc } - */ - public Vector<?> getUpper() { - return Vectors.castOrWrap(super.getUpperCorner()); - } - /** * {@inheritDoc } */ @@ -290,12 +271,7 @@ public final class BBox extends GeneralEnvelope implements Geometry { @Override public Vector<?> getPosition(int index) { ensureValid(index); - final int dim = getDimension(); - final Vector<?> position = Vectors.create(BBox.this.getCoordinateReferenceSystem(), DataType.DOUBLE); - for (int i = 0; i < dim; i++) { - position.set(i, (index == 0) ? getMinimum(i) : getMaximum(i)); - } - return position; + return (index == 0) ? getLower() : getUpper(); } @Override 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 9eb963ebc8..dcb32273f4 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 @@ -48,6 +48,7 @@ import org.opengis.util.InternationalString; import org.apache.sis.geometries.adapter.JTSAdapter; import org.apache.sis.geometries.adapter.ShapeAdapter; import org.apache.sis.geometries.adapter.ShapeConverter; +import org.apache.sis.geometries.internal.shared.GeometryEnvelope; import org.apache.sis.geometries.mesh.MeshPrimitive; import org.apache.sis.geometries.mesh.MultiMeshPrimitive; import org.apache.sis.geometry.wrapper.jts.JTS; @@ -262,8 +263,9 @@ public final class Geometries { public static MeshPrimitive createBox(Envelope geom) { - final Vector lower = Vectors.castOrCopy(geom.getLowerCorner()); - final Vector upper = Vectors.castOrCopy(geom.getUpperCorner()); + final var box = new GeometryEnvelope(geom); + final Vector lower = box.getLower(); + final Vector upper = box.getUpper(); final int dim = lower.getDimension(); 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 af03496c60..80eb2052ce 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 @@ -16,18 +16,16 @@ */ package org.apache.sis.geometries.internal.shared; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.opengis.geometry.Envelope; import org.apache.sis.geometries.DataPoints; import org.apache.sis.geometries.Geometries; import org.apache.sis.geometries.Geometry; -import org.apache.sis.geometry.GeneralDirectPosition; import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.maths.Array; +import org.apache.sis.maths.Vector; +import org.apache.sis.maths.Vectors; /** @@ -103,26 +101,25 @@ public abstract non-sealed class AbstractGeometry implements Geometry { * hull of its control points, so the returned envelope contains it. * * @param points data points of the spline, or {@code null} if none. - * @param controlPoints coordinates of the control points, possibly empty. + * @param controlPoints the control points, or {@code null} if none. * @param homogeneous whether the control points have one more coordinate than the reference system, * the weight by which the other coordinates are divided. Weights are assumed positive. * @return envelope of the data points and of the control points, or {@code null} if there is none. */ - protected static Envelope controlHullEnvelope(final DataPoints points, final List<double[]> controlPoints, + protected static Envelope controlHullEnvelope(final DataPoints points, final Array controlPoints, final boolean homogeneous) { - GeneralEnvelope envelope = (points == null || points.isEmpty()) ? null : new GeneralEnvelope(points.getEnvelope()); - for (double[] coordinates : controlPoints) { + GeometryEnvelope envelope = (points == null || points.isEmpty()) ? null : new GeometryEnvelope(points.getEnvelope()); + final long n = (controlPoints != null) ? controlPoints.getLength() : 0; + for (long i = 0; i < n; i++) { + Vector<?> position = controlPoints.get(i); if (homogeneous) { - final double weight = coordinates[coordinates.length - 1]; - coordinates = Arrays.copyOf(coordinates, coordinates.length - 1); - for (int i = 0; i < coordinates.length; i++) { - coordinates[i] /= weight; - } + final int dimension = position.getDimension() - 1; + final double weight = position.get(dimension); + position = Vectors.createDouble(dimension).set(position).scale(1 / weight); } - final var position = new GeneralDirectPosition(coordinates); if (envelope == null) { - envelope = new GeneralEnvelope(position, position); + envelope = new GeometryEnvelope(position, position); if (points != null) { envelope.setCoordinateReferenceSystem(points.getCoordinateReferenceSystem()); } @@ -133,20 +130,6 @@ public abstract non-sealed class AbstractGeometry implements Geometry { return envelope; } - /** - * Returns the coordinates of the given control points, or an empty list if {@code null}. - */ - protected static List<double[]> coordinates(final Array controlPoints) { - if (controlPoints == null) { - return List.of(); - } - final var coordinates = new ArrayList<double[]>(); - for (long i = 0, n = controlPoints.getLength(); i < n; i++) { - coordinates.add(controlPoints.get(i).toArrayDouble()); - } - return coordinates; - } - /** * Adds the envelope of the given geometry to the given union, creating it if needed. * Geometries with no envelope at all (an empty one, typically) are skipped. diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultArcByCenterPoint.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultArcByCenterPoint.java index cc4007e538..eb65f8e921 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultArcByCenterPoint.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultArcByCenterPoint.java @@ -22,8 +22,8 @@ import org.opengis.geometry.Envelope; import org.apache.sis.geometries.DataPoints; import org.apache.sis.geometries.Point; import org.apache.sis.geometries.curve.ArcByCenterPoint; -import org.apache.sis.geometry.GeneralDirectPosition; -import org.apache.sis.geometry.GeneralEnvelope; +import org.apache.sis.maths.DataType; +import org.apache.sis.maths.Vector; /** @@ -106,21 +106,20 @@ public non-sealed class DefaultArcByCenterPoint extends AbstractGeometry impleme */ @Override public Envelope getEnvelope() { - final var envelope = new GeneralEnvelope(center.getEnvelope()); - final var position = new GeneralDirectPosition(envelope.getLowerCorner()); - final double cx = position.getCoordinate(0); - final double cy = position.getCoordinate(1); + // Axes after the first two keep the coordinates of the centre. + final Vector<?> position = center.getPosition().copy(DataType.DOUBLE); + final double cx = position.get(0); + final double cy = position.get(1); final double rx = radius(0); final double ry = radius(1); // The sweep direction does not change the positions covered by the arc. final double lo = Math.min(startAngle, endAngle); final double hi = Math.max(startAngle, endAngle); - // The centre is not on the arc: the first two axes start from an end point, not from the centre. + // The centre is not on the arc: the envelope starts from an end point, not from the centre. double t = Math.toRadians(lo); - final double x = cx + rx * Math.cos(t); - final double y = cy + ry * Math.sin(t); - envelope.setRange(0, x, x); - envelope.setRange(1, y, y); + position.set(0, cx + rx * Math.cos(t)); + position.set(1, cy + ry * Math.sin(t)); + final var envelope = new GeometryEnvelope(position, position); t = Math.toRadians(hi); add(envelope, position, cx + rx * Math.cos(t), cy + ry * Math.sin(t)); // Any sweep of 360° or more contains the four extremes, so the loop stops after one turn. @@ -140,11 +139,11 @@ public non-sealed class DefaultArcByCenterPoint extends AbstractGeometry impleme * Adds to the envelope the given position, with its first two coordinates replaced by the given ones. * The other coordinates are those of the centre. */ - private static void add(final GeneralEnvelope envelope, final GeneralDirectPosition position, + private static void add(final GeometryEnvelope envelope, final Vector<?> position, final double x, final double y) { - position.setCoordinate(0, x); - position.setCoordinate(1, y); + position.set(0, x); + position.set(1, y); envelope.add(position); } diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineCurve.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineCurve.java index 97c27f2e9d..0d9eb3be22 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineCurve.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineCurve.java @@ -179,7 +179,7 @@ public non-sealed class DefaultBSplineCurve extends AbstractGeometry implements */ @Override public Envelope getEnvelope() { - return controlHullEnvelope(points, coordinates(controlPoints), rational); + return controlHullEnvelope(points, controlPoints, rational); } /** diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSolid.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSolid.java index 95a6520574..634046920d 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSolid.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSolid.java @@ -17,7 +17,6 @@ package org.apache.sis.geometries.internal.shared; import java.util.Objects; -import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.geometries.Curve; @@ -29,6 +28,7 @@ import org.apache.sis.geometries.GeometryCollection; import org.apache.sis.geometries.Surface; import org.apache.sis.geometries.solid.BSplineSolid; import org.apache.sis.maths.Array; +import org.apache.sis.maths.Vector; /** @@ -148,7 +148,7 @@ public non-sealed class DefaultBSplineSolid extends AbstractGeometry implements } @Override - public DirectPosition getSurface(double a, double b, double c) { + public Vector<?> getSurface(double a, double b, double c) { throw new UnsupportedOperationException("Not supported yet."); } @@ -178,7 +178,7 @@ public non-sealed class DefaultBSplineSolid extends AbstractGeometry implements */ @Override public Envelope getEnvelope() { - return controlHullEnvelope(points, coordinates(controlPoints), false); + return controlHullEnvelope(points, controlPoints, false); } @Override diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSurface.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSurface.java index 2db202201e..5666cc63e0 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSurface.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBSplineSurface.java @@ -19,7 +19,6 @@ package org.apache.sis.geometries.internal.shared; import java.util.List; import java.util.Objects; import javax.measure.Quantity; -import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Envelope; import org.apache.sis.geometries.Curve; import org.apache.sis.geometries.DataPoints; @@ -28,6 +27,7 @@ import org.apache.sis.geometries.curve.KnotType; import org.apache.sis.geometries.surface.BSplineSurface; import org.apache.sis.geometries.surface.BSplineSurfaceForm; import org.apache.sis.maths.Array; +import org.apache.sis.maths.Vector; /** @@ -174,7 +174,7 @@ public non-sealed class DefaultBSplineSurface extends AbstractGeometry implement } @Override - public DirectPosition getSurface(double u, double v) { + public Vector<?> getSurface(double u, double v) { throw new UnsupportedOperationException("Not supported yet."); } @@ -189,7 +189,7 @@ public non-sealed class DefaultBSplineSurface extends AbstractGeometry implement */ @Override public Envelope getEnvelope() { - return controlHullEnvelope(points, coordinates(controlPoints), !polynomial); + return controlHullEnvelope(points, controlPoints, !polynomial); } @Override diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBilinearGrid.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBilinearGrid.java index f744d08321..a4a18c5b07 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBilinearGrid.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultBilinearGrid.java @@ -19,7 +19,6 @@ package org.apache.sis.geometries.internal.shared; import java.util.List; import java.util.Objects; import javax.measure.Quantity; -import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.geometries.Curve; @@ -29,6 +28,7 @@ import org.apache.sis.geometries.GeometryType; import org.apache.sis.geometries.DataPointsType; import org.apache.sis.geometries.surface.BilinearGrid; import org.apache.sis.maths.Array; +import org.apache.sis.maths.Vector; /** @@ -138,7 +138,7 @@ public non-sealed class DefaultBilinearGrid extends AbstractGeometry implements } @Override - public DirectPosition getSurface(double u, double v) { + public Vector<?> getSurface(double u, double v) { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultConic.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultConic.java index b09ec81925..ae82eb2284 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultConic.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultConic.java @@ -23,7 +23,6 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.geometries.DataPoints; import org.apache.sis.geometries.DataPointsType; import org.apache.sis.geometries.curve.Conic; -import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.maths.Array; import org.apache.sis.maths.DataType; import org.apache.sis.maths.Vector; @@ -116,7 +115,7 @@ public non-sealed class DefaultConic extends AbstractGeometry implements Conic { */ @Override public Envelope getEnvelope() { - final var envelope = new GeneralEnvelope(points.getEnvelope()); + final var envelope = new GeometryEnvelope(points.getEnvelope()); if (points.isEmpty()) { return envelope; } @@ -142,7 +141,7 @@ public non-sealed class DefaultConic extends AbstractGeometry implements Conic { * Expands the given envelope for containing the extremes along each axis of the conic arc * going through the five given points. The envelope shall already contain those points. */ - private static void addArc(final GeneralEnvelope envelope, final Vector<?>[] p) { + private static void addArc(final GeometryEnvelope envelope, final Vector<?>[] p) { final int dimension = p[0].getDimension(); /* * Builds an orthonormal basis (e1, e2) of the plane of the points, with the centroid as origin. @@ -283,7 +282,7 @@ public non-sealed class DefaultConic extends AbstractGeometry implements Conic { final Vector<?> position = origin.copy(DataType.DOUBLE) .add(e1.copy(DataType.DOUBLE).scale(scale * xa)) .add(e2.copy(DataType.DOUBLE).scale(scale * xb)); - envelope.add(Vectors.asDirectPostion(position)); + envelope.add(position); } } } 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 c4bb81d492..8a4992f9a4 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 @@ -19,7 +19,6 @@ package org.apache.sis.geometries.internal.shared; import java.util.Arrays; 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; import org.apache.sis.geometries.DataPoints; @@ -31,6 +30,7 @@ import org.apache.sis.maths.DataType; import org.apache.sis.maths.NDArrays; import org.apache.sis.maths.ReadOnly; import org.apache.sis.maths.SampleSystem; +import org.apache.sis.maths.Vector; import org.apache.sis.util.ArgumentChecks; @@ -226,7 +226,7 @@ public non-sealed class DefaultEllipsoid extends AbstractGeometry implements Ell } @Override - public DirectPosition getSurface(double u, double v) { + public Vector<?> getSurface(double u, double v) { 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 3d66ba5d88..e026be2fb6 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 @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.measure.Quantity; -import org.opengis.geometry.DirectPosition; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.geometries.BBox; import org.apache.sis.geometries.Curve; @@ -415,8 +414,8 @@ public non-sealed class DefaultNurbSurface extends AbstractGeometry implements N * Returns the position of this surface at the given parameters, computed by {@link #evaluate(double, double)}. */ @Override - public DirectPosition getSurface(double u, double v) { - return Vectors.asDirectPostion(evaluate(u, v)); + public Vector<?> getSurface(double u, double v) { + return evaluate(u, v); } } 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 a25f66c120..118f9dc4ec 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 org.opengis.geometry.DirectPosition; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.geometries.Curve; import org.apache.sis.geometries.DataPoints; @@ -29,6 +28,7 @@ import org.apache.sis.maths.DataType; import org.apache.sis.maths.NDArrays; import org.apache.sis.maths.ReadOnly; import org.apache.sis.maths.SampleSystem; +import org.apache.sis.maths.Vector; import org.apache.sis.util.ArgumentChecks; @@ -158,7 +158,7 @@ public non-sealed class DefaultSphere extends AbstractGeometry implements Sphere } @Override - public DirectPosition getSurface(double u, double v) { + public Vector<?> getSurface(double u, double v) { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/GeometryEnvelope.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/GeometryEnvelope.java new file mode 100644 index 0000000000..db98969084 --- /dev/null +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/GeometryEnvelope.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.geometries.internal.shared; + +import org.opengis.coordinate.MismatchedDimensionException; +import org.opengis.geometry.DirectPosition; +import org.opengis.geometry.Envelope; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.apache.sis.geometry.GeneralEnvelope; +import org.apache.sis.maths.DataType; +import org.apache.sis.maths.ReadOnly; +import org.apache.sis.maths.Vector; +import org.apache.sis.maths.Vectors; + + +/** + * An envelope whose positions can be given and obtained as vectors. Each method of {@link GeneralEnvelope} + * taking a {@link DirectPosition} has an overload taking a {@link ReadOnly.Vector}, and each method producing + * a {@code DirectPosition} has a counterpart producing a {@link Vector}, so that geometry algorithms working + * on vectors do not have to convert them. + * + * @author Johann Sorel (Geomatys) + */ +public class GeometryEnvelope extends GeneralEnvelope { + /** + * Constructs an envelope of the given number of dimensions, with no reference system. + * All coordinates are initialized to 0. + * + * @param dimension number of dimensions. + */ + public GeometryEnvelope(final int dimension) { + super(dimension); + } + + /** + * Constructs an envelope in the given reference system. + * All coordinates are initialized to 0. + * + * @param crs reference system of the envelope. + */ + public GeometryEnvelope(final CoordinateReferenceSystem crs) { + super(crs); + } + + /** + * Constructs an envelope with the reference system and the coordinates of the given envelope. + * + * @param envelope the envelope to copy. + */ + public GeometryEnvelope(final Envelope envelope) { + super(envelope); + } + + /** + * Constructs an envelope defined by two corners given as direct positions. + * + * @param lower lower corner. + * @param upper upper corner. + * @throws MismatchedDimensionException if the two positions do not have the same dimension. + */ + public GeometryEnvelope(final DirectPosition lower, final DirectPosition upper) throws MismatchedDimensionException { + super(lower, upper); + } + + /** + * Constructs an envelope defined by two corners given as vectors. + * The reference system is the one of the vectors. + * + * @param lower lower corner. + * @param upper upper corner. + * @throws MismatchedDimensionException if the two vectors do not have the same dimension. + */ + public GeometryEnvelope(final ReadOnly.Vector<?> lower, final ReadOnly.Vector<?> upper) throws MismatchedDimensionException { + super(asPosition(lower), asPosition(upper)); + } + + /** + * Returns a view of the given vector as a direct position. + */ + private static DirectPosition asPosition(final ReadOnly.Vector<?> vector) { + return Vectors.asDirectPostion((vector instanceof Vector<?> v) ? v : vector.copy()); + } + + /** + * Adds a position given as a vector to this envelope. + * + * @param position the position to add. + * @throws MismatchedDimensionException if the vector does not have the dimension of this envelope. + * + * @see #add(DirectPosition) + */ + public void add(final ReadOnly.Vector<?> position) throws MismatchedDimensionException { + add(asPosition(position)); + } + + /** + * Tests whether a position given as a vector is inside this envelope or on its border. + * + * @param position the position to test. + * @return whether the position is inside this envelope or on its border. + * @throws MismatchedDimensionException if the vector does not have the dimension of this envelope. + * + * @see #contains(DirectPosition) + */ + public boolean contains(final ReadOnly.Vector<?> position) throws MismatchedDimensionException { + return contains(asPosition(position)); + } + + /** + * Returns a new vector of the dimension and reference system of this envelope. + */ + private Vector<?> createVector() { + final CoordinateReferenceSystem crs = getCoordinateReferenceSystem(); + return (crs != null) ? Vectors.create(crs, DataType.DOUBLE) : Vectors.createDouble(getDimension()); + } + + /** + * Returns the lower corner of this envelope as a vector. + * Changes to the returned vector do not change this envelope. + * + * @return a copy of the lower corner. + * + * @see #getLowerCorner() + */ + public Vector<?> getLower() { + final Vector<?> corner = createVector(); + for (int i = 0, n = getDimension(); i < n; i++) { + corner.set(i, getLower(i)); + } + return corner; + } + + /** + * Returns the upper corner of this envelope as a vector. + * Changes to the returned vector do not change this envelope. + * + * @return a copy of the upper corner. + * + * @see #getUpperCorner() + */ + public Vector<?> getUpper() { + final Vector<?> corner = createVector(); + for (int i = 0, n = getDimension(); i < n; i++) { + corner.set(i, getUpper(i)); + } + return corner; + } + + /** + * Returns the median of this envelope as a vector. + * Changes to the returned vector do not change this envelope. + * + * @return the median position. + * + * @see #getMedian() + */ + public Vector<?> getCenter() { + final Vector<?> center = createVector(); + for (int i = 0, n = getDimension(); i < n; i++) { + center.set(i, getMedian(i)); + } + return center; + } + + /** + * Returns a copy of this envelope. + * + * @return a copy of this envelope. + */ + @Override + public GeometryEnvelope clone() { + return (GeometryEnvelope) super.clone(); + } +} 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 52e2d5582a..b28569b6a2 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,13 +18,13 @@ package org.apache.sis.geometries.solid; 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.DataPoints; import org.apache.sis.geometries.GeometryType; import org.apache.sis.geometries.Solid; import org.apache.sis.geometries.SolidInterpolation; import org.apache.sis.maths.Array; +import org.apache.sis.maths.Vector; /** @@ -219,5 +219,5 @@ public sealed interface ParametricCurveSolid extends Solid * * @see ISO 19107:2019 - 9.3.1 */ - DirectPosition getSurface(double a, double b, double c); + Vector<?> getSurface(double a, double b, double c); } 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 0d0bd0e803..444c689a67 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 @@ -28,6 +28,7 @@ import org.apache.sis.geometries.GeometryType; import org.apache.sis.geometries.Surface; import org.apache.sis.geometries.SurfaceInterpolation; import org.apache.sis.maths.Array; +import org.apache.sis.maths.Vector; // Specific to the geoapi-4.0 branch: import org.opengis.metadata.Identifier; @@ -232,7 +233,7 @@ public sealed interface ParametricCurveSurface extends Surface, ReferenceSystem * @see ISO 19107:2019 - 8.3.2.11 */ @UML(identifier="surface", specification=ISO_19107) - DirectPosition getSurface(double u, double v); + Vector<?> getSurface(double u, double v); /** * Returns the name of this surface used as a reference system for its parameter space. diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/internal/shared/GeometryEnvelopeTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/internal/shared/GeometryEnvelopeTest.java new file mode 100644 index 0000000000..7e5ddbb360 --- /dev/null +++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/internal/shared/GeometryEnvelopeTest.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.geometries.internal.shared; + +import org.apache.sis.maths.DataType; +import org.apache.sis.maths.Vector; +import org.apache.sis.maths.Vectors; + +// Test dependencies +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.apache.sis.geometries.GeometryTest; + + +/** + * Tests {@link GeometryEnvelope}. + * + * @author Johann Sorel (Geomatys) + */ +public class GeometryEnvelopeTest extends GeometryTest { + + private static Vector<?> vector(final double x, final double y) { + return Vectors.create(CRS_2D, DataType.DOUBLE).set(new double[] {x, y}); + } + + @Test + public void testConstructFromVectors() { + final var envelope = new GeometryEnvelope(vector(1, 2), vector(3, 5)); + assertEquals(CRS_2D, envelope.getCoordinateReferenceSystem()); + assertEquals(1, envelope.getMinimum(0), TOLERANCE); + assertEquals(2, envelope.getMinimum(1), TOLERANCE); + assertEquals(3, envelope.getMaximum(0), TOLERANCE); + assertEquals(5, envelope.getMaximum(1), TOLERANCE); + } + + @Test + public void testAddAndContains() { + final Vector<?> position = vector(1, 2); + final var envelope = new GeometryEnvelope(position, position); + envelope.add(vector(-4, 7)); + envelope.add(Vectors.unmodifiable(vector(3, 0))); + assertArrayEquals(new double[] {-4, 0}, envelope.getLower().toArrayDouble(), TOLERANCE); + assertArrayEquals(new double[] { 3, 7}, envelope.getUpper().toArrayDouble(), TOLERANCE); + assertTrue (envelope.contains(vector(0, 5))); + assertTrue (envelope.contains(vector(3, 7))); + assertFalse(envelope.contains(vector(4, 5))); + } + + @Test + public void testCorners() { + final var envelope = new GeometryEnvelope(vector(1, 2), vector(3, 6)); + final Vector<?> lower = envelope.getLower(); + final Vector<?> upper = envelope.getUpper(); + final Vector<?> center = envelope.getCenter(); + assertEquals(CRS_2D, lower.getCoordinateReferenceSystem()); + assertArrayEquals(new double[] {1, 2}, lower .toArrayDouble(), TOLERANCE); + assertArrayEquals(new double[] {3, 6}, upper .toArrayDouble(), TOLERANCE); + assertArrayEquals(new double[] {2, 4}, center.toArrayDouble(), TOLERANCE); + // The returned vectors are copies. + lower.set(0, -100); + assertEquals(1, envelope.getMinimum(0), TOLERANCE); + } + + @Test + public void testNoCRS() { + final var envelope = new GeometryEnvelope(3); + envelope.setEnvelope(0, 0, 0, 1, 2, 3); + assertArrayEquals(new double[] {1, 2, 3}, envelope.getUpper().toArrayDouble(), TOLERANCE); + } + + @Test + public void testClone() { + final var envelope = new GeometryEnvelope(vector(1, 2), vector(3, 6)); + final GeometryEnvelope clone = envelope.clone(); + assertEquals(envelope, clone); + assertNotSame(envelope, clone); + } +}
