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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 978746cc23 feat(Geometry): remove oriented geometry, store DataPoints 
on Ray,Plane,HyperPlane,Capsule and Cylinder
978746cc23 is described below

commit 978746cc23fe3db524c761dad571314eb96800ee
Author: jsorel <[email protected]>
AuthorDate: Wed Oct 7 15:29:09 2026 +0200

    feat(Geometry): remove oriented geometry, store DataPoints on 
Ray,Plane,HyperPlane,Capsule and Cylinder
---
 .../main/org/apache/sis/geometries/DataPoints.java |  75 +++++++++
 .../main/org/apache/sis/geometries/Geometry.java   |   1 -
 .../main/org/apache/sis/geometries/HyperPlane.java | 133 ++++++++++++++--
 .../apache/sis/geometries/OrientedGeometry.java    |  60 -------
 .../main/org/apache/sis/geometries/Plane.java      | 170 ++++++++++++++++----
 .../main/org/apache/sis/geometries/Ray.java        |  56 +++++--
 .../internal/shared/AbstractOrientedGeometry.java  |  54 -------
 .../internal/shared/ArrayDataPoints.java           |  10 +-
 .../internal/shared/DefaultDataPoints.java         |   9 ++
 .../org/apache/sis/geometries/solid/Capsule.java   | 175 +++++++++++++++++----
 .../org/apache/sis/geometries/solid/Cylinder.java  | 168 +++++++++++++++++---
 .../sis/geometries/OrientedGeometryTest.java       | 154 ------------------
 12 files changed, 682 insertions(+), 383 deletions(-)

diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/DataPoints.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/DataPoints.java
index 1754f775da..7c67d259a7 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/DataPoints.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/DataPoints.java
@@ -16,6 +16,9 @@
  */
 package org.apache.sis.geometries;
 
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.maths.Array;
@@ -163,4 +166,76 @@ public interface DataPoints {
         return env;
     }
 
