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 6f09d78b5154c11b7627c5c60f3dfea72683d875 Author: jsorel <[email protected]> AuthorDate: Wed Sep 9 15:58:31 2026 +0200 feat(Geometry): add Geometry javadoc --- .../main/org/apache/sis/geometries/Geometry.java | 755 ++++++++++++++++++--- .../geometries/operation/GeometryProcessor.java | 20 +- .../org/apache/sis/geometries/package-info.java | 2 +- .../sis/geometries/operation/DistanceTest.java | 12 +- 4 files changed, 683 insertions(+), 106 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 14318c0161..57a6d8422d 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 @@ -32,7 +32,26 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem; /** - * Parent interface of any geometry. + * Parent interface of any geometry, a set of {@link DirectPosition} in a coordinate reference system. + * + * <p>A geometry behaves as a possibly infinite set of positions, and therefore supports the usual + * set-theoretic operations. Since an infinite collection cannot be implemented directly, membership + * is tested through {@link #contains(DirectPosition)}.</p> + * + * <p>Constraints:</p> + * <ul> + * <li>Geometries are metrically closed: any position whose distance to the geometry is zero + * belongs to it. Curves contain their end points, surfaces their boundary curves, + * and solids their boundary surfaces.</li> + * <li>All positions and geometries returned by an accessor use the coordinate reference system + * of this geometry, unless the operation explicitly specifies another one.</li> + * <li>All elements of a geometry collection use the coordinate reference system of the collection.</li> + * <li>An operation computes in the coordinate reference system of the first geometry accessed, + * usually the geometry on which the operation is invoked, and returns its result in that + * same system unless stated otherwise.</li> + * <li>This interface is abstract: no application schema can instantiate it directly.</li> + * </ul> + * * <p> * Based on specification : * <ul> @@ -50,8 +69,10 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem; * therefor we merged TransfiniteSetOfDirectPositions in Geometry for simplicity state * * @author Johann Sorel (Geomatys) + * + * @see ISO 19107:2019 - 6.4.4 */ -@UML(identifier="Geometry", specification=ISO_19107) // section 6.4.4 +@UML(identifier="Geometry", specification=ISO_19107) public sealed interface Geometry permits Primitive, GeometryCollection, @@ -64,32 +85,50 @@ public sealed interface Geometry { /** - * Get geometry coordinate system. + * Coordinate reference system of all the coordinates used within this geometry. * - * Difference with ISO 19107 : - * In 19107 their may be multiple RSID, the folloing RSID are used in special - * kind of curves, for the sake of simplicity we only store the first rsid until - * implementations of such curves will happen. + * <p>Constraints:</p> + * <ul> + * <li>All positions and geometries returned when accessing this geometry use this system, + * unless another one is implied or provided by the operation.</li> + * <li>A geometry contained in another one shall use a system consistent with the container.</li> + * </ul> * - * @return never null + * <p>Difference with ISO 19107: in ISO 19107 there may be multiple RSID, the following RSID + * are used in special kind of curves; for the sake of simplicity we only store the first rsid + * until implementations of such curves will happen.</p> + * + * @return coordinate reference system of this geometry, never null. + * + * @see ISO 19107:2019 - 6.4.4.20 */ - @UML(identifier="rsid", specification=ISO_19107) // section 6.4.4.20 + @UML(identifier="rsid", specification=ISO_19107) CoordinateReferenceSystem getCoordinateReferenceSystem(); /** - * Set coordinate system in which the coordinates are declared. + * Sets the coordinate system in which the coordinates are declared. * This method does not transform the coordinates. * - * @param crs , not null - * @Throws IllegalArgumentException if coordinate system is not compatible with geometrie. + * <p>Difference with ISO 19107: geometries are immutable in the standard, + * which offers no such setter.</p> + * + * @param crs the new coordinate reference system, not null. + * @throws IllegalArgumentException if the coordinate system is not compatible with the geometry. */ void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) throws IllegalArgumentException; /** - * Difference with ISO 19107 : - * we return a single Metadata instead of a list of URI. + * Documentation about the implementation of this geometry. + * When absent, the applicable documentation is ISO 19107 itself. + * + * <p>Difference with ISO 19107: we return a single Metadata instead of a list of URI, + * whose first element would point to the normative document describing this geometry.</p> + * + * @return metadata about this geometry. + * + * @see ISO 19107:2019 - 6.4.4.18 */ - @UML(identifier="metadata", specification=ISO_19107) // section 6.4.4.18 + @UML(identifier="metadata", specification=ISO_19107) default Metadata getMetadata() { throw new UnsupportedOperationException(); } @@ -97,37 +136,91 @@ public sealed interface Geometry /** * Get geometry attributes type. * + * <p>Difference with ISO 19107: this accessor has no equivalent in the standard. + * It describes the attributes carried by the geometry positions in addition to the + * coordinates, as needed by GLTF or GPU models.</p> + * * @return attributes type, never null */ AttributesType getAttributesType(); /** - * Get the geometry number of dimensions.<br> - * This is the same as coordinate system dimension. + * Number of axes in the coordinate reference system of this geometry. * * @return number of dimension + * + * @see ISO 19107:2019 - 6.4.4.11 */ - @UML(identifier="coordinateDimension", specification=ISO_19107) // section 6.4.4.11 + @UML(identifier="coordinateDimension", specification=ISO_19107) default int getDimension() { return getCoordinateReferenceSystem().getCoordinateSystem().getDimension(); } - @UML(identifier="dimension", specification=ISO_19107) // section 6.4.4.25 + /** + * Returns the inherent topological dimension of this geometry at the given position. + * + * <p>Constraints:</p> + * <ul> + * <li>The returned value is smaller than or equal to the {@linkplain #getDimension() + * coordinate dimension}.</li> + * <li>The dimension is unambiguous only for positions interior to this geometry.</li> + * <li>If the given position is null, the largest dimension found in the interior of this + * geometry is returned.</li> + * </ul> + * + * @param point position where to evaluate the dimension, or null for the whole geometry. + * @return topological dimension at the given position. + * + * @see ISO 19107:2019 - 6.4.4.25 + */ + @UML(identifier="dimension", specification=ISO_19107) default int getDimension(DirectPosition point) { throw new UnsupportedOperationException(); } - @UML(identifier="is3D", specification=ISO_19107) // section 6.4.4.13 + /** + * Returns whether this geometry uses three spatial dimensions. + * + * <p>Constraints:</p> + * <ul> + * <li>If {@code true}, then the {@linkplain #getSpatialDimension() spatial dimension} is 3.</li> + * </ul> + * + * @return {@code true} if this geometry is three-dimensional. + * + * @see ISO 19107:2019 - 6.4.4.13 + */ + @UML(identifier="is3D", specification=ISO_19107) default boolean is3D() { return getDimension() == 3; } - @UML(identifier="spatialDimension", specification=ISO_19107) // section 6.4.4.21 + /** + * Number of spatial axes in the coordinate reference system of this geometry, usually 2 or 3. + * + * @return number of spatial dimensions. + * + * @see ISO 19107:2019 - 6.4.4.21 + */ + @UML(identifier="spatialDimension", specification=ISO_19107) default int getSpatialDimension() { return getDimension(); } - @UML(identifier="topologicalDimension", specification=ISO_19107) // section 6.4.4.22 + /** + * Largest topological dimension among the components of this geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>−1 for an empty geometry, 0 for a point, 1 for a curve, 2 for a surface, 3 for a solid.</li> + * <li>For a collection, the maximum of the dimensions of the contained primitives.</li> + * </ul> + * + * @return topological dimension of this geometry. + * + * @see ISO 19107:2019 - 6.4.4.22 + */ + @UML(identifier="topologicalDimension", specification=ISO_19107) default int getTopologicDimension() { if (this instanceof Empty) { return -1; @@ -143,7 +236,24 @@ public sealed interface Geometry throw new UnsupportedOperationException(); } - @UML(identifier="boundaryType", specification=ISO_19107) // section 6.4.8 + /** + * Rule used to compute the {@linkplain #boundary() boundary} of this geometry + * in the ambiguous cases raised by aggregates. + * + * <p>Constraints:</p> + * <ul> + * <li>{@code METRIC} derives the boundary from distances, as in a metric space.</li> + * <li>{@code MOD_2} puts in the boundary the positions lying on an odd number of element + * boundaries, and in the interior those lying on an even number.</li> + * <li>{@code AT_LEAST_2} puts in the boundary the positions lying on exactly one element + * boundary, and in the interior those lying on more than one.</li> + * </ul> + * + * @return rule used to compute the boundary of this geometry. + * + * @see ISO 19107:2019 - 6.4.3, 10.8.3 + */ + @UML(identifier="boundaryType", specification=ISO_19107) default BoundaryType getBoundaryType() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); @@ -153,12 +263,28 @@ public sealed interface Geometry * Returns the name of the instantiable subtype of Geometry of which this geometric object is an instantiable member.<br> * The name of the subtype of Geometry is returned as a string. * - * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 * @return geometry subtype name. + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * @see ISO 19107:2019 - 6.4.4.23 */ String getGeometryType(); - @UML(identifier="type", specification=ISO_19107) // section 6.4.4.23 + /** + * Interfaces of this standard, or of its extensions, supported by this geometry instance. + * + * <p>Constraints:</p> + * <ul> + * <li>At least one value, taken from the types the implementation declares as supported.</li> + * <li>The values are the most specific types applicable to this instance.</li> + * <li>An empty geometry is of type {@code EMPTY}.</li> + * </ul> + * + * @return types of this geometry. + * + * @see ISO 19107:2019 - 6.4.4.23 + */ + @UML(identifier="type", specification=ISO_19107) default List<GeometryType> getGeometryType2() { //TODO merge with getGeometryType throw new UnsupportedOperationException(); @@ -171,42 +297,92 @@ public sealed interface Geometry * The simplest representation of an Envelope is as two direct positions, one containing all the minimums, and another all the maximums.<br> * In some cases, this coordinate will be outside the range of validity for the Spatial Reference System. * - * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * <p>Constraints:</p> + * <ul> + * <li>Smallest coordinate rectangle containing all the positions of this geometry.</li> + * <li>The envelope of an empty geometry is the empty geometry.</li> + * <li>If the coordinate system wraps around a singularity, several representations of the + * envelope are possible and the choice is left to the implementation.</li> + * </ul> + * * @return Envelope in geometry coordinate reference system. + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * @see ISO 19107:2019 - 6.4.4.12 */ - @UML(identifier="envelope", specification=ISO_19107) // section 6.4.4.12 + @UML(identifier="envelope", specification=ISO_19107) Envelope getEnvelope(); /** * The mathematical centroid for this Geometry as a Point. * The result is not guaranteed to be on this Geometry. * - * Difference from OGC SFA : this method in declared on Surface and MultiSurface - * but in ISO 19107 it is on Geometry. + * <p>Constraints:</p> + * <ul> + * <li>In a heterogeneous collection, only the components of the largest dimension contribute; + * for surfaces the average is weighted by area, and curves having no area are ignored.</li> + * <li>The centroid may fall outside the domain of validity of the coordinate reference system.</li> + * <li>The centroid of an empty geometry is the empty geometry.</li> + * </ul> + * + * <p>Difference from OGC SFA : this method in declared on Surface and MultiSurface + * but in ISO 19107 it is on Geometry.</p> * - * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2 * @return centroid for this Geometry + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.10.2 + * @see ISO 19107:2019 - 6.4.4.8 */ - @UML(identifier="centroid", specification=ISO_19107) // section 6.4.4.8 + @UML(identifier="centroid", specification=ISO_19107) default Point getCentroid() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); } - @UML(identifier="representativePoint", specification=ISO_19107) // section 6.4.4.19 + /** + * A position guaranteed to be interior to this geometry, for example for label placement. + * The {@linkplain #getCentroid() centroid} is a suitable value when it lies inside this geometry. + * + * @return a position interior to this geometry. + * + * @see ISO 19107:2019 - 6.4.4.19 + */ + @UML(identifier="representativePoint", specification=ISO_19107) default Point getRepresentativePoint() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); } - @UML(identifier="convexHull", specification=ISO_19107) // section 6.4.4.10 - default Geometry getConvexHull() { + /** + * Union of this geometry and of its {@linkplain #boundary() boundary}. + * + * @return closure of this geometry, in the coordinate reference system of this geometry. + * + * @see ISO 19107:2019 - 6.4.4.9 + */ + @UML(identifier="closure", specification=ISO_19107) + default Geometry getClosure() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); } - @UML(identifier="closure", specification=ISO_19107) // section 6.4.4.9 - default Geometry getClosure() { + /** + * Smallest geometry containing this geometry within which this geometry is a subset, + * or {@code null} if the application schema has no notion of complex. + * + * <p>Constraints:</p> + * <ul> + * <li>A geometry is maximal when no larger super-set of it exists in the same dataset.</li> + * <li>A primitive usually belongs to a single maximal complex, which makes the relationship + * a strong aggregation.</li> + * </ul> + * + * @return maximal complex containing this geometry, or {@code null} if none. + * + * @see ISO 19107:2019 - 6.4.4.17 + */ + @UML(identifier="maximalComplex", specification=ISO_19107) + default Geometry getMaximalComplex() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); } @@ -214,14 +390,16 @@ public sealed interface Geometry /** * Exports this geometric object to a specific Well-known Text Representation of Geometry. * - * Difference with ISO 19107 : + * <p>Difference with ISO 19107 : * - this method is located on Encoding sub interface in the standard, it is placed - * on Geometry to match OGC SFA. + * on Geometry to match OGC SFA.</p> * - * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 * @return this geometry in Well-known Text + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * @see ISO 19107:2019 - 6.4.4.5, 6.4.7 */ - @UML(identifier="asText", specification=ISO_19107) // section 6.4.4.5 + @UML(identifier="asText", specification=ISO_19107) default String asText() { //TODO remove this method default when all classes implement it. return this.getClass().getSimpleName(); @@ -230,14 +408,16 @@ public sealed interface Geometry /** * Exports this geometric object to a specific Well-known Binary Representation of Geometry. * - * Difference with ISO 19107 : + * <p>Difference with ISO 19107 : * - this method is located on Encoding sub interface in the standard, it is placed - * on Geometry to match OGC SFA. + * on Geometry to match OGC SFA.</p> * - * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 * @return this geometry in Well-known Binary + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * @see ISO 19107:2019 - 6.4.4.3, 6.4.7 */ - @UML(identifier="asBinary", specification=ISO_19107) // section 6.4.4.3 + @UML(identifier="asBinary", specification=ISO_19107) default byte[] asBinary() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); @@ -247,10 +427,23 @@ public sealed interface Geometry * Returns TRUE if this geometric object is the empty Geometry. * If true, then this geometric object represents the empty point set ∅ for the coordinate space. * - * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * <p>Constraints:</p> + * <ul> + * <li>The empty set being unique, all empty geometries are spatially equal.</li> + * <li>The {@linkplain #getTopologicDimension() topological dimension} of an empty geometry is −1, + * and its {@linkplain #getGeometryType2() type} is {@code EMPTY}.</li> + * <li>Every derived geometry is empty as well, and every derived position is null.</li> + * <li>{@link #isCycle()}, {@link #isSimple()} and {@link #isValid()} are all {@code true} + * for an empty geometry.</li> + * <li>The distance from an empty geometry to any geometry is infinite.</li> + * </ul> + * * @return true if empty. + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * @see ISO 19107:2019 - 6.4.4.2, 6.4.10 */ - @UML(identifier="isEmpty", specification=ISO_19107) // section 6.4.4.2 + @UML(identifier="isEmpty", specification=ISO_19107) boolean isEmpty(); /** @@ -258,22 +451,58 @@ public sealed interface Geometry * The description of each instantiable geometric class will include the specific conditions that cause an instance * of that class to be classified as not simple. * - * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * <p>Constraints:</p> + * <ul> + * <li>{@code false} if and only if this geometry has a point of self intersection or of self tangency.</li> + * <li>Equivalently, every interior position has a neighbourhood whose intersection with this + * geometry is topologically isomorphic to an <var>n</var>-sphere, where <var>n</var> is the + * {@linkplain #getTopologicDimension() topological dimension}.</li> + * </ul> + * * @return true if geometry is simple + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * @see ISO 19107:2019 - 6.4.4.15 */ - @UML(identifier="isSimple", specification=ISO_19107) // section 6.4.4.15 + @UML(identifier="isSimple", specification=ISO_19107) default boolean isSimple() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); } - @UML(identifier="isCycle", specification=ISO_19107) // section 6.4.4.14 + /** + * Returns whether this geometry closes on itself, i.e. whether its + * {@linkplain #boundary() boundary} is empty. + * + * <p>Constraints:</p> + * <ul> + * <li>A point and the empty geometry are always cycles.</li> + * <li>A curve is a cycle if its start point is its end point.</li> + * <li>A surface is a cycle if it is isomorphic to a sphere or to a torus.</li> + * <li>A solid of finite size in a 3-dimensional coordinate space is never a cycle.</li> + * </ul> + * + * <p>ISO 19107 uses <cite>cycle</cite> rather than <cite>closed</cite>, because the latter has + * two distinct and incompatible meanings in topology.</p> + * + * @return {@code true} if this geometry is a cycle. + * + * @see ISO 19107:2019 - 6.4.4.14 + */ + @UML(identifier="isCycle", specification=ISO_19107) default boolean isCycle() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); } - @UML(identifier="isValid", specification=ISO_19107) // section 6.4.4.16 + /** + * Returns whether the structure of this geometry is valid as a geometry. + * + * @return {@code true} if this geometry is valid. + * + * @see ISO 19107:2019 - 6.4.4.16 + */ + @UML(identifier="isValid", specification=ISO_19107) default boolean isValid() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); @@ -284,10 +513,27 @@ public sealed interface Geometry * Because the result of this function is a closure, and hence topologically closed, the resulting boundary can be * represented using representational Geometry primitives (Reference [1], section 3.12.2). * - * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * <p>Constraints:</p> + * <ul> + * <li>The boundary is expressed in the coordinate reference system of this geometry.</li> + * <li>Its {@linkplain #getTopologicDimension() topological dimension} is one less than the + * dimension of this geometry, unless this geometry is empty or is a + * {@linkplain #isCycle() cycle}, in which case the boundary is empty.</li> + * <li>The boundary of a point, and of any finite set of points, is empty.</li> + * <li>The boundary of a curve is its start point and its end point.</li> + * <li>The boundary of a surface is a set of simple curves, each of them a cycle having the + * surface on its left but not on its right.</li> + * <li>The boundary of a solid is a set of surfaces, each of them a cycle.</li> + * <li>How the boundary of an aggregate is computed depends on + * {@linkplain #getBoundaryType() the boundary type}.</li> + * </ul> + * * @return boundary of the geometry + * + * @see OGC Simple Feature Access 1.2.1 - 6.1.2.2 + * @see ISO 19107:2019 - 6.4.4.7, 10.8.3 */ - @UML(identifier="boundary", specification=ISO_19107) // section 6.4.4.7 + @UML(identifier="boundary", specification=ISO_19107) default Geometry boundary() { //TODO remove this method default when all classes implement it. throw new UnsupportedOperationException(); @@ -297,6 +543,8 @@ public sealed interface Geometry * Map of properties for user needs. * Those informations may be lost in geometry processes. * + * <p>Difference with ISO 19107: this accessor has no equivalent in the standard.</p> + * * @return Map, can be null if the geometry cannot store additional informations. */ default Map<String,Object> userProperties() { @@ -308,6 +556,16 @@ public sealed interface Geometry // //////////////////////////////////////////////////////////////////////// /** + * Returns a geometry containing all the positions closer to this geometry than the given distance, + * expressed in the units of the coordinate reference system. + * + * <p>Difference with ISO 19107, which takes a distance quantity: + * see {@link #buffer(Length)} for the standard operation.</p> + * + * @param distance radius of the buffer. + * @return buffer around this geometry. + * @throws OperationException if the buffer cannot be computed. + * * @see GeometryProcessor#buffer(org.apache.sis.geometries.Geometry, double) */ public default Geometry buffer(double distance) throws OperationException { @@ -315,128 +573,340 @@ public sealed interface Geometry } /** + * Returns a geometry containing all the positions whose distance to this geometry + * is smaller than or equal to the given radius. + * + * <p>Constraints:</p> + * <ul> + * <li>A zero radius returns a geometry equal to this geometry.</li> + * <li>A negative radius returns the positions inside this geometry whose distance to its + * boundary is greater than the absolute value of the radius.</li> + * <li>The result is expressed in the coordinate reference system of this geometry, and its + * topological dimension is usually the spatial dimension of that system.</li> + * <li>The buffer of an empty geometry is the empty geometry.</li> + * </ul> + * + * @param radius radius of the buffer. + * @return buffer around this geometry. + * @throws OperationException if the buffer cannot be computed. + * * @see GeometryProcessor#buffer(org.apache.sis.geometries.Geometry, javax.measure.quantity.Length) + * @see ISO 19107:2019 - 6.4.4.24, 6.4.8.3, 6.4.9 */ - @UML(identifier="buffer", specification=ISO_19107) // section 6.4.4.24 and 6.4.8.3 - //@UML(identifier="3Dbuffer", specification=ISO_19107) // section 6.4.9 + @UML(identifier="buffer", specification=ISO_19107) + //@UML(identifier="3Dbuffer", specification=ISO_19107) public default Geometry buffer(Length radius) throws OperationException { return new GeometryProcessor().buffer(this, radius); } /** + * Returns the smallest convex set containing this geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>Convexity depends on the meaning given to a straight line, therefore the result + * depends on the coordinate reference system in use.</li> + * <li>The convex hull may fall outside the domain of validity of the coordinate reference system.</li> + * <li>The convex hull of an empty geometry is the empty geometry.</li> + * </ul> + * + * @return convex hull of this geometry. + * @throws OperationException if the convex hull cannot be computed. + * * @see GeometryProcessor#convexHull(org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.10, 6.4.9 */ - //@UML(identifier="3DconvexHull", specification=ISO_19107) // section 6.4.9 + @UML(identifier="convexHull", specification=ISO_19107) + //@UML(identifier="3DconvexHull", specification=ISO_19107) public default Geometry convexHull() throws OperationException { return new GeometryProcessor().convexHull(this); } /** + * Returns the set-theoretic difference between this geometry and the given geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>The difference of two closed sets is not necessarily closed, therefore the result may + * differ from the topological difference along its boundary.</li> + * <li>The difference between this geometry and an empty geometry is this geometry.</li> + * </ul> + * + * @param other the geometry to subtract from this geometry. + * @return this geometry minus the given geometry. + * @throws OperationException if the difference cannot be computed. + * * @see GeometryProcessor#difference(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.30, 6.4.8.5, 6.4.9 */ - @UML(identifier="difference", specification=ISO_19107) // section 6.4.4.30 and 6.4.8.5 - //@UML(identifier="3Ddifference", specification=ISO_19107) // section 6.4.9 + @UML(identifier="difference", specification=ISO_19107) + //@UML(identifier="3Ddifference", specification=ISO_19107) public default Geometry difference(Geometry other) throws OperationException { return new GeometryProcessor().difference(this, other); } /** + * Returns the shortest distance between this geometry and the given geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>Zero if the two geometries intersect.</li> + * <li>Consistent with the geometric reference surface in use, therefore a map distance, + * a geodesic distance or a terrain distance depending on that surface.</li> + * <li>Infinite if either geometry is empty.</li> + * </ul> + * + * @param other the geometry to measure the distance to. + * @return distance between the two geometries. + * @throws OperationException if the distance cannot be computed. + * * @see GeometryProcessor#distance(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.26, 6.4.8.2, 6.4.9 */ - public default double distance(Geometry other) throws OperationException { + @UML(identifier="distance", specification=ISO_19107) + //@UML(identifier="3Ddistance", specification=ISO_19107) + public default Length distance(Geometry other) throws OperationException { return new GeometryProcessor().distance(this, other); } /** - * @see GeometryProcessor#distance2(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) - */ - @UML(identifier="distance", specification=ISO_19107) // section 6.4.4.26 and 6.4.8.2 - //@UML(identifier="3Ddistance", specification=ISO_19107) // section 6.4.9 - public default Length distance2(Geometry other) throws OperationException { - return new GeometryProcessor().distance2(this, other); - } - - /** + * Returns the set-theoretic intersection of this geometry and the given geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>The intersection of two closed sets being closed, the result matches the topological + * intersection within the precision of the geometric representations.</li> + * <li>The intersection with an empty geometry is the empty geometry.</li> + * </ul> + * + * @param other the geometry to intersect with this geometry. + * @return intersection of the two geometries. + * @throws OperationException if the intersection cannot be computed. + * * @see GeometryProcessor#intersection(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.30, 6.4.8.4, 6.4.9 */ - @UML(identifier="intersection", specification=ISO_19107) // section 6.4.4.30 and 6.4.8.4 - //@UML(identifier="3Dintersection", specification=ISO_19107) // section 6.4.9 + @UML(identifier="intersection", specification=ISO_19107) + //@UML(identifier="3Dintersection", specification=ISO_19107) public default Geometry intersection(Geometry other) throws OperationException { return new GeometryProcessor().intersection(this, other); } /** + * Returns the set-theoretic symmetric difference of this geometry and the given geometry, + * that is (A−B) ∪ (B−A). + * + * <p>Constraints:</p> + * <ul> + * <li>The symmetric difference of two closed sets is not necessarily closed, therefore the + * result may differ from the topological answer along its boundary.</li> + * <li>The symmetric difference between this geometry and an empty geometry is this geometry.</li> + * </ul> + * + * @param other the geometry to combine with this geometry. + * @return symmetric difference of the two geometries. + * @throws OperationException if the symmetric difference cannot be computed. + * * @see GeometryProcessor#symDifference(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.30, 6.4.8.6, 6.4.9 */ - @UML(identifier="symDifference", specification=ISO_19107) // section 6.4.4.30 and 6.4.8.6 - //@UML(identifier="3DsymDifference", specification=ISO_19107) // section 6.4.9 + @UML(identifier="symDifference", specification=ISO_19107) + //@UML(identifier="3DsymDifference", specification=ISO_19107) public default Geometry symDifference(Geometry other) throws OperationException { return new GeometryProcessor().symDifference(this, other); } /** + * Returns the set-theoretic union of this geometry and the given geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>The union of two closed sets being closed, the result matches the topological union + * within the precision of the geometric representations.</li> + * <li>The union with an empty geometry is this geometry.</li> + * </ul> + * + * @param other the geometry to unite with this geometry. + * @return union of the two geometries. + * @throws OperationException if the union cannot be computed. + * * @see GeometryProcessor#union(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.30, 6.4.8.7, 6.4.9 */ - @UML(identifier="union", specification=ISO_19107) // section 6.4.4.30 and 6.4.8.7 - //@UML(identifier="3Dunion", specification=ISO_19107) // section 6.4.9 + @UML(identifier="union", specification=ISO_19107) + //@UML(identifier="3Dunion", specification=ISO_19107) public default Geometry union(Geometry other) throws OperationException { return new GeometryProcessor().union(this, other); } /** + * Returns this geometry expressed in the given coordinate reference system. + * + * <p>Constraints:</p> + * <ul> + * <li>The returned geometry is equal to this geometry within the accuracy of the transformation.</li> + * <li>Non-spatial coordinates follow their own logic for converting to a compatible system; + * a purely spatial geometry is only submitted to a change of coordinates.</li> + * <li>The returned geometry is of the same type as this geometry whenever possible.</li> + * </ul> + * + * <p>Difference with ISO 19107, which identifies the target system by a RSID: + * the target system is given as a {@link CoordinateReferenceSystem}.</p> + * + * @param crs the target coordinate reference system. + * @return this geometry in the given coordinate reference system. + * + * @see GeometryProcessor#transform(org.apache.sis.geometries.Geometry, org.opengis.referencing.crs.CoordinateReferenceSystem, org.opengis.referencing.operation.MathTransform) + * @see ISO 19107:2019 - 6.4.4.28 + */ + @UML(identifier="transform", specification=ISO_19107) + public default Geometry transform(CoordinateReferenceSystem crs) { + return new GeometryProcessor().transform(this, crs, null); + } + + /** + * Returns whether the given position belongs to this geometry. + * This is the membership test which stands for this geometry being a possibly infinite + * set of positions. + * + * @param element the position to test. + * @return {@code true} if the given position is on this geometry. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#contains(org.apache.sis.geometries.Geometry, org.opengis.geometry.DirectPosition) + * @see ISO 19107:2019 - 6.4.2, 6.4.4.30, 6.4.9 */ - @UML(identifier="contains", specification=ISO_19107) // section 6.4.4.30 ? - //@UML(identifier="3Dcontains", specification=ISO_19107) // section 6.4.9 + @UML(identifier="contains", specification=ISO_19107) + //@UML(identifier="3Dcontains", specification=ISO_19107) public default boolean contains(DirectPosition element) throws OperationException { return new GeometryProcessor().contains(this, element); } /** + * Returns whether the given geometry is a subset of this geometry, that is whether no position + * of the given geometry lies in the exterior of this geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>Equivalent to {@code relate(other, "TNNNNNFFN")}.</li> + * <li>{@code a.contains(b)} is equivalent to {@code b.within(a)}.</li> + * </ul> + * + * @param other the geometry to test for inclusion. + * @return {@code true} if this geometry contains the given geometry. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#contains(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.30, 6.4.8.8, 10.8.6.3.2 */ - @UML(identifier="contains", specification=ISO_19107) // section 6.4.8.8, 6.4.4.2 + @UML(identifier="contains", specification=ISO_19107) public default boolean contains(Geometry other) throws OperationException { return new GeometryProcessor().contains(this, other); } /** + * Returns whether the two geometries cross, that is whether their interiors intersect in a set + * of dimension lower than the largest of their dimensions, without either geometry containing + * the other. + * + * <p>Constraints:</p> + * <ul> + * <li>Applies to the point/curve, point/surface, curve/curve and curve/surface cases.</li> + * </ul> + * + * @param other the geometry to test against. + * @return {@code true} if the two geometries cross. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#crosses(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.8.8, 6.4.9, 10.8.6.3.6 */ - @UML(identifier="crosses", specification=ISO_19107) // section 6.4.8.8 - //@UML(identifier="3Dcrosses", specification=ISO_19107) // section 6.4.9 + @UML(identifier="crosses", specification=ISO_19107) + //@UML(identifier="3Dcrosses", specification=ISO_19107) public default boolean crosses(Geometry other) throws OperationException { return new GeometryProcessor().crosses(this, other); } /** + * Returns whether the two geometries have no position in common. + * + * <p>Constraints:</p> + * <ul> + * <li>Equivalent to {@code relate(other, "FFNFFNNNN")}, or {@code "FNNN"} on the order 4 matrix.</li> + * <li>The negation of {@link #intersects(Geometry)}.</li> + * </ul> + * + * @param other the geometry to test against. + * @return {@code true} if the two geometries are disjoint. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#disjoint(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.8.8, 6.4.9, 10.8.6.3.3 */ - @UML(identifier="disjoint", specification=ISO_19107) // section 6.4.8.8 - //@UML(identifier="3Ddisjoint", specification=ISO_19107) // section 6.4.9 + @UML(identifier="disjoint", specification=ISO_19107) + //@UML(identifier="3Ddisjoint", specification=ISO_19107) public default boolean disjoint(Geometry other) throws OperationException { return new GeometryProcessor().disjoint(this, other); } /** + * Returns whether the two geometries are the same set of positions. + * + * <p>Constraints:</p> + * <ul> + * <li>Equivalent to {@code relate(other, "NFFFNFNNF")}.</li> + * <li>Only the spatial coordinates are compared, so a spatio-temporal geometry is tested + * for spatial equality only.</li> + * <li>The given geometry is converted to the coordinate reference system of this geometry + * before the comparison.</li> + * <li>Any two empty geometries are equal.</li> + * </ul> + * + * @param other the geometry to compare with. + * @return {@code true} if the two geometries are spatially equal. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#equal(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.27, 6.4.4.30, 6.4.8.8, 6.4.9, 10.8.6.3.1 */ - @UML(identifier="equals", specification=ISO_19107) // section 6.4.8.8, 6.4.4.30 - //@UML(identifier="3Dequals", specification=ISO_19107) // section 6.4.9 + @UML(identifier="equals", specification=ISO_19107) + //@UML(identifier="3Dequals", specification=ISO_19107) public default boolean equal(Geometry other) throws OperationException { return new GeometryProcessor().equal(this, other); } /** + * Returns whether the two geometries have at least one position in common. + * + * <p>Constraints:</p> + * <ul> + * <li>Equivalent to {@code relate(other, "TNNN")} on the order 4 matrix.</li> + * <li>The negation of {@link #disjoint(Geometry)}.</li> + * </ul> + * + * @param other the geometry to test against. + * @return {@code true} if the two geometries intersect. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#intersects(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.4.30, 6.4.8.8, 6.4.9, 10.8.6.3.4 */ - @UML(identifier="intersects", specification=ISO_19107) // section 6.4.8.8, 6.4.4.30 - //@UML(identifier="3Dintersects", specification=ISO_19107) // section 6.4.9 + @UML(identifier="intersects", specification=ISO_19107) + //@UML(identifier="3Dintersects", specification=ISO_19107) public default boolean intersects(Geometry other) throws OperationException { return new GeometryProcessor().intersects(this, other); } /** + * Returns the part of this geometry located at the given measure along a linear reference. + * + * <p>Difference with ISO 19107: this operation has no equivalent in the standard, + * which delegates linear referencing to ISO 19148.</p> + * + * @param mValue measure value at which to locate. + * @return part of this geometry at the given measure. + * @throws OperationException if the location cannot be computed. + * * @see GeometryProcessor#locateAlong(org.apache.sis.geometries.Geometry, double) */ public default Geometry locateAlong(double mValue) throws OperationException { @@ -444,6 +914,16 @@ public sealed interface Geometry } /** + * Returns the part of this geometry located between the two given measures along a linear reference. + * + * <p>Difference with ISO 19107: this operation has no equivalent in the standard, + * which delegates linear referencing to ISO 19148.</p> + * + * @param mStart measure value where the returned geometry begins. + * @param mEnd measure value where the returned geometry ends. + * @return part of this geometry between the two given measures. + * @throws OperationException if the location cannot be computed. + * * @see GeometryProcessor#contains(org.apache.sis.geometries.Geometry, double, double) */ public default Geometry locateBetween(double mStart, double mEnd) throws OperationException { @@ -451,15 +931,40 @@ public sealed interface Geometry } /** + * Returns whether the two geometries have the same dimension and their interiors intersect, + * without either geometry containing the other. + * + * <p>Constraints:</p> + * <ul> + * <li>Equivalent to {@code relate(other, "TNTNNNTNN")}.</li> + * <li>Symmetric: {@code a.overlaps(b)} is equivalent to {@code b.overlaps(a)}.</li> + * </ul> + * + * @param other the geometry to test against. + * @return {@code true} if the two geometries overlap. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#overlaps(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.8.8, 6.4.9, 10.8.6.3.8 */ - @UML(identifier="overlaps", specification=ISO_19107) // section 6.4.8.8 - //@UML(identifier="3Doverlaps", specification=ISO_19107) // section 6.4.9 + @UML(identifier="overlaps", specification=ISO_19107) + //@UML(identifier="3Doverlaps", specification=ISO_19107) public default boolean overlaps(Geometry other) throws OperationException { return new GeometryProcessor().overlaps(this, other); } /** + * Returns whether the two geometries are related according to the given intersection pattern, + * encoded as an integer mask. + * + * <p>Difference with ISO 19107, which specifies the pattern as a string: + * see {@link #relate(Geometry, String)} for the standard operation.</p> + * + * @param other the geometry to test against. + * @param matrix intersection pattern, encoded as an integer mask. + * @return {@code true} if the two geometries match the given pattern. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#relate(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry, int) */ public default boolean relate(Geometry other, int matrix) throws OperationException { @@ -467,37 +972,99 @@ public sealed interface Geometry } /** + * Returns whether the two geometries are related according to the given intersection pattern. + * This is the reference operation from which all the named topological predicates are derived. + * + * <p>Constraints:</p> + * <ul> + * <li>A pattern of 4 characters tests the intersections between the closures and the exteriors + * of the two geometries, in row-major order.</li> + * <li>A pattern of 9 characters tests the intersections between the interiors, the boundaries + * and the exteriors of the two geometries, in row-major order.</li> + * <li>{@code T} requires a non-empty intersection, {@code F} an empty one, and {@code N} + * (also written {@code *}) leaves that cell untested.</li> + * <li>The digits {@code 0} to {@code 3} additionally require the intersection to be of that + * topological dimension at most.</li> + * </ul> + * + * @param other the geometry to test against. + * @param matrix intersection pattern of 4 or 9 characters. + * @return {@code true} if the two geometries match the given pattern. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#relate(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry, java.lang.String) + * @see ISO 19107:2019 - 6.4.8.8, 6.4.9, 10.8.4, 10.8.5, 10.8.6 */ - @UML(identifier="relate", specification=ISO_19107) // section 6.4.8.8 - //@UML(identifier="3Drelate", specification=ISO_19107) // section 6.4.9 + @UML(identifier="relate", specification=ISO_19107) + //@UML(identifier="3Drelate", specification=ISO_19107) public default boolean relate(Geometry other, String matrix) throws OperationException { return new GeometryProcessor().relate(this, other, matrix); } /** + * Returns whether the two geometries meet without their interiors intersecting. + * + * <p>Constraints:</p> + * <ul> + * <li>The closures intersect but the interiors are disjoint.</li> + * <li>Equivalent to {@code relate(other, "FT*******")}, {@code "F**T*****"} + * or {@code "F***T****"}.</li> + * </ul> + * + * @param other the geometry to test against. + * @return {@code true} if the two geometries touch. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#touches(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.8.8, 6.4.9, 10.8.6.3.5 */ - @UML(identifier="touches", specification=ISO_19107) // section 6.4.8.8 - //@UML(identifier="3Dtouches", specification=ISO_19107) // section 6.4.9 + @UML(identifier="touches", specification=ISO_19107) + //@UML(identifier="3Dtouches", specification=ISO_19107) public default boolean touches(Geometry other) throws OperationException { return new GeometryProcessor().touches(this, other); } /** + * Returns whether this geometry is a subset of the given geometry, that is whether no position + * of this geometry lies in the exterior of the given geometry. + * + * <p>Constraints:</p> + * <ul> + * <li>Equivalent to {@code relate(other, "TNFNNFNNN")}.</li> + * <li>{@code a.within(b)} is equivalent to {@code b.contains(a)}.</li> + * </ul> + * + * @param other the geometry to test for inclusion in. + * @return {@code true} if this geometry is within the given geometry. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#within(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry) + * @see ISO 19107:2019 - 6.4.8.8, 6.4.9, 10.8.6.3.7 */ - @UML(identifier="within", specification=ISO_19107) // section 6.4.8.8 - //@UML(identifier="3Dwithin", specification=ISO_19107) // section 6.4.9 + @UML(identifier="within", specification=ISO_19107) + //@UML(identifier="3Dwithin", specification=ISO_19107) public default boolean within(Geometry other) throws OperationException { return new GeometryProcessor().within(this, other); } /** + * Returns whether the given geometry lies closer to this geometry than the given distance. + * + * <p>Constraints:</p> + * <ul> + * <li>Equivalent to {@code buffer(distance).intersects(other)}.</li> + * </ul> + * + * @param other the geometry to test against. + * @param distance maximal distance between the two geometries. + * @return {@code true} if the two geometries are within the given distance. + * @throws OperationException if the test cannot be performed. + * * @see GeometryProcessor#withinDistance(org.apache.sis.geometries.Geometry, org.apache.sis.geometries.Geometry, javax.measure.quantity.Length) + * @see ISO 19107:2019 - 6.4.8.8, 6.4.9, 10.8.7 */ - @UML(identifier="withinDistance", specification=ISO_19107) // section 6.4.8.8 - //@UML(identifier="3DwithinDistance", specification=ISO_19107) // section 6.4.9 + @UML(identifier="withinDistance", specification=ISO_19107) + //@UML(identifier="3DwithinDistance", specification=ISO_19107) public default boolean withinDistance(Geometry other, Length distance) throws OperationException { return new GeometryProcessor().withinDistance(this, other, distance); } diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java index 74f51dcf87..3fd2fa991d 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java @@ -43,6 +43,8 @@ import org.apache.sis.maths.DataType; import org.apache.sis.maths.NDArrays; import org.apache.sis.maths.SampleSystem; import org.apache.sis.maths.Tuple; +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.DirectPosition; @@ -115,23 +117,25 @@ public final class GeometryProcessor { * spatial reference system of this geometric object. * Because the geometries are closed, it is possible to find a point on each geometric object involved, such that * the distance between these 2 points is the returned distance between their geometric objects. + * + * <p>TODO / Limitation: the returned quantity is labelled in metres, but its magnitude is the plain + * Pythagorean distance computed in the units of the coordinate system axes. On a geographic + * coordinate reference system that magnitude is therefore an amount of degrees reported as + * metres. Computing a true geodesic distance on the reference surface, as required by + * ISO 19107 REQ. 11, remains to be done.</p> */ - public double distance(Geometry geom1, Geometry geom2) throws OperationException { + @UML(identifier="distance", specification=ISO_19107) // section 6.4.4.26 and 6.4.8.2 + //@UML(identifier="3Ddistance", specification=ISO_19107) // section 6.4.9 + public Length distance(Geometry geom1, Geometry geom2) throws OperationException { if (geom1 instanceof Point pt1) { if (geom2 instanceof Point pt2) { - return Distance.distance(pt1, pt2); + return Quantities.create(Distance.distance(pt1, pt2), Units.METRE); } } throw new UnsupportedOperationException(); } - @UML(identifier="distance", specification=ISO_19107) // section 6.4.4.26 and 6.4.8.2 - //@UML(identifier="3Ddistance", specification=ISO_19107) // section 6.4.9 - public Length distance2(Geometry geom1, Geometry geom2) throws OperationException { - throw new UnsupportedOperationException(); - } - /** * Returns a geometric object that represents the Point set intersection of this geometric object with anotherGeometry. */ diff --git a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java index 67cbe5c327..7ace808911 100644 --- a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java +++ b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/package-info.java @@ -63,7 +63,7 @@ * <h3>TODO : ISO 19107 Complex (Section 6.4.34)</h3> * No interface or implementation yet. * This is special sub class of Collection with advance analysis capabilities. - * Add methode getMaximalComplex on Geometry, see section 6.4.4.17 + * Geometry.getMaximalComplex returns a Geometry until this interface exists. * * <h3>TODO : ISO 19107 Topology (Section 10)</h3> * No interface or implementation yet. diff --git a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java index a077bcff77..a51836f55d 100644 --- a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java +++ b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/DistanceTest.java @@ -16,9 +16,11 @@ */ package org.apache.sis.geometries.operation; +import javax.measure.quantity.Length; import org.apache.sis.geometries.GeometryFactory; import org.apache.sis.geometries.Point; import org.apache.sis.maths.SampleSystem; +import org.apache.sis.measure.Units; import org.apache.sis.referencing.CommonCRS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; @@ -42,7 +44,7 @@ public class DistanceTest { final Point point1 = GeometryFactory.createPoint(CommonCRS.WGS84.geographic()); final Point point2 = GeometryFactory.createPoint(CommonCRS.WGS84.normalizedGeographic()); try { - double distance = new GeometryProcessor().distance(point1, point2); + new GeometryProcessor().distance(point1, point2); fail("evaluation should fail"); } catch (OperationException ex) { //ok @@ -52,13 +54,17 @@ public class DistanceTest { { //at same position final Point point1 = GeometryFactory.createPoint(CRS2D, 10.0, 5.0); final Point point2 = GeometryFactory.createPoint(CRS2D, 10.0, 5.0); - assertEquals(0.0, new GeometryProcessor().distance(point1, point2), 0.0); + final Length distance = new GeometryProcessor().distance(point1, point2); + assertEquals(Units.METRE, distance.getUnit()); + assertEquals(0.0, distance.getValue().doubleValue(), 0.0); } { //at 1.0 of distance final Point point1 = GeometryFactory.createPoint(CRS2D, 10, 5); final Point point2 = GeometryFactory.createPoint(CRS2D, 10, 6); - assertEquals(1.0, new GeometryProcessor().distance(point1, point2), 0.0); + final Length distance = new GeometryProcessor().distance(point1, point2); + assertEquals(Units.METRE, distance.getUnit()); + assertEquals(1.0, distance.getValue().doubleValue(), 0.0); } }