+    /**
+     * Returns a hash code value for the given sequence, computed from the 
attributes it declares
+     * and from the values it holds for them. Implementations of this 
interface shall base their
+     * {@code hashCode()} on this method, so that two sequences holding the 
same data have the
+     * same hash code whatever the way they store it.
+     *
+     * @param  points  the sequence to hash, not null.
+     * @return a hash code value for the given sequence.
+     */
+    static int hashCode(final DataPoints points) {
+        final DataPointsType type = points.getType();
+        final int size = points.size();
+        int hash = DataPointsType.hashCode(type) + 31 * size;
+        for (final String name : type.getAttributeNames()) {
+            int attribute = name.hashCode();
+            for (int i = 0; i < size; i++) {
+                attribute = 31 * attribute + 
Objects.hashCode(points.getAttribute(i, name));
+            }
+            // Summed so that the result does not depend on the order in which 
the names are returned.
+            hash += attribute;
+        }
+        return hash;
+    }
+
+    /**
+     * Returns whether the given object is a sequence declaring the same 
attributes as the given one
+     * and holding the same values for them. Implementations of this interface 
shall base their
+     * {@code equals(Object)} on this method, so that two sequences holding 
the same data are equal
+     * whatever the way they store it: a sequence backed by arrays is equal to 
a sequence backed by
+     * a list of points when both describe the same positions.
+     *
+     * <p>The attributes are compared one by one rather than by delegating to
+     * {@link DataPointsType#equals(DataPointsType, Object)}, because a 
sequence may be its own
+     * description, and that method reports two descriptions as different as 
soon as one of them
+     * also carries the positions.</p>
+     *
+     * @param  points  the sequence to compare, not null.
+     * @param  obj     the object to compare to the given sequence, or {@code 
null}.
+     * @return whether the two hold the same attributes with the same values.
+     */
+    static boolean equals(final DataPoints points, final Object obj) {
+        if (points == obj) {
+            return true;
+        }
+        if (!(obj instanceof DataPoints other)) {
+            return false;
+        }
+        final int size = points.size();
+        if (size != other.size()) {
+            return false;
+        }
+        final DataPointsType type = points.getType();
+        final DataPointsType otherType = other.getType();
+        final List<String> names = type.getAttributeNames();
+        final List<String> others = otherType.getAttributeNames();
+        if (names.size() != others.size() || !new 
HashSet<>(names).containsAll(others)) {
+            return false;
+        }
+        for (final String name : names) {
+            if (!Objects.equals(type.getAttributeSystem(name), 
otherType.getAttributeSystem(name)) ||
+                !Objects.equals(type.getAttributeType  (name), 
otherType.getAttributeType  (name)))
+            {
+                return false;
+            }
+            for (int i = 0; i < size; i++) {
+                if (!Objects.equals(points.getAttribute(i, name), 
other.getAttribute(i, name))) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
 }
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 5487278e83..1c440d52d2 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
@@ -84,7 +84,6 @@ import org.apache.sis.measure.Units;
 public sealed interface Geometry
         permits Primitive,
                 GeometryCollection,
-                OrientedGeometry,
                 Empty,
                 Prism,
                 MeshPrimitive,
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
index 48529407a7..946d5006ef 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/HyperPlane.java
@@ -16,23 +16,60 @@
  */
 package org.apache.sis.geometries;
 
+import java.util.Objects;
 import static org.opengis.annotation.Specification.ISO_12113;
 import org.opengis.annotation.UML;
-import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.geometries.internal.shared.AbstractOrientedGeometry;
+import org.apache.sis.geometries.internal.shared.AbstractGeometry;
+import org.apache.sis.maths.NDArrays;
+import org.apache.sis.maths.Tuple;
+import org.apache.sis.maths.Vector;
 
 
 /**
- * A hyperplane centered at the origin in local space, with normal along the 
+Y axis in local space.
- * The hyper plane divised the geometric space in two.
+ * A hyperplane divides the geometric space in two.
+ * It is build from a position and a normal.
  *
  * @author Johann Sorel (Geomatys)
  */
 @UML(identifier="Plane", specification=ISO_12113)
-public final class HyperPlane extends AbstractOrientedGeometry {
+public final class HyperPlane extends AbstractGeometry{
 
-    public HyperPlane() {
+    /**
+     * Must contain a single point.
+     */
+    private final DataPoints points;
+
+    private Vector<?> normal;
+
+    /**
+     * Creates a hyperplane passing by the given position.
+     * The reference system of the hyperplane is the one of that position.
+     *
+     * @param  position  a position the hyperplane passes by, not null.
+     * @param  normal    the direction the hyperplane is perpendicular to, not 
null.
+     */
+    public HyperPlane(Tuple<?> position, Vector<?> normal) {
+        points = 
GeometryFactory.createSequence(NDArrays.of(position.getSampleSystem(), 
position.getDataType(), 1));
+        points.setPosition(0, position);
+        this.normal = normal;
+    }
+
+    /**
+     * Creates a hyperplane passing by the single position of the given 
sequence.
+     * The sequence is taken as-is, so the caller may give the hyperplane the 
attributes
+     * carried by that sequence.
+     *
+     * @param  points  a position the hyperplane passes by, as a sequence of 
exactly one position.
+     * @param  normal  the direction the hyperplane is perpendicular to, not 
null.
+     * @throws IllegalArgumentException if the given sequence does not hold 
exactly one position.
+     */
+    public HyperPlane(DataPoints points, Vector<?> normal) {
+        if (points.size() != 1) {
+            throw new IllegalArgumentException("HyperPlane sequence must 
contain one point");
+        }
+        this.points = points;
+        this.normal = normal;
     }
 
     @Override
@@ -40,6 +77,63 @@ public final class HyperPlane extends 
AbstractOrientedGeometry {
         return GeometryType.HYPERPLANE;
     }
 
+    public DataPoints getDataPoints() {
+        return points;
+    }
+
+    public Tuple<?> getPosition() {
+        return points.getPosition(0);
+    }
+
+    public void setPosition(Tuple<?> position) {
+        points.setPosition(0, position);
+    }
+
+    public Vector<?> getNormal() {
+        return normal;
+    }
+
+    public void setNormal(Vector<?> normal) {
+        this.normal = normal;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>A hyperplane extends to infinity along every direction it contains. 
It is therefore
+     * bounded on one axis only when it is perpendicular to that axis, which 
happens when the
+     * normal is aligned with it. In every other case, including a normal 
which is null in all
+     * its dimensions, the hyperplane spans the whole space on every axis.</p>
+     */
+    @Override
+    public BBox getEnvelope() {
+        final Tuple<?> position = getPosition();
+        final int dim = normal.getDimension();
+        final BBox bbox = new BBox(dim);
+        /*
+         * Search the axis the normal is aligned with. There is one only if 
every other
+         * dimension of the normal is null, in which case the hyperplane is 
flat on it.
+         */
+        int flat = -1;
+        for (int i=0;i<dim;i++){
+            if (normal.get(i) != 0){
+                if (flat >= 0){
+                    flat = -1;
+                    break;
+                }
+                flat = i;
+            }
+        }
+        for (int i=0;i<dim;i++){
+            if (i == flat){
+                bbox.setRange(i, position.get(i), position.get(i));
+            } else {
+                bbox.setRange(i, Double.NEGATIVE_INFINITY, 
Double.POSITIVE_INFINITY);
+            }
+        }
+        return bbox;
+    }
+
     @Override
     public boolean isEmpty() {
         return false;
@@ -47,22 +141,39 @@ public final class HyperPlane extends 
AbstractOrientedGeometry {
 
     @Override
     public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getCoordinateReferenceSystem();
     }
 
     @Override
     public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) 
throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Not supported yet.");
+        points.setCoordinateReferenceSystem(crs);
     }
 
     @Override
     public DataPointsType getDataPointsType() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getType();
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final HyperPlane other = (HyperPlane) obj;
+        if (!Objects.equals(this.points, other.points)) {
+            return false;
+        }
+        return this.normal == other.normal || (this.normal != null && 
this.normal.equals(other.normal));
+    }
 
     @Override
-    public Envelope getUnorientedEnvelope() {
-        throw new UnsupportedOperationException("Not supported yet.");
+    public int hashCode() {
+        int hash = 3;
+        hash = 89 * hash + Objects.hashCode(this.points);
+        hash = 89 * hash + Objects.hashCode(this.normal);
+        return hash;
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/OrientedGeometry.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/OrientedGeometry.java
deleted file mode 100644
index 9621f5d45a..0000000000
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/OrientedGeometry.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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;
-
-import org.opengis.geometry.Envelope;
-import org.apache.sis.geometries.internal.shared.AbstractOrientedGeometry;
-import org.apache.sis.maths.Similarity;
-
-
-/**
- * An oriented geometry is a geometry with specific properties
- * and additional rotation,translation properties.
- * <p>
- * Oriented geometries are often the base class of named geometries which 
contain curves,
- * like sphere or cylinders, but alos any non basic shapes which can be 
defined by self-defined properties
- * like height/width/radius and a separate point and orientation.
- * <p>
- * TODO : oriented geometries includes :
- * - infinite plane
- * - finite plane, also called Quad
- * - cylinder with varying top/bottom radius
- * - cone whih is a 0 radius cylinder
- * - capsule  (cylinder with hemispherical ends), with varying top/bottom 
radius
- * - sphere
- * - ellipsoid
- *
- * @author Johann Sorel
- */
-public sealed interface OrientedGeometry extends Geometry
-        permits AbstractOrientedGeometry
-{
-
-    /**
-     * Get geometry transform.
-     * @return Similarity, never null
-     */
-    Similarity<?> getTransform();
-
-    /**
-     * Get the geometry envelope without the orientation rotation and 
translation
-     * applied.
-     * @return Envelope
-     */
-    Envelope getUnorientedEnvelope();
-
-}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
index a8c1a44de9..b5aa4c7aa2 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Plane.java
@@ -16,33 +16,72 @@
  */
 package org.apache.sis.geometries;
 
+import java.util.Objects;
 import static org.opengis.annotation.Specification.ISO_12113;
 import org.opengis.annotation.UML;
-import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.geometries.internal.shared.AbstractOrientedGeometry;
+import org.apache.sis.geometries.internal.shared.AbstractGeometry;
+import org.apache.sis.maths.NDArrays;
+import org.apache.sis.maths.Tuple;
+import org.apache.sis.maths.Vector;
 
 
 /**
- * A plane centered at the origin in local space, with normal along the +Y 
axis in local space,
- * optionally with finite extents and may be double or single-sided.
+ * A plane centered on a position, perpendicular to a normal,
+ * optionally with finite extents.
+ * <p>
+ * A plane has no side: it is a sheet, and both of its faces belong to it. A 
surface which
+ * divides the space in two, and which therefore has a side, is a {@link 
HyperPlane}.
  * <p>
  * Synonym : Quad , for a plane with finite extents
  * <p>
- * Synonym : Sheet , for a double-sided plane
+ * Synonym : Sheet
  *
  *
  * @author Johann Sorel (Geomatys)
  * @spec ISO_12113 KHR_implicit_shapes extension Plane
  */
 @UML(identifier="Plane", specification=ISO_12113)
-public final class Plane extends AbstractOrientedGeometry {
+public final class Plane extends AbstractGeometry{
+
+    /**
+     * Must contain a single point.
+     */
+    private final DataPoints points;
+
+    private Vector<?> normal;
 
     private double sizeX = Double.NaN;
     private double sizeZ = Double.NaN;
-    private boolean doubleSided = false;
 
-    public Plane() {
+    /**
+     * Creates a plane centered on the given position.
+     * The reference system of the plane is the one of that position.
+     *
+     * @param  position  the position the plane is centered on, not null.
+     * @param  normal    the direction the plane is perpendicular to, not null.
+     */
+    public Plane(Tuple<?> position, Vector<?> normal) {
+        points = 
GeometryFactory.createSequence(NDArrays.of(position.getSampleSystem(), 
position.getDataType(), 1));
+        points.setPosition(0, position);
+        this.normal = normal;
+    }
+
+    /**
+     * Creates a plane centered on the single position of the given sequence.
+     * The sequence is taken as-is, so the caller may give the plane the 
attributes
+     * carried by that sequence.
+     *
+     * @param  points  the position the plane is centered on, as a sequence of 
exactly one position.
+     * @param  normal  the direction the plane is perpendicular to, not null.
+     * @throws IllegalArgumentException if the given sequence does not hold 
exactly one position.
+     */
+    public Plane(DataPoints points, Vector<?> normal) {
+        if (points.size() != 1) {
+            throw new IllegalArgumentException("Plane sequence must contain 
one point");
+        }
+        this.points = points;
+        this.normal = normal;
     }
 
     @Override
@@ -50,6 +89,26 @@ public final class Plane extends AbstractOrientedGeometry {
         return GeometryType.PLANE;
     }
 
+    public DataPoints getDataPoints() {
+        return points;
+    }
+
+    public Tuple<?> getPosition() {
+        return points.getPosition(0);
+    }
+
+    public void setPosition(Tuple<?> position) {
+        points.setPosition(0, position);
+    }
+
+    public Vector<?> getNormal() {
+        return normal;
+    }
+
+    public void setNormal(Vector<?> normal) {
+        this.normal = normal;
+    }
+
     /**
      * @return the plane X size
      */
@@ -78,20 +137,6 @@ public final class Plane extends AbstractOrientedGeometry {
         this.sizeZ = size;
     }
 
-    /**
-     * @return true if double sided
-     */
-    public boolean isDoubleSided() {
-        return doubleSided;
-    }
-
-    /**
-     * @param doubleSided true if double sided
-     */
-    public void setDoubleSided(boolean doubleSided) {
-        this.doubleSided = doubleSided;
-    }
-
     @Override
     public boolean isEmpty() {
         return false;
@@ -107,32 +152,95 @@ public final class Plane extends AbstractOrientedGeometry 
{
     }
 
     /**
-     * A plane becomes a sheet when it is double sided.
+     * {@inheritDoc}
      *
-     * @return true if plane is a sheet
+     * <p>A plane is perpendicular to its normal, so it is bounded on an axis 
only when the
+     * normal is aligned with that axis. On the axes it spans, a plane which 
is not a
+     * {@linkplain #isQuad() quad} extends to infinity.</p>
+     *
+     * <p>TODO / Limitation: the sizes of a quad are stated along two axes 
named <var>X</var> and
+     * <var>Z</var>, which this class no longer has the local frame to 
interpret. They are read
+     * here as the two axes the plane spans, in their order in the coordinate 
system, which is
+     * the expected reading of a normal aligned with the second axis of a 
three-dimensional
+     * system. A quad whose normal is not aligned with an axis, or which lies 
in a space of
+     * another number of dimensions, is reported as unbounded on the axes it 
spans: a bounding
+     * box is allowed to be larger than the geometry it contains, never 
smaller.</p>
      */
-    public boolean isSheet() {
-        return doubleSided;
+    @Override
+    public BBox getEnvelope() {
+        final Tuple<?> position = getPosition();
+        final int dim = normal.getDimension();
+        final BBox bbox = new BBox(dim);
+        /*
+         * Search the axis the normal is aligned with. There is one only if 
every other
+         * dimension of the normal is null, in which case the plane is flat on 
it.
+         */
+        int flat = -1;
+        for (int i=0;i<dim;i++){
+            if (normal.get(i) != 0){
+                if (flat >= 0){
+                    flat = -1;
+                    break;
+                }
+                flat = i;
+            }
+        }
+        final boolean bounded = isQuad() && flat >= 0 && dim == 3;
+        int spanned = 0;
+        for (int i=0;i<dim;i++){
+            if (i == flat){
+                bbox.setRange(i, position.get(i), position.get(i));
+            } else if (bounded){
+                final double half = ((spanned++ == 0) ? sizeX : sizeZ) / 2;
+                bbox.setRange(i, position.get(i) - half, position.get(i) + 
half);
+            } else {
+                bbox.setRange(i, Double.NEGATIVE_INFINITY, 
Double.POSITIVE_INFINITY);
+            }
+        }
+        return bbox;
     }
 
     @Override
     public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getCoordinateReferenceSystem();
     }
 
     @Override
     public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) 
throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Not supported yet.");
+        points.setCoordinateReferenceSystem(crs);
     }
 
     @Override
     public DataPointsType getDataPointsType() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getType();
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Plane other = (Plane) obj;
+        if (!Objects.equals(this.points, other.points)) {
+            return false;
+        }
+        if (!Objects.equals(this.normal, other.normal)) {
+            return false;
+        }
+        return Double.doubleToLongBits(this.sizeX) == 
Double.doubleToLongBits(other.sizeX)
+            && Double.doubleToLongBits(this.sizeZ) == 
Double.doubleToLongBits(other.sizeZ);
+    }
 
     @Override
-    public Envelope getUnorientedEnvelope() {
-        throw new UnsupportedOperationException("Not supported yet.");
+    public int hashCode() {
+        int hash = 3;
+        hash = 89 * hash + Objects.hashCode(this.points);
+        hash = 89 * hash + Objects.hashCode(this.normal);
+        hash = 89 * hash + Double.hashCode(this.sizeX);
+        hash = 89 * hash + Double.hashCode(this.sizeZ);
+        return hash;
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java
index 9c885b0234..2254ebb854 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Ray.java
@@ -19,9 +19,9 @@ package org.apache.sis.geometries;
 import java.util.Objects;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.geometries.internal.shared.AbstractGeometry;
+import org.apache.sis.maths.NDArrays;
 import org.apache.sis.maths.Tuple;
 import org.apache.sis.maths.Vector;
-import org.apache.sis.maths.Vectors;
 
 
 /**
@@ -32,15 +32,40 @@ import org.apache.sis.maths.Vectors;
  */
 public final class Ray extends AbstractGeometry{
 
-    private Tuple<?> position;
+    /**
+     * Must contain a single point.
+     */
+    private final DataPoints points;
+
     private Vector<?> direction;
 
-    public Ray(int dimension) {
-        this(Vectors.createDouble(dimension),Vectors.createDouble(dimension));
+    /**
+     * Creates a ray starting from the given position.
+     * The reference system of the ray is the one of that position.
+     *
+     * @param  position   the position the ray starts from, not null.
+     * @param  direction  the direction the ray extends toward, not null.
+     */
+    public Ray(Tuple<?> position, Vector<?> direction) {
+        points = 
GeometryFactory.createSequence(NDArrays.of(position.getSampleSystem(), 
position.getDataType(), 1));
+        points.setPosition(0, position);
+        this.direction = direction;
     }
 
-    public Ray(Tuple<?> position, Vector<?> direction) {
-        this.position = position;
+    /**
+     * Creates a ray starting from the single position of the given sequence.
+     * The sequence is taken as-is, so the caller may give the ray the 
attributes
+     * carried by that sequence.
+     *
+     * @param  points     the position the ray starts from, as a sequence of 
exactly one position.
+     * @param  direction  the direction the ray extends toward, not null.
+     * @throws IllegalArgumentException if the given sequence does not hold 
exactly one position.
+     */
+    public Ray(DataPoints points, Vector<?> direction) {
+        if (points.size() != 1) {
+            throw new IllegalArgumentException("Ray sequence must contain one 
point");
+        }
+        this.points = points;
         this.direction = direction;
     }
 
@@ -49,12 +74,16 @@ public final class Ray extends AbstractGeometry{
         return GeometryType.RAY;
     }
 
+    public DataPoints getDataPoints() {
+        return points;
+    }
+
     public Tuple<?> getPosition() {
-        return position;
+        return points.getPosition(0);
     }
 
     public void setPosition(Tuple<?> position) {
-        this.position = position;
+        points.setPosition(0, position);
     }
 
     public Vector<?> getDirection() {
@@ -67,6 +96,7 @@ public final class Ray extends AbstractGeometry{
 
     @Override
     public BBox getEnvelope() {
+        final Tuple<?> position = getPosition();
         final int dim = direction.getDimension();
         final BBox bbox = new BBox(dim);
         for (int i=0;i<dim;i++){
@@ -89,17 +119,17 @@ public final class Ray extends AbstractGeometry{
 
     @Override
     public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getCoordinateReferenceSystem();
     }
 
     @Override
     public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) 
throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Not supported yet.");
+        points.setCoordinateReferenceSystem(crs);
     }
 
     @Override
     public DataPointsType getDataPointsType() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getType();
     }
 
     @Override
@@ -111,7 +141,7 @@ public final class Ray extends AbstractGeometry{
             return false;
         }
         final Ray other = (Ray) obj;
-        if (this.position != other.position && (this.position == null || 
!this.position.equals(other.position))) {
+        if (!Objects.equals(this.points, other.points)) {
             return false;
         }
         return this.direction == other.direction || (this.direction != null && 
this.direction.equals(other.direction));
@@ -120,7 +150,7 @@ public final class Ray extends AbstractGeometry{
     @Override
     public int hashCode() {
         int hash = 3;
-        hash = 89 * hash + Objects.hashCode(this.position);
+        hash = 89 * hash + Objects.hashCode(this.points);
         hash = 89 * hash + Objects.hashCode(this.direction);
         return hash;
     }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/AbstractOrientedGeometry.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/AbstractOrientedGeometry.java
deleted file mode 100644
index 4c4bbd6e6c..0000000000
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/AbstractOrientedGeometry.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.geometry.Envelope;
-import org.apache.sis.geometries.OrientedGeometry;
-import org.apache.sis.maths.Similarity;
-import org.apache.sis.maths.Similarity3D;
-
-
-/**
- * Abstract oriented geometry.
- *
- * @author Johann Sorel (Geomatys)
- */
-public abstract non-sealed class AbstractOrientedGeometry extends 
AbstractGeometry implements OrientedGeometry {
-
-    protected final Similarity<?> transform;
-
-    public AbstractOrientedGeometry() {
-        this.transform = new Similarity3D();
-    }
-
-    @Override
-    public Similarity<?> getTransform() {
-        return transform;
-    }
-
-    @Override
-    public Envelope getEnvelope() {
-        Envelope unenv = getUnorientedEnvelope();
-        if (unenv == null) return null;
-
-        double[] lower = unenv.getLowerCorner().getCoordinates();
-        double[] upper = unenv.getUpperCorner().getCoordinates();
-
-        throw new UnsupportedOperationException("Not supported yet");
-    }
-
-}
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/ArrayDataPoints.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/ArrayDataPoints.java
index 2fe4a6edb5..ad40cb2247 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/ArrayDataPoints.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/ArrayDataPoints.java
@@ -164,18 +164,12 @@ public final class ArrayDataPoints implements DataPoints, 
DataPointsType {
 
     @Override
     public int hashCode() {
-        return 37 * attributes.hashCode();
+        return DataPoints.hashCode(this);
     }
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof ArrayDataPoints)) {
-            return false;
-        }
-        return attributes.equals(((ArrayDataPoints) obj).attributes);
+        return DataPoints.equals(this, obj);
     }
 
     /**
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultDataPoints.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultDataPoints.java
index 333df10c88..3f0d1a835c 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultDataPoints.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/internal/shared/DefaultDataPoints.java
@@ -91,4 +91,13 @@ public final class DefaultDataPoints implements DataPoints {
         points.get(index).setAttribute(name, value);
     }
 
+    @Override
+    public int hashCode() {
+        return DataPoints.hashCode(this);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return DataPoints.equals(this, obj);
+    }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java
index d63b9006fb..5ef9d757c9 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Capsule.java
@@ -16,31 +16,68 @@
  */
 package org.apache.sis.geometries.solid;
 
+import java.util.Objects;
 import static org.opengis.annotation.Specification.ISO_12113;
 import org.opengis.annotation.UML;
-import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.geometries.GeometryType;
+import org.apache.sis.geometries.BBox;
+import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.DataPointsType;
-import org.apache.sis.geometries.internal.shared.AbstractOrientedGeometry;
+import org.apache.sis.geometries.GeometryFactory;
+import org.apache.sis.geometries.GeometryType;
+import org.apache.sis.geometries.internal.shared.AbstractGeometry;
+import org.apache.sis.maths.DataType;
+import org.apache.sis.maths.NDArrays;
+import org.apache.sis.maths.Tuple;
+import org.apache.sis.maths.Vector;
+import org.apache.sis.maths.Vectors;
 
 
 /**
- * A capsule (cylinder with hemispherical ends) centered at the origin and 
defined by two "capping" spheres
- * with potentially different radii, aligned along the Y axis in local space.
+ * A capsule (cylinder with hemispherical ends) defined by two "capping" 
spheres centered on two
+ * positions, with potentially different radii.
  *
  *
  * @author Johann Sorel (Geomatys)
  * @spec ISO_12113 KHR_implicit_shapes extension Capsule
  */
 @UML(identifier="Capsule", specification=ISO_12113)
-public final class Capsule extends AbstractOrientedGeometry {
+public final class Capsule extends AbstractGeometry{
+
+    /**
+     * Must contain two points : the center of the bottom sphere, then the 
center of the top one.
+     */
+    private final DataPoints points;
 
-    private double height = 1.0;
     private double radiusTop = 1.0;
     private double radiusBottom = 1.0;
 
-    public Capsule() {
+    /**
+     * Creates a capsule whose capping spheres are centered on the two given 
positions.
+     * The reference system of the capsule is the one of those positions.
+     *
+     * @param  bottom  the center of the bottom sphere, not null.
+     * @param  top     the center of the top sphere, not null.
+     */
+    public Capsule(Tuple<?> bottom, Tuple<?> top) {
+        points = 
GeometryFactory.createSequence(NDArrays.of(bottom.getSampleSystem(), 
bottom.getDataType(), 2));
+        points.setPosition(0, bottom);
+        points.setPosition(1, top);
+    }
+
+    /**
+     * Creates a capsule whose capping spheres are centered on the two 
positions of the given
+     * sequence. The sequence is taken as-is, so the caller may give the 
capsule the attributes
+     * carried by that sequence.
+     *
+     * @param  points  the centers of the bottom and top spheres, in that 
order.
+     * @throws IllegalArgumentException if the given sequence does not hold 
exactly two positions.
+     */
+    public Capsule(DataPoints points) {
+        if (points.size() != 2) {
+            throw new IllegalArgumentException("Capsule sequence must contain 
two points");
+        }
+        this.points = points;
     }
 
     @Override
@@ -48,81 +85,155 @@ public final class Capsule extends 
AbstractOrientedGeometry {
         return GeometryType.CAPSULE;
     }
 
+    public DataPoints getDataPoints() {
+        return points;
+    }
+
     /**
-     * Height is along the Y axis, right handed as defined in GLTF.
-     * @return the cylinder height
+     * @return the center of the bottom sphere
      */
-    public double getHeight() {
-        return height;
+    public Tuple<?> getBottom() {
+        return points.getPosition(0);
     }
 
     /**
-     * @param height new cylinder height
+     * @param position new center of the bottom sphere
      */
-    public void setHeight(double height) {
-        this.height = height;
+    public void setBottom(Tuple<?> position) {
+        points.setPosition(0, position);
     }
 
     /**
-     * @return cylinder top circle radius
+     * @return the center of the top sphere
+     */
+    public Tuple<?> getTop() {
+        return points.getPosition(1);
+    }
+
+    /**
+     * @param position new center of the top sphere
+     */
+    public void setTop(Tuple<?> position) {
+        points.setPosition(1, position);
+    }
+
+    /**
+     * Returns the vector going from the center of the bottom sphere to the 
center of the top one.
+     * It is built on doubles whatever the type of the positions, the 
direction and the length of
+     * an axis being real values even when the positions they are derived from 
are integers.
+     */
+    private Vector<?> getAxis() {
+        final Tuple<?> bottom = getBottom();
+        final Vector<?> axis = Vectors.create(bottom.getSampleSystem(), 
DataType.DOUBLE);
+        axis.set(getTop());
+        axis.subtract(bottom);
+        return axis;
+    }
+
+    /**
+     * The height is the length of the axis going from the center of the 
bottom sphere to the
+     * center of the top one, so it is not set but derived from the two 
positions this capsule
+     * is built on. It does not include the two hemispherical ends.
+     *
+     * @return the capsule height
+     */
+    public double getHeight() {
+        return getAxis().length();
+    }
+
+    /**
+     * @return capsule top sphere radius
      */
     public double getRadiusTop() {
         return radiusTop;
     }
 
     /**
-     * @param radius new cylinder top radius
+     * @param radius new capsule top radius
      */
     public void setRadiusTop(double radius) {
         this.radiusTop = radius;
     }
 
     /**
-     * @return cylinder bottom circle radius
+     * @return capsule bottom sphere radius
      */
     public double getRadiusBottom() {
         return radiusBottom;
     }
 
     /**
-     * @param radius new cylinder bottom radius
+     * @param radius new capsule bottom radius
      */
     public void setRadiusBottom(double radius) {
         this.radiusBottom = radius;
     }
 
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+
     /**
-     * A cylinder becomes a cone when the top or bottom radius is set to 0.0.
+     * {@inheritDoc}
      *
-     * @return true if cylinder is a cone, top or bottom radius is 0.0.
+     * <p>A capsule is the convex hull of its two capping spheres, so it 
reaches the whole radius
+     * of each of them on every axis. Contrarily to a {@linkplain Cylinder 
cylinder}, whose flat
+     * ends spread less than their radius on the axis they face, a capsule is 
therefore bounded
+     * by the union of the two boxes bounding its spheres.</p>
      */
-    public boolean isCone() {
-        return radiusBottom == 0.0 || radiusTop == 0.0;
-    }
-
     @Override
-    public boolean isEmpty() {
-        return false;
+    public BBox getEnvelope() {
+        final Tuple<?> bottom = getBottom();
+        final Tuple<?> top = getTop();
+        final int dim = points.getDimension();
+        final BBox bbox = new BBox(dim);
+        for (int i=0;i<dim;i++){
+            final double b = bottom.get(i);
+            final double t = top.get(i);
+            bbox.setRange(i, Math.min(b - radiusBottom, t - radiusTop),
+                             Math.max(b + radiusBottom, t + radiusTop));
+        }
+        return bbox;
     }
 
     @Override
     public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getCoordinateReferenceSystem();
     }
 
     @Override
     public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) 
throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Not supported yet.");
+        points.setCoordinateReferenceSystem(crs);
     }
 
     @Override
     public DataPointsType getDataPointsType() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getType();
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Capsule other = (Capsule) obj;
+        if (!Objects.equals(this.points, other.points)) {
+            return false;
+        }
+        return Double.doubleToLongBits(this.radiusTop) == 
Double.doubleToLongBits(other.radiusTop)
+            && Double.doubleToLongBits(this.radiusBottom) == 
Double.doubleToLongBits(other.radiusBottom);
+    }
 
     @Override
-    public Envelope getUnorientedEnvelope() {
-        throw new UnsupportedOperationException("Not supported yet.");
+    public int hashCode() {
+        int hash = 3;
+        hash = 89 * hash + Objects.hashCode(this.points);
+        hash = 89 * hash + Double.hashCode(this.radiusTop);
+        hash = 89 * hash + Double.hashCode(this.radiusBottom);
+        return hash;
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java
 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java
index 9e03062061..9d06ce8736 100644
--- 
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java
+++ 
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/solid/Cylinder.java
@@ -16,17 +16,25 @@
  */
 package org.apache.sis.geometries.solid;
 
+import java.util.Objects;
 import static org.opengis.annotation.Specification.ISO_12113;
 import org.opengis.annotation.UML;
-import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.geometries.GeometryType;
+import org.apache.sis.geometries.BBox;
+import org.apache.sis.geometries.DataPoints;
 import org.apache.sis.geometries.DataPointsType;
-import org.apache.sis.geometries.internal.shared.AbstractOrientedGeometry;
+import org.apache.sis.geometries.GeometryFactory;
+import org.apache.sis.geometries.GeometryType;
+import org.apache.sis.geometries.internal.shared.AbstractGeometry;
+import org.apache.sis.maths.DataType;
+import org.apache.sis.maths.NDArrays;
+import org.apache.sis.maths.Tuple;
+import org.apache.sis.maths.Vector;
+import org.apache.sis.maths.Vectors;
 
 
 /**
- * A cylinder centered at the origin and aligned along the Y axis in local 
space, with potentially different radii at each end.
+ * A cylinder along the axis joining two positions, with potentially different 
radii at each end.
  * <p>
  * A cone is a special case of cylinder when one of the radii is zero.
  * <p>
@@ -40,13 +48,42 @@ import 
org.apache.sis.geometries.internal.shared.AbstractOrientedGeometry;
  * @spec ISO_12113 KHR_implicit_shapes extension Cylinder
  */
 @UML(identifier="Cylinder", specification=ISO_12113)
-public final class Cylinder extends AbstractOrientedGeometry {
+public final class Cylinder extends AbstractGeometry{
+
+    /**
+     * Must contain two points : the center of the bottom circle, then the 
center of the top one.
+     */
+    private final DataPoints points;
 
-    private double height = 1.0;
     private double radiusTop = 1.0;
     private double radiusBottom = 1.0;
 
-    public Cylinder() {
+    /**
+     * Creates a cylinder along the axis joining the two given positions.
+     * The reference system of the cylinder is the one of those positions.
+     *
+     * @param  bottom  the center of the bottom circle, not null.
+     * @param  top     the center of the top circle, not null.
+     */
+    public Cylinder(Tuple<?> bottom, Tuple<?> top) {
+        points = 
GeometryFactory.createSequence(NDArrays.of(bottom.getSampleSystem(), 
bottom.getDataType(), 2));
+        points.setPosition(0, bottom);
+        points.setPosition(1, top);
+    }
+
+    /**
+     * Creates a cylinder along the axis joining the two positions of the 
given sequence.
+     * The sequence is taken as-is, so the caller may give the cylinder the 
attributes
+     * carried by that sequence.
+     *
+     * @param  points  the centers of the bottom and top circles, in that 
order.
+     * @throws IllegalArgumentException if the given sequence does not hold 
exactly two positions.
+     */
+    public Cylinder(DataPoints points) {
+        if (points.size() != 2) {
+            throw new IllegalArgumentException("Cylinder sequence must contain 
two points");
+        }
+        this.points = points;
     }
 
     @Override
@@ -54,19 +91,60 @@ public final class Cylinder extends 
AbstractOrientedGeometry {
         return GeometryType.CYLINDER;
     }
 
+    public DataPoints getDataPoints() {
+        return points;
+    }
+
     /**
-     * Height is along the Y axis, right handed as defined in GLTF.
-     * @return the cylinder height
+     * @return the center of the bottom circle
      */
-    public double getHeight() {
-        return height;
+    public Tuple<?> getBottom() {
+        return points.getPosition(0);
+    }
+
+    /**
+     * @param position new center of the bottom circle
+     */
+    public void setBottom(Tuple<?> position) {
+        points.setPosition(0, position);
+    }
+
+    /**
+     * @return the center of the top circle
+     */
+    public Tuple<?> getTop() {
+        return points.getPosition(1);
+    }
+
+    /**
+     * @param position new center of the top circle
+     */
+    public void setTop(Tuple<?> position) {
+        points.setPosition(1, position);
+    }
+
+    /**
+     * Returns the vector going from the center of the bottom circle to the 
center of the top one.
+     * It is built on doubles whatever the type of the positions, the 
direction and the length of
+     * an axis being real values even when the positions they are derived from 
are integers.
+     */
+    private Vector<?> getAxis() {
+        final Tuple<?> bottom = getBottom();
+        final Vector<?> axis = Vectors.create(bottom.getSampleSystem(), 
DataType.DOUBLE);
+        axis.set(getTop());
+        axis.subtract(bottom);
+        return axis;
     }
 
     /**
-     * @param height new cylinder height
+     * The height is the length of the axis going from the center of the 
bottom circle to the
+     * center of the top one, so it is not set but derived from the two 
positions this cylinder
+     * is built on.
+     *
+     * @return the cylinder height
      */
-    public void setHeight(double height) {
-        this.height = height;
+    public double getHeight() {
+        return getAxis().length();
     }
 
     /**
@@ -111,24 +189,76 @@ public final class Cylinder extends 
AbstractOrientedGeometry {
         return false;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>A circle of radius <var>r</var> perpendicular to a unit axis 
<var>n</var> spreads by
+     * <var>r</var>·√(1 − <var>n</var>ᵢ²) on the axis <var>i</var>, which is 
the whole radius on
+     * the axes the circle faces and nothing on the axis it is perpendicular 
to. The envelope is
+     * the union of the two circles spread that way. A cylinder whose two 
positions are the same
+     * has no axis to speak of, and is then bounded by its radii on every 
axis.</p>
+     */
+    @Override
+    public BBox getEnvelope() {
+        final Tuple<?> bottom = getBottom();
+        final Tuple<?> top = getTop();
+        final Vector<?> axis = getAxis();
+        final double height = axis.length();
+        final int dim = points.getDimension();
+        final BBox bbox = new BBox(dim);
+        for (int i=0;i<dim;i++){
+            final double b = bottom.get(i);
+            final double t = top.get(i);
+            final double spread;
+            if (height > 0) {
+                final double n = axis.get(i) / height;
+                spread = Math.sqrt(Math.max(0, 1 - n*n));
+            } else {
+                spread = 1;
+            }
+            bbox.setRange(i, Math.min(b - radiusBottom*spread, t - 
radiusTop*spread),
+                             Math.max(b + radiusBottom*spread, t + 
radiusTop*spread));
+        }
+        return bbox;
+    }
+
     @Override
     public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getCoordinateReferenceSystem();
     }
 
     @Override
     public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) 
throws IllegalArgumentException {
-        throw new UnsupportedOperationException("Not supported yet.");
+        points.setCoordinateReferenceSystem(crs);
     }
 
     @Override
     public DataPointsType getDataPointsType() {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return points.getType();
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Cylinder other = (Cylinder) obj;
+        if (!Objects.equals(this.points, other.points)) {
+            return false;
+        }
+        return Double.doubleToLongBits(this.radiusTop) == 
Double.doubleToLongBits(other.radiusTop)
+            && Double.doubleToLongBits(this.radiusBottom) == 
Double.doubleToLongBits(other.radiusBottom);
+    }
 
     @Override
-    public Envelope getUnorientedEnvelope() {
-        throw new UnsupportedOperationException("Not supported yet.");
+    public int hashCode() {
+        int hash = 3;
+        hash = 89 * hash + Objects.hashCode(this.points);
+        hash = 89 * hash + Double.hashCode(this.radiusTop);
+        hash = 89 * hash + Double.hashCode(this.radiusBottom);
+        return hash;
     }
 }
diff --git 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/OrientedGeometryTest.java
 
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/OrientedGeometryTest.java
deleted file mode 100644
index 4bbdd9e833..0000000000
--- 
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/OrientedGeometryTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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;
-
-// Test dependencies
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-
-/**
- * Tests {@link OrientedGeometry}.
- *
- * @author Johann Sorel (Geomatys)
- */
-public class OrientedGeometryTest extends GeometryTest {
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetTransform() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetUnorientedEnvelope() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetCoordinateReferenceSystem() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testSetCoordinateReferenceSystem() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetMetadata() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetAttributesType() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetDimension() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetDimension_DirectPosition() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testIs3D() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetSpatialDimension() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetTopologicDimension() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetBoundaryType() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetGeometryType() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetGeometryType2() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetEnvelope() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetCentroid() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetRepresentativePoint() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetClosure() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetMaximalComplex() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testIsEmpty() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testIsSimple() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testIsCycle() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testIsValid() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testGetBoundary() {
-    }
-
-    @Test
-    @Disabled("Not implemented yet.")
-    public void testUserProperties() {
-    }
-}

Reply via email to