You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ma...@apache.org on 2020/05/06 01:54:22 UTC
[commons-geometry] branch master updated: GEOMETRY-92: adding
specialized segment, ray, and reverse ray classes for 2D and 3D;
GEOMETRY-93: major refactor from 'subhyperplane' naming convention to
'hyperplane-subset' naming convention
This is an automated email from the ASF dual-hosted git repository.
mattjuntunen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-geometry.git
The following commit(s) were added to refs/heads/master by this push:
new eee2589 GEOMETRY-92: adding specialized segment, ray, and reverse ray classes for 2D and 3D; GEOMETRY-93: major refactor from 'subhyperplane' naming convention to 'hyperplane-subset' naming convention
eee2589 is described below
commit eee258978cae8fe4987c2155ddfbd08c73d3c9db
Author: Matt Juntunen <ma...@apache.org>
AuthorDate: Tue May 5 21:50:34 2020 -0400
GEOMETRY-92: adding specialized segment, ray, and reverse ray classes for 2D and 3D; GEOMETRY-93: major refactor from 'subhyperplane' naming convention to 'hyperplane-subset' naming convention
---
.../apache/commons/geometry/core/Embedding.java | 20 +-
.../org/apache/commons/geometry/core/Region.java | 9 +-
.../BoundarySource.java => RegionEmbedding.java} | 33 +-
.../BoundarySource.java => Sized.java} | 33 +-
.../AbstractConvexHyperplaneBoundedRegion.java | 106 ++-
...> AbstractRegionEmbeddingHyperplaneSubset.java} | 26 +-
.../geometry/core/partitioning/BoundarySource.java | 6 +-
.../geometry/core/partitioning/Hyperplane.java | 14 +-
.../core/partitioning/HyperplaneBoundedRegion.java | 2 +-
...Hyperplane.java => HyperplaneConvexSubset.java} | 20 +-
.../core/partitioning/HyperplaneSubset.java | 130 +++
.../geometry/core/partitioning/SubHyperplane.java | 153 ----
.../core/partitioning/bsp/AbstractBSPTree.java | 131 ++-
.../partitioning/bsp/AbstractRegionBSPTree.java | 183 ++--
.../geometry/core/partitioning/bsp/BSPTree.java | 33 +-
.../core/partitioning/bsp/RegionCutBoundary.java | 44 +-
.../commons/geometry/core/RegionEmbeddingTest.java | 116 +++
.../apache/commons/geometry/core/SizedTest.java | 55 ++
.../geometry/core/partition/test/TestBSPTree.java | 15 +-
.../core/partition/test/TestLineSegment.java | 16 +-
.../partition/test/TestLineSegmentCollection.java | 14 +-
.../test/TestLineSegmentCollectionBuilder.java | 14 +-
.../core/partition/test/TestRegionBSPTree.java | 4 +-
.../AbstractConvexHyperplaneBoundedRegionTest.java | 4 +-
.../core/partitioning/AbstractHyperplaneTest.java | 2 +-
...stractRegionEmbeddingHyperplaneSubsetTest.java} | 39 +-
.../core/partitioning/bsp/AbstractBSPTreeTest.java | 2 +-
.../bsp/AbstractRegionBSPTreeTest.java | 22 +-
.../partitioning/bsp/RegionCutBoundaryTest.java | 2 +-
.../euclidean/threed/SphereGenerator.java | 3 +-
.../euclidean/internal/AbstractPathConnector.java | 8 +-
.../commons/geometry/euclidean/oned/Interval.java | 10 +-
.../geometry/euclidean/oned/OrientedPoint.java | 159 +---
.../geometry/euclidean/oned/OrientedPoints.java | 107 +++
.../euclidean/threed/AbstractSubLine3D.java | 56 --
.../euclidean/threed/BoundarySource3D.java | 27 +-
.../threed/BoundarySourceLinecaster3D.java | 37 +-
.../geometry/euclidean/threed/ConvexSubPlane.java | 195 -----
.../geometry/euclidean/threed/ConvexVolume.java | 38 +-
...{SubPlane.java => EmbeddedTreePlaneSubset.java} | 114 +--
.../commons/geometry/euclidean/threed/Plane.java | 184 +---
.../euclidean/threed/PlaneConvexSubset.java | 128 +++
.../{AbstractSubPlane.java => PlaneSubset.java} | 35 +-
.../commons/geometry/euclidean/threed/Planes.java | 264 ++++++
.../geometry/euclidean/threed/RegionBSPTree3D.java | 62 +-
.../geometry/euclidean/threed/Segment3D.java | 267 ------
.../EmbeddedTreeLineSubset3D.java} | 52 +-
.../euclidean/threed/{ => line}/Line3D.java | 156 ++--
.../euclidean/threed/line/LineConvexSubset3D.java | 115 +++
.../threed/line/LineSpanningSubset3D.java | 123 +++
.../euclidean/threed/line/LineSubset3D.java | 62 ++
.../threed/{ => line}/LinecastPoint3D.java | 3 +-
.../threed/{ => line}/Linecastable3D.java | 26 +-
.../geometry/euclidean/threed/line/Lines3D.java | 271 ++++++
.../geometry/euclidean/threed/line/Ray3D.java | 145 +++
.../euclidean/threed/line/ReverseRay3D.java | 139 +++
.../geometry/euclidean/threed/line/Segment3D.java | 141 +++
.../threed/{shapes => line}/package-info.java | 8 +-
.../threed/{shapes => shape}/Parallelepiped.java | 13 +-
.../euclidean/threed/{shapes => shape}/Sphere.java | 42 +-
.../threed/{shapes => shape}/package-info.java | 2 +-
.../euclidean/twod/AbstractSegmentConnector.java | 298 -------
.../geometry/euclidean/twod/AbstractSubLine.java | 127 ---
.../geometry/euclidean/twod/BoundarySource2D.java | 32 +-
.../euclidean/twod/BoundarySourceLinecaster2D.java | 28 +-
.../geometry/euclidean/twod/ConvexArea.java | 83 +-
.../euclidean/twod/EmbeddedTreeLineSubset.java | 262 ++++++
.../commons/geometry/euclidean/twod/Line.java | 155 ++--
.../geometry/euclidean/twod/LineConvexSubset.java | 141 +++
.../euclidean/twod/LineSpanningSubset.java | 156 ++++
.../geometry/euclidean/twod/LineSubset.java | 156 ++++
.../geometry/euclidean/twod/Linecastable2D.java | 20 +-
.../commons/geometry/euclidean/twod/Lines.java | 277 ++++++
.../commons/geometry/euclidean/twod/Ray.java | 194 ++++
.../geometry/euclidean/twod/RegionBSPTree2D.java | 83 +-
.../geometry/euclidean/twod/ReverseRay.java | 189 ++++
.../commons/geometry/euclidean/twod/Segment.java | 329 +++----
.../commons/geometry/euclidean/twod/SubLine.java | 219 -----
.../twod/path/AbstractLinePathConnector.java | 299 +++++++
.../InteriorAngleLinePathConnector.java} | 68 +-
.../twod/{Polyline.java => path/LinePath.java} | 586 +++++++------
.../{threed/shapes => twod/path}/package-info.java | 6 +-
.../euclidean/twod/{shapes => shape}/Circle.java | 17 +-
.../twod/{shapes => shape}/Parallelogram.java | 15 +-
.../twod/{shapes => shape}/package-info.java | 2 +-
.../euclidean/DocumentationExamplesTest.java | 91 +-
.../geometry/euclidean/EuclideanTestUtils.java | 36 +-
.../geometry/euclidean/oned/IntervalTest.java | 78 +-
.../geometry/euclidean/oned/OrientedPointTest.java | 237 ++---
.../euclidean/oned/RegionBSPTree1DTest.java | 46 +-
.../threed/AffineTransformMatrix3DTest.java | 6 +-
.../euclidean/threed/BoundarySource3DTest.java | 24 +-
.../threed/BoundarySourceLinecaster3DTest.java | 57 +-
.../euclidean/threed/ConvexVolumeTest.java | 53 +-
...eTest.java => EmbeddedTreePlaneSubsetTest.java} | 147 ++--
.../euclidean/threed/LinecastChecker3D.java | 6 +-
...ubPlaneTest.java => PlaneConvexSubsetTest.java} | 165 ++--
.../geometry/euclidean/threed/PlaneTest.java | 296 +++----
.../euclidean/threed/RegionBSPTree3DTest.java | 207 ++---
.../geometry/euclidean/threed/Segment3DTest.java | 386 --------
.../EmbeddedTreeLineSubset3DTest.java} | 46 +-
.../euclidean/threed/{ => line}/Line3DTest.java | 273 ++++--
.../threed/line/LineConvexSubset3DTest.java | 293 +++++++
.../threed/{ => line}/LinecastPoint3DTest.java | 17 +-
.../geometry/euclidean/threed/line/Ray3DTest.java | 221 +++++
.../euclidean/threed/line/ReverseRay3DTest.java | 221 +++++
.../euclidean/threed/line/Segment3DTest.java | 337 +++++++
.../threed/rotation/QuaternionRotationTest.java | 2 +-
.../{shapes => shape}/ParallelepipedTest.java | 14 +-
.../threed/{shapes => shape}/SphereTest.java | 71 +-
.../twod/AbstractSegmentConnectorTest.java | 563 ------------
.../twod/AffineTransformMatrix2DTest.java | 6 +-
.../euclidean/twod/BoundarySource2DTest.java | 24 +-
.../twod/BoundarySourceLinecaster2DTest.java | 56 +-
.../geometry/euclidean/twod/ConvexAreaTest.java | 183 ++--
...neTest.java => EmbeddedTreeLineSubsetTest.java} | 307 ++++---
.../euclidean/twod/LineConvexSubsetTest.java | 481 ++++++++++
.../geometry/euclidean/twod/LineSpanTest.java | 220 +++++
.../commons/geometry/euclidean/twod/LineTest.java | 462 +++++-----
.../geometry/euclidean/twod/LinecastChecker2D.java | 4 +-
.../euclidean/twod/LinecastPoint2DTest.java | 14 +-
.../commons/geometry/euclidean/twod/RayTest.java | 374 ++++++++
.../euclidean/twod/RegionBSPTree2DTest.java | 293 +++----
.../geometry/euclidean/twod/ReverseRayTest.java | 368 ++++++++
.../geometry/euclidean/twod/SegmentTest.java | 971 ++++++---------------
.../twod/path/AbstractLinePathConnectorTest.java | 568 ++++++++++++
.../InteriorAngleLinePathConnectorTest.java} | 117 +--
.../{PolylineTest.java => path/LinePathTest.java} | 564 ++++++------
.../euclidean/twod/rotation/Rotation2DTest.java | 5 +-
.../twod/{shapes => shape}/CircleTest.java | 61 +-
.../twod/{shapes => shape}/ParallelogramTest.java | 16 +-
.../examples/jmh/euclidean/CirclePerformance.java | 2 +-
.../jmh/euclidean/RegionBSPTree2DPerformance.java | 139 +++
.../jmh/euclidean/RegionBSPTree3DPerformance.java | 141 +++
.../examples/jmh/euclidean/SpherePerformance.java | 2 +-
.../geometry/hull/euclidean/twod/ConvexHull2D.java | 12 +-
.../hull/euclidean/twod/MonotoneChain.java | 4 +-
.../hull/euclidean/twod/ConvexHull2DTest.java | 22 +-
.../twod/ConvexHullGenerator2DAbstractTest.java | 8 +-
.../geometry/spherical/oned/AngularInterval.java | 12 +-
.../commons/geometry/spherical/oned/CutAngle.java | 144 +--
.../commons/geometry/spherical/oned/CutAngles.java | 92 ++
.../geometry/spherical/oned/RegionBSPTree1S.java | 10 +-
.../spherical/twod/AbstractGreatArcConnector.java | 8 +-
.../geometry/spherical/twod/ConvexArea2S.java | 10 +-
...cle.java => EmbeddedTreeGreatCircleSubset.java} | 68 +-
.../commons/geometry/spherical/twod/GreatArc.java | 46 +-
.../geometry/spherical/twod/GreatArcPath.java | 6 +-
.../geometry/spherical/twod/GreatCircle.java | 76 +-
...tSubGreatCircle.java => GreatCircleSubset.java} | 16 +-
.../geometry/spherical/twod/GreatCircles.java | 130 +++
.../spherical/DocumentationExamplesTest.java | 7 +-
.../spherical/oned/AngularIntervalTest.java | 56 +-
.../geometry/spherical/oned/CutAngleTest.java | 238 +++--
.../spherical/oned/RegionBSPTree1STest.java | 62 +-
.../geometry/spherical/oned/Transform1STest.java | 2 +-
.../twod/AbstractGreatArcPathConnectorTest.java | 44 +-
.../spherical/twod/BoundarySource2STest.java | 2 +-
.../geometry/spherical/twod/ConvexArea2STest.java | 66 +-
...st.java => EmbeddedTreeSubGreatCircleTest.java} | 159 ++--
.../geometry/spherical/twod/GreatArcPathTest.java | 36 +-
.../geometry/spherical/twod/GreatArcTest.java | 62 +-
.../geometry/spherical/twod/GreatCircleTest.java | 162 ++--
.../twod/InteriorAngleGreatArcConnectorTest.java | 50 +-
.../spherical/twod/RegionBSPTree2STest.java | 26 +-
.../geometry/spherical/twod/Transform2STest.java | 2 +-
.../checkstyle/checkstyle-suppressions.xml | 15 +-
src/site/xdoc/userguide/index.xml | 186 ++--
168 files changed, 11587 insertions(+), 7505 deletions(-)
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Embedding.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Embedding.java
index cf258c8..9dca186 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Embedding.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Embedding.java
@@ -36,36 +36,36 @@ import java.util.stream.Collectors;
public interface Embedding<P extends Point<P>, S extends Point<S>> {
/** Transform a space point into a subspace point.
- * @param point n-dimension point of the space
+ * @param pt n-dimension point of the space
* @return lower-dimension point of the subspace corresponding to
* the specified space point
* @see #toSpace
*/
- S toSubspace(P point);
+ S toSubspace(P pt);
/** Transform a collection of space points into subspace points.
- * @param points collection of n-dimension points to transform
+ * @param pts collection of n-dimension points to transform
* @return collection of transformed lower-dimension points.
* @see #toSubspace(Point)
*/
- default List<S> toSubspace(final Collection<P> points) {
- return points.stream().map(this::toSubspace).collect(Collectors.toList());
+ default List<S> toSubspace(final Collection<P> pts) {
+ return pts.stream().map(this::toSubspace).collect(Collectors.toList());
}
/** Transform a subspace point into a space point.
- * @param point lower-dimension point of the subspace
+ * @param pt lower-dimension point of the subspace
* @return n-dimension point of the space corresponding to the
* specified subspace point
* @see #toSubspace(Point)
*/
- P toSpace(S point);
+ P toSpace(S pt);
/** Transform a collection of subspace points into space points.
- * @param points collection of lower-dimension points to transform
+ * @param pts collection of lower-dimension points to transform
* @return collection of transformed n-dimension points.
* @see #toSpace(Point)
*/
- default List<P> toSpace(final Collection<S> points) {
- return points.stream().map(this::toSpace).collect(Collectors.toList());
+ default List<P> toSpace(final Collection<S> pts) {
+ return pts.stream().map(this::toSpace).collect(Collectors.toList());
}
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java
index 16da017..f22e00c 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Region.java
@@ -20,7 +20,7 @@ package org.apache.commons.geometry.core;
* into sets of points lying on the inside, outside, and boundary.
* @param <P> Point implementation type
*/
-public interface Region<P extends Point<P>> {
+public interface Region<P extends Point<P>> extends Sized {
/** Return true if the region spans the entire space. In other words,
* a region is full if no points in the space are classified as
@@ -35,13 +35,6 @@ public interface Region<P extends Point<P>> {
*/
boolean isEmpty();
- /** Get the size of the region. The meaning of this will vary depending on
- * the space and dimension of the region. For example, in Euclidean space,
- * this will be a length in 1D, an area in 2D, and a volume in 3D.
- * @return the size of the region
- */
- double getSize();
-
/** Get the size of the boundary of the region. The size is a value in
* the {@code d-1} dimension space. For example, in Euclidean space,
* this will be a length in 2D and an area in 3D.
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/RegionEmbedding.java
similarity index 52%
copy from commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java
copy to commons-geometry-core/src/main/java/org/apache/commons/geometry/core/RegionEmbedding.java
index 6dffc6b..b82b75a 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/RegionEmbedding.java
@@ -14,21 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.core.partitioning;
+package org.apache.commons.geometry.core;
-import java.util.stream.Stream;
-
-import org.apache.commons.geometry.core.Point;
-
-/** Interface representing an object that can produce region boundaries as a stream
- * of convex subhyperplanes.
- * @param <C> Convex subhyperplane implementation type
+/** Interface representing a geometric element that embeds a region in a subspace.
+ * @param <P> Point type defining the embedding space.
+ * @param <S> Point type defining the embedded subspace.
+ * @see Embedding
+ * @see Region
*/
-@FunctionalInterface
-public interface BoundarySource<C extends ConvexSubHyperplane<? extends Point<?>>> {
+public interface RegionEmbedding<P extends Point<P>, S extends Point<S>>
+ extends Embedding<P, S>, Sized {
+
+ /** Get the size of the instance, which by default is the size of the embedded
+ * subspace region.
+ * @return the size of instance
+ */
+ @Override
+ default double getSize() {
+ return getSubspaceRegion().getSize();
+ }
- /** Return a stream containing the boundaries for this instance.
- * @return a stream containing the boundaries for this instance
+ /** Get the embedded subspace region.
+ * @return the embedded subspace region
*/
- Stream<C> boundaryStream();
+ Region<S> getSubspaceRegion();
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Sized.java
similarity index 50%
copy from commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java
copy to commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Sized.java
index 6dffc6b..b911160 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/Sized.java
@@ -14,21 +14,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.core.partitioning;
+package org.apache.commons.geometry.core;
-import java.util.stream.Stream;
+/** Interface representing a geometric element with a size. The exact meaning
+ * of the size will vary between spaces and dimensions. For example, the size
+ * of a line is its length, while the size of a polygon is its area.
+ */
+public interface Sized {
-import org.apache.commons.geometry.core.Point;
+ /** Get the size of the instance.
+ * @return the size of the instance
+ */
+ double getSize();
-/** Interface representing an object that can produce region boundaries as a stream
- * of convex subhyperplanes.
- * @param <C> Convex subhyperplane implementation type
- */
-@FunctionalInterface
-public interface BoundarySource<C extends ConvexSubHyperplane<? extends Point<?>>> {
+ /** Return true if the size of the instance is finite.
+ * @return true if the size of the instance is finite
+ */
+ default boolean isFinite() {
+ return Double.isFinite(getSize());
+ }
- /** Return a stream containing the boundaries for this instance.
- * @return a stream containing the boundaries for this instance
+ /** Return true if the size of the instance is infinite.
+ * @return true if the size of the instance is infinite
*/
- Stream<C> boundaryStream();
+ default boolean isInfinite() {
+ return Double.isInfinite(getSize());
+ }
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegion.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegion.java
index 82c8bec..5ff18d8 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegion.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegion.java
@@ -29,15 +29,15 @@ import org.apache.commons.geometry.core.Transform;
/** Base class for convex hyperplane-bounded regions. This class provides generic implementations of many
* algorithms related to convex regions.
* @param <P> Point implementation type
- * @param <S> Convex subhyperplane implementation type
+ * @param <S> Hyperplane convex subset implementation type
*/
-public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>, S extends ConvexSubHyperplane<P>>
+public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>, S extends HyperplaneConvexSubset<P>>
implements HyperplaneBoundedRegion<P> {
/** List of boundaries for the region. */
private final List<S> boundaries;
- /** Simple constructor. Callers are responsible for ensuring that the given list of subhyperplanes
- * represent a valid convex region boundary. No validation is performed.
+ /** Simple constructor. Callers are responsible for ensuring that the given list of boundaries
+ * define a convex region. No validation is performed.
* @param boundaries the boundaries of the convex region
*/
protected AbstractConvexHyperplaneBoundedRegion(final List<S> boundaries) {
@@ -121,14 +121,13 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
return closestPt;
}
- /** Trim the given convex subhyperplane to the portion contained inside this instance.
- * @param convexSubHyperplane convex subhyperplane to trim. Null is returned if the subhyperplane
- * does not intersect the instance.
+ /** Trim the given hyperplane subset to the portion contained inside this instance.
+ * @param sub hyperplane subset to trim. Null is returned if the subset does not intersect the instance.
* @return portion of the argument that lies entirely inside the region represented by
* this instance, or null if it does not intersect.
*/
- public ConvexSubHyperplane<P> trim(final ConvexSubHyperplane<P> convexSubHyperplane) {
- ConvexSubHyperplane<P> remaining = convexSubHyperplane;
+ public HyperplaneConvexSubset<P> trim(final HyperplaneConvexSubset<P> sub) {
+ HyperplaneConvexSubset<P> remaining = sub;
for (final S boundary : boundaries) {
remaining = remaining.split(boundary.getHyperplane()).getMinus();
if (remaining == null) {
@@ -154,13 +153,13 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
* @param transform the transform to apply to the instance
* @param thisInstance a reference to the current instance; this is passed as
* an argument in order to allow it to be a generic type
- * @param subhpType the type used for the boundary subhyperplanes
+ * @param boundaryType the type used for the boundary hyperplane subsets
* @param factory function used to create new convex region instances
* @param <R> Region implementation type
* @return the result of the transform operation
*/
protected <R extends AbstractConvexHyperplaneBoundedRegion<P, S>> R transformInternal(
- final Transform<P> transform, final R thisInstance, final Class<S> subhpType,
+ final Transform<P> transform, final R thisInstance, final Class<S> boundaryType,
final Function<List<S>, R> factory) {
if (isFull()) {
@@ -174,7 +173,7 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
// determine if the hyperplanes should be reversed
final S boundary = origBoundaries.get(0);
- ConvexSubHyperplane<P> tBoundary = boundary.transform(transform);
+ HyperplaneConvexSubset<P> tBoundary = boundary.transform(transform);
final boolean reverseDirection = swapsInsideOutside(transform);
@@ -182,7 +181,7 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
if (reverseDirection) {
tBoundary = tBoundary.reverse();
}
- tBoundaries.add(subhpType.cast(tBoundary));
+ tBoundaries.add(boundaryType.cast(tBoundary));
for (int i = 1; i < origBoundaries.size(); ++i) {
tBoundary = origBoundaries.get(i).transform(transform);
@@ -191,7 +190,7 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
tBoundary = tBoundary.reverse();
}
- tBoundaries.add(subhpType.cast(tBoundary));
+ tBoundaries.add(boundaryType.cast(tBoundary));
}
return factory.apply(tBoundaries);
@@ -216,22 +215,22 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
* @param splitter splitting hyperplane
* @param thisInstance a reference to the current instance; this is passed as
* an argument in order to allow it to be a generic type
- * @param subhpType the type used for the boundary subhyperplanes
+ * @param boundaryType the type used for the boundary hyperplane subsets
* @param factory function used to create new convex region instances
* @param <R> Region implementation type
* @return the result of the split operation
*/
protected <R extends AbstractConvexHyperplaneBoundedRegion<P, S>> Split<R> splitInternal(
- final Hyperplane<P> splitter, final R thisInstance, final Class<S> subhpType,
+ final Hyperplane<P> splitter, final R thisInstance, final Class<S> boundaryType,
final Function<List<S>, R> factory) {
if (isFull()) {
- final R minus = factory.apply(Arrays.asList(subhpType.cast(splitter.span())));
- final R plus = factory.apply(Arrays.asList(subhpType.cast(splitter.reverse().span())));
+ final R minus = factory.apply(Arrays.asList(boundaryType.cast(splitter.span())));
+ final R plus = factory.apply(Arrays.asList(boundaryType.cast(splitter.reverse().span())));
return new Split<>(minus, plus);
} else {
- final ConvexSubHyperplane<P> trimmedSplitter = trim(splitter.span());
+ final HyperplaneConvexSubset<P> trimmedSplitter = trim(splitter.span());
if (trimmedSplitter == null) {
// The splitter lies entirely outside of the region; we need
@@ -246,10 +245,10 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
final List<S> minusBoundaries = new ArrayList<>();
final List<S> plusBoundaries = new ArrayList<>();
- splitBoundaries(splitter, subhpType, minusBoundaries, plusBoundaries);
+ splitBoundaries(splitter, boundaryType, minusBoundaries, plusBoundaries);
- minusBoundaries.add(subhpType.cast(trimmedSplitter));
- plusBoundaries.add(subhpType.cast(trimmedSplitter.reverse()));
+ minusBoundaries.add(boundaryType.cast(trimmedSplitter));
+ plusBoundaries.add(boundaryType.cast(trimmedSplitter.reverse()));
return new Split<>(factory.apply(minusBoundaries), factory.apply(plusBoundaries));
}
@@ -284,7 +283,7 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
double minusSize = 0;
double plusSize = 0;
- Split<? extends ConvexSubHyperplane<P>> split;
+ Split<? extends HyperplaneConvexSubset<P>> split;
SplitLocation loc;
for (final S boundary : boundaries) {
@@ -309,18 +308,18 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
/** Split the boundaries of the region by the given hyperplane, adding the split parts into the
* corresponding lists.
* @param splitter splitting hyperplane
- * @param subhpType the type used for the boundary subhyperplanes
+ * @param boundaryType the type used for the boundary hyperplane subsets
* @param minusBoundaries list that will contain the portions of the boundaries on the minus side
* of the splitting hyperplane
* @param plusBoundaries list that will contain the portions of the boundaries on the plus side of
* the splitting hyperplane
*/
- private void splitBoundaries(final Hyperplane<P> splitter, final Class<S> subhpType,
+ private void splitBoundaries(final Hyperplane<P> splitter, final Class<S> boundaryType,
final List<S> minusBoundaries, final List<S> plusBoundaries) {
- Split<? extends ConvexSubHyperplane<P>> split;
- ConvexSubHyperplane<P> minusBoundary;
- ConvexSubHyperplane<P> plusBoundary;
+ Split<? extends HyperplaneConvexSubset<P>> split;
+ HyperplaneConvexSubset<P> minusBoundary;
+ HyperplaneConvexSubset<P> plusBoundary;
for (final S boundary : boundaries) {
split = boundary.split(splitter);
@@ -329,37 +328,36 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
plusBoundary = split.getPlus();
if (minusBoundary != null) {
- minusBoundaries.add(subhpType.cast(minusBoundary));
+ minusBoundaries.add(boundaryType.cast(minusBoundary));
}
if (plusBoundary != null) {
- plusBoundaries.add(subhpType.cast(plusBoundary));
+ plusBoundaries.add(boundaryType.cast(plusBoundary));
}
}
}
- /** Internal class encapsulating the logic for building convex region boundaries from collections of
- * hyperplanes.
+ /** Internal class encapsulating the logic for building convex region boundaries from collections of hyperplanes.
* @param <P> Point implementation type
- * @param <S> ConvexSubHyperplane implementation type
+ * @param <S> Hyperplane convex subset implementation type
*/
- protected static class ConvexRegionBoundaryBuilder<P extends Point<P>, S extends ConvexSubHyperplane<P>> {
+ protected static class ConvexRegionBoundaryBuilder<P extends Point<P>, S extends HyperplaneConvexSubset<P>> {
- /** Convex subhyperplane implementation type. */
- private final Class<S> subhyperplaneType;
+ /** Hyperplane convex subset implementation type. */
+ private final Class<S> subsetType;
- /** Construct a new instance for building convex region boundaries with the given convex subhyperplane
- * implementation type.
- * @param subhyperplaneType Convex subhyperplane implementation type
+ /** Construct a new instance for building convex region boundaries with the given hyperplane
+ * convex subset implementation type.
+ * @param subsetType Hyperplane convex subset implementation type
*/
- public ConvexRegionBoundaryBuilder(final Class<S> subhyperplaneType) {
- this.subhyperplaneType = subhyperplaneType;
+ public ConvexRegionBoundaryBuilder(final Class<S> subsetType) {
+ this.subsetType = subsetType;
}
- /** Compute a list of convex subhyperplanes representing the boundaries of the convex region
+ /** Compute a list of hyperplane convex subsets representing the boundaries of the convex region
* bounded by the given collection of hyperplanes.
* @param bounds hyperplanes defining the convex region
- * @return a list of convex subhyperplanes representing the boundaries of the convex region
+ * @return a list of hyperplane convex subsets representing the boundaries of the convex region
* @throws IllegalArgumentException if the given hyperplanes do not form a convex region
*/
public List<S> build(final Iterable<? extends Hyperplane<P>> bounds) {
@@ -368,14 +366,14 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
// cut each hyperplane by every other hyperplane in order to get the region boundaries
int boundIdx = 0;
- ConvexSubHyperplane<P> boundary;
+ HyperplaneConvexSubset<P> boundary;
for (final Hyperplane<P> currentBound : bounds) {
++boundIdx;
boundary = splitBound(currentBound, bounds, boundIdx);
if (boundary != null) {
- boundaries.add(subhyperplaneType.cast(boundary));
+ boundaries.add(subsetType.cast(boundary));
}
}
@@ -388,18 +386,18 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
}
/** Split the given bounding hyperplane by all of the other hyperplanes in the given collection, returning the
- * remaining subhyperplane.
+ * remaining hyperplane subset.
* @param currentBound the bound to split; this value is assumed to have come from {@code bounds}
* @param bounds collection of bounds to use to split {@code currentBound}
* @param currentBoundIdx the index of {@code currentBound} in {@code bounds}
- * @return the part of {@code currentBound}'s subhyperplane that lies on the minus side of all of the
+ * @return the part of {@code currentBound}'s hyperplane subset that lies on the minus side of all of the
* splitting hyperplanes
* @throws IllegalArgumentException if the hyperplanes do not form a convex region
*/
- private ConvexSubHyperplane<P> splitBound(final Hyperplane<P> currentBound,
+ private HyperplaneConvexSubset<P> splitBound(final Hyperplane<P> currentBound,
final Iterable<? extends Hyperplane<P>> bounds, final int currentBoundIdx) {
- ConvexSubHyperplane<P> boundary = currentBound.span();
+ HyperplaneConvexSubset<P> boundary = currentBound.span();
int splitterIdx = 0;
for (final Hyperplane<P> splitter : bounds) {
@@ -410,15 +408,15 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
if (currentBoundIdx > splitterIdx) {
// this hyperplane is duplicated in the list; skip all but the
- // first insertion of its subhyperplane
+ // first insertion of its hyperplane subset
return null;
}
} else {
- // split the subhyperplane
- final Split<? extends ConvexSubHyperplane<P>> split = boundary.split(splitter);
+ // split the boundary
+ final Split<? extends HyperplaneConvexSubset<P>> split = boundary.split(splitter);
if (split.getLocation() == SplitLocation.NEITHER) {
- // the subhyperplane lies directly on the splitter
+ // the boundary lies directly on the splitter
if (!currentBound.similarOrientation(splitter)) {
// two or more splitters are coincident and have opposite
@@ -426,7 +424,7 @@ public abstract class AbstractConvexHyperplaneBoundedRegion<P extends Point<P>,
// of both
throw nonConvexException(bounds);
} else if (currentBoundIdx > splitterIdx) {
- // two or more hyperplanes are equivalent; only use the boundary
+ // two or more hyperplanes are equivalent; only use the boundary
// from the first one and return null for this one
return null;
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractEmbeddingSubHyperplane.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractRegionEmbeddingHyperplaneSubset.java
similarity index 81%
rename from commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractEmbeddingSubHyperplane.java
rename to commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractRegionEmbeddingHyperplaneSubset.java
index acbce9c..e72071a 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractEmbeddingSubHyperplane.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/AbstractRegionEmbeddingHyperplaneSubset.java
@@ -18,18 +18,19 @@ package org.apache.commons.geometry.core.partitioning;
import org.apache.commons.geometry.core.Point;
import org.apache.commons.geometry.core.Region;
+import org.apache.commons.geometry.core.RegionEmbedding;
import org.apache.commons.geometry.core.RegionLocation;
-/** Abstract base class for subhyperplane implementations that embed a lower-dimension region through
+/** Abstract base class for hyperplane subset implementations that embed a lower-dimension region through
* an embedding hyperplane.
* @param <P> Point implementation type
* @param <S> Subspace point implementation type
* @param <H> Hyperplane containing the embedded subspace
*/
-public abstract class AbstractEmbeddingSubHyperplane<
+public abstract class AbstractRegionEmbeddingHyperplaneSubset<
P extends Point<P>,
S extends Point<S>,
- H extends EmbeddingHyperplane<P, S>> implements SubHyperplane<P> {
+ H extends EmbeddingHyperplane<P, S>> implements HyperplaneSubset<P>, RegionEmbedding<P, S> {
/** {@inheritDoc} */
@Override
@@ -45,20 +46,14 @@ public abstract class AbstractEmbeddingSubHyperplane<
/** {@inheritDoc} */
@Override
- public boolean isInfinite() {
- return Double.isInfinite(getSize());
+ public S toSubspace(final P pt) {
+ return getHyperplane().toSubspace(pt);
}
/** {@inheritDoc} */
@Override
- public boolean isFinite() {
- return Double.isFinite(getSize());
- }
-
- /** {@inheritDoc} */
- @Override
- public double getSize() {
- return getSubspaceRegion().getSize();
+ public P toSpace(final S pt) {
+ return getHyperplane().toSpace(pt);
}
/** {@inheritDoc} */
@@ -98,8 +93,7 @@ public abstract class AbstractEmbeddingSubHyperplane<
@Override
public abstract H getHyperplane();
- /** Return the embedded subspace region for this instance.
- * @return the embedded subspace region for this instance
- */
+ /** {@inheritDoc} */
+ @Override
public abstract HyperplaneBoundedRegion<S> getSubspaceRegion();
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java
index 6dffc6b..625faf1 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/BoundarySource.java
@@ -21,11 +21,11 @@ import java.util.stream.Stream;
import org.apache.commons.geometry.core.Point;
/** Interface representing an object that can produce region boundaries as a stream
- * of convex subhyperplanes.
- * @param <C> Convex subhyperplane implementation type
+ * of hyperplane convex subsets.
+ * @param <C> Hyperplane convex subset implementation type
*/
@FunctionalInterface
-public interface BoundarySource<C extends ConvexSubHyperplane<? extends Point<?>>> {
+public interface BoundarySource<C extends HyperplaneConvexSubset<? extends Point<?>>> {
/** Return a stream containing the boundaries for this instance.
* @return a stream containing the boundaries for this instance
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java
index 6ae7ff1..aed3b33 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/Hyperplane.java
@@ -19,8 +19,8 @@ package org.apache.commons.geometry.core.partitioning;
import org.apache.commons.geometry.core.Point;
import org.apache.commons.geometry.core.Transform;
-/** Interface representing a hyperplane, which is a subspace of dimension
- * one less than its surrounding space. (A hyperplane in Euclidean 3D space,
+/** Interface representing a hyperplane, which in a space of dimension {@code n} is
+ * a subspace of dimension {@code n - 1}. (A hyperplane in Euclidean 3D space,
* for example, is a 2 dimensional plane.)
*
* <p>
@@ -36,7 +36,7 @@ import org.apache.commons.geometry.core.Transform;
*
* @param <P> Point implementation type
* @see HyperplaneLocation
- * @see SubHyperplane
+ * @see HyperplaneSubset
*/
public interface Hyperplane<P extends Point<P>> {
@@ -92,9 +92,9 @@ public interface Hyperplane<P extends Point<P>> {
*/
boolean similarOrientation(Hyperplane<P> other);
- /** Return a {@link ConvexSubHyperplane} spanning this entire hyperplane. The returned
- * subhyperplane contains all points lying in this hyperplane and no more.
- * @return a {@link ConvexSubHyperplane} containing all points lying in this hyperplane
+ /** Return a {@link HyperplaneConvexSubset} spanning this entire hyperplane. The returned
+ * subset contains all points lying in this hyperplane and no more.
+ * @return a {@link HyperplaneConvexSubset} containing all points lying in this hyperplane
*/
- ConvexSubHyperplane<P> span();
+ HyperplaneConvexSubset<P> span();
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneBoundedRegion.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneBoundedRegion.java
index 0718d09..982c60a 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneBoundedRegion.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneBoundedRegion.java
@@ -21,7 +21,7 @@ import org.apache.commons.geometry.core.Region;
/** Interface representing regions with boundaries defined by hyperplanes or
* portions of hyperplanes. This interface is intended to represent closed regions
- * with finite sizes as well as infinite and empty spaces. Regions of this type
+ * with finite sizes as well as infinite and empty regions. Regions of this type
* can be recursively split by hyperplanes into similar regions.
* @param <P> Point implementation type
*/
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/ConvexSubHyperplane.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneConvexSubset.java
similarity index 67%
rename from commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/ConvexSubHyperplane.java
rename to commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneConvexSubset.java
index 606e233..96eb987 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/ConvexSubHyperplane.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneConvexSubset.java
@@ -19,32 +19,32 @@ package org.apache.commons.geometry.core.partitioning;
import org.apache.commons.geometry.core.Point;
import org.apache.commons.geometry.core.Transform;
-/** Extension of the {@link SubHyperplane} interface with the additional restriction
+/** Extension of the {@link HyperplaneSubset} interface with the additional restriction
* that instances represent convex regions of space.
* @param <P> Point implementation type
*/
-public interface ConvexSubHyperplane<P extends Point<P>> extends SubHyperplane<P> {
+public interface HyperplaneConvexSubset<P extends Point<P>> extends HyperplaneSubset<P> {
- /** Reverse the orientation of the hyperplane for this instance. The subhyperplane
- * occupies the same locations in space but with a reversed orientation.
- * @return a convex subhyperplane representing the same region but with the
+ /** Reverse the orientation of the hyperplane for this instance, returning the result as
+ * a new instance. The returned subset contains the same points but has a reversed orientation.
+ * @return a hyperplane convex subset representing the same region but with the
* opposite orientation.
*/
- ConvexSubHyperplane<P> reverse();
+ HyperplaneConvexSubset<P> reverse();
/** {@inheritDoc}
*
- * <p>The parts resulting from a split operation with a convex subhyperplane
+ * <p>The parts resulting from a split operation with a convex subset
* are guaranteed to also be convex.</p>
*/
@Override
- Split<? extends ConvexSubHyperplane<P>> split(Hyperplane<P> splitter);
+ Split<? extends HyperplaneConvexSubset<P>> split(Hyperplane<P> splitter);
/** {@inheritDoc}
*
- * <p>Convex subhyperplanes subjected to affine transformations remain
+ * <p>Hyperplane convex subsets subjected to affine transformations remain
* convex.</p>
*/
@Override
- ConvexSubHyperplane<P> transform(Transform<P> transform);
+ HyperplaneConvexSubset<P> transform(Transform<P> transform);
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneSubset.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneSubset.java
new file mode 100644
index 0000000..8d3f73b
--- /dev/null
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/HyperplaneSubset.java
@@ -0,0 +1,130 @@
+/*
+ * 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.commons.geometry.core.partitioning;
+
+import java.util.List;
+
+import org.apache.commons.geometry.core.Point;
+import org.apache.commons.geometry.core.RegionLocation;
+import org.apache.commons.geometry.core.Sized;
+import org.apache.commons.geometry.core.Transform;
+
+/** Interface representing a subset of the points lying on a hyperplane. Examples include
+ * rays and line segments in Euclidean 2D space and triangular facets in Euclidean 3D space.
+ * Hyperplane subsets can have finite or infinite size and can represent contiguous regions
+ * of the hyperplane (as in the examples aboves); multiple, disjoint regions; or the
+ * {@link Hyperplane#span() entire hyperplane}.
+ *
+ * @param <P> Point implementation type
+ * @see Hyperplane
+ */
+public interface HyperplaneSubset<P extends Point<P>> extends Splittable<P, HyperplaneSubset<P>>, Sized {
+
+ /** Get the hyperplane containing this instance.
+ * @return the hyperplane containing this instance
+ */
+ Hyperplane<P> getHyperplane();
+
+ /** Return true if this instance contains all points in the
+ * hyperplane.
+ * @return true if this instance contains all points in the
+ * hyperplane
+ */
+ boolean isFull();
+
+ /** Return true if this instance does not contain any points.
+ * @return true if this instance does not contain any points
+ */
+ boolean isEmpty();
+
+ /** Classify a point with respect to the subset region. The point is classified as follows:
+ * <ul>
+ * <li>{@link RegionLocation#INSIDE INSIDE} - The point lies on the hyperplane
+ * and inside of the subset region.</li>
+ * <li>{@link RegionLocation#BOUNDARY BOUNDARY} - The point lies on the hyperplane
+ * and is on the boundary of the subset region.</li>
+ * <li>{@link RegionLocation#OUTSIDE OUTSIDE} - The point does not lie on
+ * the hyperplane or it does lie on the hyperplane but is outside of the
+ * subset region.</li>
+ * </ul>
+ * @param pt the point to classify
+ * @return classification of the point with respect to the hyperplane
+ * and subspace region
+ */
+ RegionLocation classify(P pt);
+
+ /** Return true if the hyperplane subset contains the given point, meaning that the point
+ * lies on the hyperplane and is not on the outside of the subset region.
+ * @param pt the point to check
+ * @return true if the point is contained in the hyperplane subset
+ */
+ default boolean contains(P pt) {
+ final RegionLocation loc = classify(pt);
+ return loc != null && loc != RegionLocation.OUTSIDE;
+ }
+
+ /** Return the closest point to the argument that is contained in the subset
+ * (ie, not classified as {@link RegionLocation#OUTSIDE outside}), or null if no
+ * such point exists.
+ * @param pt the reference point
+ * @return the closest point to the reference point that is contained in the subset,
+ * or null if no such point exists
+ */
+ P closest(P pt);
+
+ /** Return a {@link Builder} instance for joining multiple
+ * hyperplane subsets together.
+ * @return a new builder instance
+ */
+ Builder<P> builder();
+
+ /** Return a new hyperplane subset resulting from the application of the given transform.
+ * The current instance is not modified.
+ * @param transform the transform instance to apply
+ * @return new transformed hyperplane subset
+ */
+ HyperplaneSubset<P> transform(Transform<P> transform);
+
+ /** Convert this instance into a list of convex child subsets.
+ * @return a list of hyperplane convex subsets representing the same subspace
+ * region as this instance
+ */
+ List<? extends HyperplaneConvexSubset<P>> toConvex();
+
+ /** Interface for joining multiple {@link HyperplaneSubset}s into a single
+ * instance.
+ * @param <P> Point implementation type
+ */
+ interface Builder<P extends Point<P>> {
+
+ /** Add a {@link HyperplaneSubset} instance to the builder.
+ * @param sub subset to add to this instance
+ */
+ void add(HyperplaneSubset<P> sub);
+
+ /** Add a {@link HyperplaneConvexSubset} instance to the builder.
+ * @param sub convex subset to add to this instance
+ */
+ void add(HyperplaneConvexSubset<P> sub);
+
+ /** Get a {@link HyperplaneSubset} representing the union
+ * of all input subsets.
+ * @return subset representing the union of all input subsets
+ */
+ HyperplaneSubset<P> build();
+ }
+}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/SubHyperplane.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/SubHyperplane.java
deleted file mode 100644
index 74a4169..0000000
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/SubHyperplane.java
+++ /dev/null
@@ -1,153 +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.commons.geometry.core.partitioning;
-
-import java.util.List;
-
-import org.apache.commons.geometry.core.Point;
-import org.apache.commons.geometry.core.RegionLocation;
-import org.apache.commons.geometry.core.Transform;
-
-/** Interface representing subhyperplanes.
- *
- * <p>
- * A subhyperplane is a portion of a hyperplane. For example, the triangular
- * facet of a polyhedron in Euclidean 3D space is a subhyperplane because
- * its interior represents a subset of the plane defined by the three points.
- * While hyperplanes always extend through the entire space that surrounds
- * them, subhyperplanes have no such restriction: they can represent a single,
- * small portion of the hyperplane (as in the example above); multiple, disjoint
- * regions; or the entire hyperplane.
- *
- * @param <P> Point implementation type
- * @see Hyperplane
- */
-public interface SubHyperplane<P extends Point<P>> extends Splittable<P, SubHyperplane<P>> {
-
- /** Get the hyperplane that this instance is embedded in.
- * @return the hyperplane that this instance is embedded in.
- */
- Hyperplane<P> getHyperplane();
-
- /** Return true if this instance contains all points in the
- * hyperplane.
- * @return true if this instance contains all points in the
- * hyperplane
- */
- boolean isFull();
-
- /** Return true if this instance does not contain any points.
- * @return true if this instance does not contain any points
- */
- boolean isEmpty();
-
- /** Return true if this instance has infinite size.
- * @return true if this instance has infinite size
- */
- boolean isInfinite();
-
- /** Return true if this instance has finite size.
- * @return true if this instance has finite size
- */
- boolean isFinite();
-
- /** Return the size of this instance. This will have different
- * meanings in different spaces and dimensions. For example, in
- * Euclidean space, this will be length in 2D and area in 3D.
- * @return the size of this instance
- */
- double getSize();
-
- /** Classify a point with respect to the subhyperplane's region. The point is
- * classified as follows:
- * <ul>
- * <li>{@link RegionLocation#INSIDE INSIDE} - The point lies on the hyperplane
- * and inside of the subhyperplane's region.</li>
- * <li>{@link RegionLocation#BOUNDARY BOUNDARY} - The point lies on the hyperplane
- * and is on the boundary of the subhyperplane's region.</li>
- * <li>{@link RegionLocation#OUTSIDE OUTSIDE} - The point does not lie on
- * the hyperplane or it does lie on the hyperplane but is outside of the
- * subhyperplane's region.</li>
- * </ul>
- * @param point the point to classify
- * @return classification of the point with respect to the subhyperplane's hyperplane
- * and region
- */
- RegionLocation classify(P point);
-
- /** Return true if the subhyperplane contains the given point, meaning that the point
- * lies on the hyperplane and is not on the outside of the subhyperplane's region.
- * @param point the point to check
- * @return true if the point is contained in the subhyperplane
- */
- default boolean contains(P point) {
- final RegionLocation loc = classify(point);
- return loc != null && loc != RegionLocation.OUTSIDE;
- }
-
- /** Return the closest point to the argument that is contained in the subhyperplane
- * (ie, not classified as {@link RegionLocation#OUTSIDE outside}), or null if no
- * such point exists.
- * @param point the reference point
- * @return the closest point to the reference point that is contained in the subhyperplane,
- * or null if no such point exists
- */
- P closest(P point);
-
- /** Return a {@link Builder} instance for joining multiple
- * subhyperplanes together.
- * @return a new builder instance
- */
- Builder<P> builder();
-
- /** Return a new subhyperplane instance resulting from the application
- * of the given transform. The current instance is not modified.
- * @param transform the transform instance to apply
- * @return new transformed subhyperplane instance
- */
- SubHyperplane<P> transform(Transform<P> transform);
-
- /** Convert this instance into a list of convex child subhyperplanes.
- * @return a list of convex subhyperplanes representing the same subspace
- * region as this instance
- */
- List<? extends ConvexSubHyperplane<P>> toConvex();
-
- /** Interface for joining multiple {@link SubHyperplane}s into a single
- * instance.
- * @param <P> Point implementation type
- */
- interface Builder<P extends Point<P>> {
-
- /** Add a {@link SubHyperplane} instance to the builder.
- * @param sub subhyperplane to add to this instance
- */
- void add(SubHyperplane<P> sub);
-
- /** Add a {@link ConvexSubHyperplane} instance to the builder.
- * @param sub convex subhyperplane to add to this instance
- */
- void add(ConvexSubHyperplane<P> sub);
-
- /** Get a {@link SubHyperplane} representing the union
- * of all input subhyperplanes.
- * @return subhyperplane representing the union of all input
- * subhyperplanes
- */
- SubHyperplane<P> build();
- }
-}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTree.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTree.java
index a7d7a2b..55761d2 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTree.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTree.java
@@ -23,7 +23,7 @@ import java.util.NoSuchElementException;
import org.apache.commons.geometry.core.Point;
import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
import org.apache.commons.geometry.core.partitioning.Split;
@@ -49,7 +49,7 @@ import org.apache.commons.geometry.core.partitioning.SplitLocation;
* <li>Since the methods used to construct and modify trees can vary by use case, no public API is provided
* for manipulating the tree. Subclasses are expected to use the protected methods of this class to
* create their own. For tree construction, subclasses are expected to pass their own {@link SubtreeInitializer}
- * instances to {@link #insert(ConvexSubHyperplane, SubtreeInitializer) insert} and
+ * instances to {@link #insert(HyperplaneConvexSubset, SubtreeInitializer) insert} and
* {@link #cutNode(AbstractNode, Hyperplane, SubtreeInitializer) cutNode} in order to set the correct properties on
* tree nodes. To support tree copying, subclasses must also override
* {@link #copyNodeProperties(AbstractNode, AbstractNode) copyNodeProperties}.</li>
@@ -212,17 +212,15 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
/** Copy non-structural node properties from {@code src} to {@code dst}.
* Non-structural properties are those properties not directly related
* to the structure of the BSP tree, i.e. properties other than parent/child
- * connections and cut subhyperplanes. Subclasses should override this method
- * when additional properties are stored on nodes.
+ * connections and cuts. Subclasses should override this method to copy additional
+ * properties stored on nodes.
* @param src source node
* @param dst destination node
*/
- protected void copyNodeProperties(final N src, final N dst) {
- // no-op
- }
+ protected abstract void copyNodeProperties(N src, N dst);
/** Create a non-structural copy of the given node. Properties such as parent/child
- * connections and cut subhyperplanes are <em>not</em> copied.
+ * connections and cuts are <em>not</em> copied.
* @param src the node to copy; does not need to belong to the current tree
* @return the copied node
* @see AbstractBSPTree#copyNodeProperties(AbstractNode, AbstractNode)
@@ -250,7 +248,7 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
copyNodeProperties(src, dst);
// copy the subtree structure
- ConvexSubHyperplane<P> cut = null;
+ HyperplaneConvexSubset<P> cut = null;
N minus = null;
N plus = null;
@@ -333,7 +331,7 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
* @param start the node to begin the search with
* @param pt the point to check
* @param cutRule value determining the search behavior when the test point
- * lies directly on the cut subhyperplane of an internal node
+ * lies directly on the cut of an internal node
* @return the smallest node in the tree containing the point
*/
protected N findNode(final N start, final P pt, final FindNodeCutRule cutRule) {
@@ -425,7 +423,7 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
* path from the given node to the root of the tree.</li>
* <li>If the remaining portion of the hyperplane is <em>not</em> empty, then
* <ul>
- * <li>the remaining portion becomes the cut subhyperplane for the node,</li>
+ * <li>the remaining portion becomes the cut hyperplane subset for the node,</li>
* <li>two new child nodes are created and initialized with
* {@code subtreeInitializer}, and</li>
* <li>true is returned.</li>
@@ -453,8 +451,8 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
* @param subtreeInitializer object used to initialize any newly-created subtrees
* @return true if the node was cut and two new child nodes were created;
* otherwise false
- * @see #trimToNode(AbstractNode, ConvexSubHyperplane)
- * @see #setNodeCut(AbstractNode, ConvexSubHyperplane, SubtreeInitializer)
+ * @see #trimToNode(AbstractNode, HyperplaneConvexSubset)
+ * @see #setNodeCut(AbstractNode, HyperplaneConvexSubset, SubtreeInitializer)
* @see #removeNodeCut(AbstractNode)
* @see #invalidate()
*/
@@ -463,7 +461,7 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
// cut the hyperplane using all hyperplanes from this node up
// to the root
- final ConvexSubHyperplane<P> cut = trimToNode(node, cutter.span());
+ final HyperplaneConvexSubset<P> cut = trimToNode(node, cutter.span());
if (cut == null || cut.isEmpty()) {
// insertion failed; the node was not cut
removeNodeCut(node);
@@ -474,18 +472,18 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
return true;
}
- /** Trim the given subhyperplane to the region defined by the given node. This method cuts the
- * subhyperplane with the cut hyperplanes (binary partitioners) of all parent nodes up to
- * the root and returns the trimmed subhyperplane or {@code null} if the subhyperplane lies
- * outside of the region defined by the node.
+ /** Trim the given hyperplane convex subset to the region defined by the given node. This method
+ * cuts the subset with the cut hyperplanes (binary partitioners) of all parent nodes up to the
+ * root and returns the trimmed subset or {@code null} if the subset lies outside of the region
+ * defined by the node.
*
- * <p>If the subhyperplane is directly coincident with a binary partitioner of a parent node,
+ * <p>If the subset is directly coincident with a binary partitioner of a parent node,
* then the relative orientations of the associated hyperplanes are used to determine the behavior,
* as described below.
* <ul>
- * <li>If the orientations are <strong>similar</strong>, then the subhyperplane is determined to
+ * <li>If the orientations are <strong>similar</strong>, then the subset is determined to
* lie <em>outside</em> of the node's region and {@code null} is returned.</li>
- * <li>If the orientations are <strong>different</strong> (ie, opposite), then the subhyperplane
+ * <li>If the orientations are <strong>different</strong> (ie, opposite), then the subset
* is determined to lie <em>inside</em> of the node's region and the fit operation continues
* with the remaining parent nodes.</li>
* </ul>
@@ -503,24 +501,24 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
* hyperplane to the tree that is coincident with a parent node but with the opposite orientation,
* <em>does</em> add information to the tree.
*
- * @param node the node representing the region to fit the subhyperplane to
- * @param sub the subhyperplane to trim to the node's region
- * @return the trimmed subhyperplane or null if the given subhyperplane does not intersect
+ * @param node the node representing the region to fit the hyperplane subset to
+ * @param sub the hyperplane subset to trim to the node's region
+ * @return the trimmed hyperplane subset or null if the given hyperplane subset does not intersect
* the node's region
*/
- protected ConvexSubHyperplane<P> trimToNode(final N node, final ConvexSubHyperplane<P> sub) {
+ protected HyperplaneConvexSubset<P> trimToNode(final N node, final HyperplaneConvexSubset<P> sub) {
- ConvexSubHyperplane<P> result = sub;
+ HyperplaneConvexSubset<P> result = sub;
N parentNode = node.getParent();
N currentNode = node;
while (parentNode != null && result != null) {
- final Split<? extends ConvexSubHyperplane<P>> split = result.split(parentNode.getCutHyperplane());
+ final Split<? extends HyperplaneConvexSubset<P>> split = result.split(parentNode.getCutHyperplane());
if (split.getLocation() == SplitLocation.NEITHER) {
// if we're directly on the splitter and have the same orientation, then
- // we say the subhyperplane does not lie in the node's region (no new information
+ // we say the subset does not lie in the node's region (no new information
// is added to the tree in this case)
if (result.getHyperplane().similarOrientation(parentNode.getCutHyperplane())) {
result = null;
@@ -556,19 +554,19 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
return false;
}
- /** Set the cut subhyperplane for the given node. Two new child nodes are created for the given
+ /** Set the cut hyperplane subset for the given node. Two new child nodes are created for the
* node and the new subtree is initialized with {@code subtreeInitializer}.
*
* <p>This method performs absolutely <em>no</em> validation on the given cut
- * subhyperplane. It is the responsibility of the caller to ensure that the
- * subhyperplane fits the region represented by the node.</p>
+ * hyperplane subset. It is the responsibility of the caller to ensure that the
+ * hyperplane subset fits the region represented by the node.</p>
*
* <p>This method always calls {@link #invalidate()} to invalidate cached tree properties.</p>
* @param node the node to cut
- * @param cut the convex subhyperplane to set as the node cut
+ * @param cut the hyperplane convex subset to set as the node cut
* @param subtreeInitializer object used to initialize the newly-created subtree
*/
- protected void setNodeCut(final N node, final ConvexSubHyperplane<P> cut,
+ protected void setNodeCut(final N node, final HyperplaneConvexSubset<P> cut,
final SubtreeInitializer<N> subtreeInitializer) {
node.setSubtree(cut, createNode(), createNode());
@@ -578,35 +576,35 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
invalidate();
}
- /** Insert the given convex subhyperplane into the tree, starting at the root node. Any subtrees
+ /** Insert the given hyperplane convex subset into the tree, starting at the root node. Any subtrees
* created are initialized with {@code subtreeInit}.
- * @param convexSub convex subhyperplane to insert into the tree
+ * @param convexSub hyperplane convex subset to insert into the tree
* @param subtreeInit object used to initialize newly created subtrees
*/
- protected void insert(final ConvexSubHyperplane<P> convexSub, final SubtreeInitializer<N> subtreeInit) {
+ protected void insert(final HyperplaneConvexSubset<P> convexSub, final SubtreeInitializer<N> subtreeInit) {
insertRecursive(getRoot(), convexSub,
convexSub.getHyperplane().span(), subtreeInit);
}
- /** Recursively insert a subhyperplane into the tree at the given node.
+ /** Recursively insert a hyperplane convex subset into the tree at the given node.
* @param node the node to begin insertion with
- * @param insert the subhyperplane to insert
- * @param trimmed subhyperplane containing the result of splitting the entire
+ * @param insert the hyperplane subset to insert
+ * @param trimmed hyperplane subset containing the result of splitting the entire
* space with each hyperplane from this node to the root
* @param subtreeInit object used to initialize newly created subtrees
*/
- private void insertRecursive(final N node, final ConvexSubHyperplane<P> insert,
- final ConvexSubHyperplane<P> trimmed, final SubtreeInitializer<N> subtreeInit) {
+ private void insertRecursive(final N node, final HyperplaneConvexSubset<P> insert,
+ final HyperplaneConvexSubset<P> trimmed, final SubtreeInitializer<N> subtreeInit) {
if (node.isLeaf()) {
setNodeCut(node, trimmed, subtreeInit);
} else {
- final Split<? extends ConvexSubHyperplane<P>> insertSplit = insert.split(node.getCutHyperplane());
+ final Split<? extends HyperplaneConvexSubset<P>> insertSplit = insert.split(node.getCutHyperplane());
- final ConvexSubHyperplane<P> minus = insertSplit.getMinus();
- final ConvexSubHyperplane<P> plus = insertSplit.getPlus();
+ final HyperplaneConvexSubset<P> minus = insertSplit.getMinus();
+ final HyperplaneConvexSubset<P> plus = insertSplit.getPlus();
if (minus != null || plus != null) {
- final Split<? extends ConvexSubHyperplane<P>> trimmedSplit = trimmed.split(node.getCutHyperplane());
+ final Split<? extends HyperplaneConvexSubset<P>> trimmedSplit = trimmed.split(node.getCutHyperplane());
if (minus != null) {
insertRecursive(node.getMinus(), minus, trimmedSplit.getMinus(), subtreeInit);
@@ -642,7 +640,7 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
private void transformRecursive(final N node, final Transform<P> t, final boolean swapChildren) {
if (node.isInternal()) {
// transform our cut
- final ConvexSubHyperplane<P> transformedCut = node.getCut().transform(t);
+ final HyperplaneConvexSubset<P> transformedCut = node.getCut().transform(t);
// transform our children
transformRecursive(node.getMinus(), t, swapChildren);
@@ -680,29 +678,29 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
}
}
- /** Split the subtree rooted at the given node by a partitioning convex subhyperplane defined
+ /** Split the subtree rooted at the given node by a partitioning convex subset defined
* on the same region as the node. The subtree rooted at {@code node} is imported into
* this tree, meaning that if it comes from a different tree, the other tree is not
* modified.
* @param node the root node of the subtree to split; may come from a different tree,
* in which case the other tree is not modified
- * @param partitioner partitioning convex subhyperplane
+ * @param partitioner partitioning convex subset
* @return node containing the split subtree
*/
- protected N splitSubtree(final N node, final ConvexSubHyperplane<P> partitioner) {
+ protected N splitSubtree(final N node, final HyperplaneConvexSubset<P> partitioner) {
if (node.isLeaf()) {
return splitLeafNode(node, partitioner);
}
return splitInternalNode(node, partitioner);
}
- /** Split the given leaf node by a partitioning convex subhyperplane defined on the
+ /** Split the given leaf node by a partitioning convex subset defined on the
* same region and import it into this tree.
* @param node the leaf node to split
- * @param partitioner partitioning convex subhyperplane
+ * @param partitioner partitioning convex subset
* @return node containing the split subtree
*/
- private N splitLeafNode(final N node, final ConvexSubHyperplane<P> partitioner) {
+ private N splitLeafNode(final N node, final HyperplaneConvexSubset<P> partitioner) {
// in this case, we just create a new parent node with the partitioner as its
// cut and two copies of the original node as children
final N parent = createNode();
@@ -711,16 +709,17 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
return parent;
}
- /** Split the given internal node by a partitioning convex subhyperplane defined on the same region
+ /** Split the given internal node by a partitioning convex subset defined on the same region
* as the node and import it into this tree.
* @param node the internal node to split
- * @param partitioner partitioning convex subhyperplane
+ * @param partitioner partitioning convex subset
* @return node containing the split subtree
*/
- private N splitInternalNode(final N node, final ConvexSubHyperplane<P> partitioner) {
+ private N splitInternalNode(final N node, final HyperplaneConvexSubset<P> partitioner) {
// split the partitioner and node cut with each other's hyperplanes to determine their relative positions
- final Split<? extends ConvexSubHyperplane<P>> partitionerSplit = partitioner.split(node.getCutHyperplane());
- final Split<? extends ConvexSubHyperplane<P>> nodeCutSplit = node.getCut().split(partitioner.getHyperplane());
+ final Split<? extends HyperplaneConvexSubset<P>> partitionerSplit = partitioner.split(node.getCutHyperplane());
+ final Split<? extends HyperplaneConvexSubset<P>> nodeCutSplit =
+ node.getCut().split(partitioner.getHyperplane());
final SplitLocation partitionerSplitSide = partitionerSplit.getLocation();
final SplitLocation nodeCutSplitSide = nodeCutSplit.getLocation();
@@ -822,15 +821,15 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
/** The parent node; this will be null for the tree root node. */
private N parent;
- /** The subhyperplane cutting the node's region; this will be null for leaf nodes. */
- private ConvexSubHyperplane<P> cut;
+ /** The hyperplane convex subset cutting the node's region; this will be null for leaf nodes. */
+ private HyperplaneConvexSubset<P> cut;
- /** The node lying on the minus side of the cut subhyperplane; this will be null
+ /** The node lying on the minus side of the cut hyperplane; this will be null
* for leaf nodes.
*/
private N minus;
- /** The node lying on the plus side of the cut subhyperplane; this will be null
+ /** The node lying on the plus side of the cut hyperplane; this will be null
* for leaf nodes.
*/
private N plus;
@@ -961,7 +960,7 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
/** {@inheritDoc} */
@Override
- public ConvexSubHyperplane<P> getCut() {
+ public HyperplaneConvexSubset<P> getCut() {
return cut;
}
@@ -985,7 +984,7 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
/** {@inheritDoc} */
@Override
- public ConvexSubHyperplane<P> trim(final ConvexSubHyperplane<P> sub) {
+ public HyperplaneConvexSubset<P> trim(final HyperplaneConvexSubset<P> sub) {
return getTree().trimToNode(getSelf(), sub);
}
@@ -1005,14 +1004,14 @@ public abstract class AbstractBSPTree<P extends Point<P>, N extends AbstractBSPT
* all null (representing a leaf node) or all non-null (representing an internal node).
*
* <p>Absolutely no validation is performed on the arguments. Callers are responsible for
- * ensuring that any given subhyperplane fits the region defined by the node and that
+ * ensuring that any given hyperplane subset fits the region defined by the node and that
* any child nodes belong to this tree and are correctly initialized.</p>
*
- * @param newCut the new cut subhyperplane for the node
+ * @param newCut the new cut hyperplane subset for the node
* @param newMinus the new minus child for the node
* @param newPlus the new plus child for the node
*/
- protected void setSubtree(final ConvexSubHyperplane<P> newCut, final N newMinus, final N newPlus) {
+ protected void setSubtree(final HyperplaneConvexSubset<P> newCut, final N newMinus, final N newPlus) {
this.cut = newCut;
final N self = getSelf();
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTree.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTree.java
index 9a56876..1df224b 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTree.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTree.java
@@ -26,13 +26,13 @@ import org.apache.commons.geometry.core.Point;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.internal.IteratorTransform;
import org.apache.commons.geometry.core.partitioning.BoundarySource;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.partitioning.SplitLocation;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
import org.apache.commons.geometry.core.partitioning.bsp.BSPTreeVisitor.ClosestFirstVisitor;
/** Abstract {@link BSPTree} specialized for representing regions of space. For example,
@@ -146,75 +146,75 @@ public abstract class AbstractRegionBSPTree<
return boundarySize;
}
- /** Insert a subhyperplane into the tree, using the default {@link RegionCutRule} of
+ /** Insert a hyperplane subset into the tree, using the default {@link RegionCutRule} of
* {@link RegionCutRule#MINUS_INSIDE MINUS_INSIDE}.
- * @param sub the subhyperplane to insert into the tree
+ * @param sub the hyperplane subset to insert into the tree
*/
- public void insert(final SubHyperplane<P> sub) {
+ public void insert(final HyperplaneSubset<P> sub) {
insert(sub, DEFAULT_REGION_CUT_RULE);
}
- /** Insert a subhyperplane into the tree.
- * @param sub the subhyperplane to insert into the tree
+ /** Insert a hyperplane subset into the tree.
+ * @param sub the hyperplane subset to insert into the tree
* @param cutRule rule used to determine the region locations of new child nodes
*/
- public void insert(final SubHyperplane<P> sub, final RegionCutRule cutRule) {
+ public void insert(final HyperplaneSubset<P> sub, final RegionCutRule cutRule) {
insert(sub.toConvex(), cutRule);
}
- /** Insert a convex subhyperplane into the tree, using the default {@link RegionCutRule} of
+ /** Insert a hyperplane convex subset into the tree, using the default {@link RegionCutRule} of
* {@link RegionCutRule#MINUS_INSIDE MINUS_INSIDE}.
- * @param convexSub the convex subhyperplane to insert into the tree
+ * @param convexSub the hyperplane convex subset to insert into the tree
*/
- public void insert(final ConvexSubHyperplane<P> convexSub) {
+ public void insert(final HyperplaneConvexSubset<P> convexSub) {
insert(convexSub, DEFAULT_REGION_CUT_RULE);
}
- /** Insert a convex subhyperplane into the tree.
- * @param convexSub the convex subhyperplane to insert into the tree
+ /** Insert a hyperplane convex subset into the tree.
+ * @param convexSub the hyperplane convex subset to insert into the tree
* @param cutRule rule used to determine the region locations of new child nodes
*/
- public void insert(final ConvexSubHyperplane<P> convexSub, final RegionCutRule cutRule) {
+ public void insert(final HyperplaneConvexSubset<P> convexSub, final RegionCutRule cutRule) {
insert(convexSub, getSubtreeInitializer(cutRule));
}
- /** Insert a set of convex subhyperplanes into the tree, using the default {@link RegionCutRule} of
+ /** Insert a set of hyperplane convex subsets into the tree, using the default {@link RegionCutRule} of
* {@link RegionCutRule#MINUS_INSIDE MINUS_INSIDE}.
- * @param convexSubs iterable containing a collection of subhyperplanes
+ * @param convexSubs iterable containing a collection of hyperplane convex subsets
* to insert into the tree
*/
- public void insert(final Iterable<? extends ConvexSubHyperplane<P>> convexSubs) {
+ public void insert(final Iterable<? extends HyperplaneConvexSubset<P>> convexSubs) {
insert(convexSubs, DEFAULT_REGION_CUT_RULE);
}
- /** Insert a set of convex subhyperplanes into the tree.
- * @param convexSubs iterable containing a collection of subhyperplanes
+ /** Insert a set of hyperplane convex subsets into the tree.
+ * @param convexSubs iterable containing a collection of hyperplane convex subsets
* to insert into the tree
* @param cutRule rule used to determine the region locations of new child nodes
*/
- public void insert(final Iterable<? extends ConvexSubHyperplane<P>> convexSubs, final RegionCutRule cutRule) {
- for (final ConvexSubHyperplane<P> convexSub : convexSubs) {
+ public void insert(final Iterable<? extends HyperplaneConvexSubset<P>> convexSubs, final RegionCutRule cutRule) {
+ for (final HyperplaneConvexSubset<P> convexSub : convexSubs) {
insert(convexSub, cutRule);
}
}
- /** Insert all convex subhyperplanes from the given source into the tree, using the default
+ /** Insert all hyperplane convex subsets from the given source into the tree, using the default
* {@link RegionCutRule} of {@link RegionCutRule#MINUS_INSIDE MINUS_INSIDE}.
- * @param boundarySrc source of boundary convex subhyperplanes to insert
+ * @param boundarySrc source of boundary hyperplane subsets to insert
* into the tree
*/
- public void insert(final BoundarySource<? extends ConvexSubHyperplane<P>> boundarySrc) {
+ public void insert(final BoundarySource<? extends HyperplaneConvexSubset<P>> boundarySrc) {
insert(boundarySrc, DEFAULT_REGION_CUT_RULE);
}
- /** Insert all convex subhyperplanes from the given source into the tree.
- * @param boundarySrc source of boundary convex subhyperplanes to insert
+ /** Insert all hyperplane convex subsets from the given source into the tree.
+ * @param boundarySrc source of boundary hyperplane subsets to insert
* into the tree
* @param cutRule rule used to determine the region locations of new child nodes
*/
- public void insert(final BoundarySource<? extends ConvexSubHyperplane<P>> boundarySrc,
+ public void insert(final BoundarySource<? extends HyperplaneConvexSubset<P>> boundarySrc,
final RegionCutRule cutRule) {
- try (Stream<? extends ConvexSubHyperplane<P>> stream = boundarySrc.boundaryStream()) {
+ try (Stream<? extends HyperplaneConvexSubset<P>> stream = boundarySrc.boundaryStream()) {
stream.forEach(c -> insert(c, cutRule));
}
}
@@ -252,18 +252,18 @@ public abstract class AbstractRegionBSPTree<
* @return an {@link Iterable} for iterating over the boundaries of the region
* @see #getBoundaries()
*/
- public Iterable<? extends ConvexSubHyperplane<P>> boundaries() {
+ public Iterable<? extends HyperplaneConvexSubset<P>> boundaries() {
return createBoundaryIterable(Function.identity());
}
/** Internal method for creating the iterable instances used to iterate the region boundaries.
- * @param typeConverter function to convert the generic convex subhyperplane type into
+ * @param typeConverter function to convert the generic hyperplane subset type into
* the type specific for this tree
- * @param <C> ConvexSubhyperplane implementation type
+ * @param <C> HyperplaneConvexSubset implementation type
* @return an iterable to iterating the region boundaries
*/
- protected <C extends ConvexSubHyperplane<P>> Iterable<C> createBoundaryIterable(
- final Function<ConvexSubHyperplane<P>, C> typeConverter) {
+ protected <C extends HyperplaneConvexSubset<P>> Iterable<C> createBoundaryIterable(
+ final Function<HyperplaneConvexSubset<P>, C> typeConverter) {
return () -> new RegionBoundaryIterator<>(
getRoot().nodes().iterator(),
@@ -275,18 +275,18 @@ public abstract class AbstractRegionBSPTree<
* the boundaries is determined by the internal structure of the tree.
* @return a list of the boundaries of the region
*/
- public List<? extends ConvexSubHyperplane<P>> getBoundaries() {
+ public List<? extends HyperplaneConvexSubset<P>> getBoundaries() {
return createBoundaryList(Function.identity());
}
- /** Iternal method for creating a list of the region boundaries.
- * @param typeConverter function to convert the generic convex subhyperplane type into
+ /** Internal method for creating a list of the region boundaries.
+ * @param typeConverter function to convert the generic convex subset type into
* the type specific for this tree
- * @param <C> ConvexSubhyperplane implementation type
+ * @param <C> HyperplaneConvexSubset implementation type
* @return a list of the region boundaries
*/
- protected <C extends ConvexSubHyperplane<P>> List<C> createBoundaryList(
- final Function<ConvexSubHyperplane<P>, C> typeConverter) {
+ protected <C extends HyperplaneConvexSubset<P>> List<C> createBoundaryList(
+ final Function<HyperplaneConvexSubset<P>, C> typeConverter) {
final List<C> result = new ArrayList<>();
@@ -406,7 +406,7 @@ public abstract class AbstractRegionBSPTree<
}
/** Change this region into its complement. All inside nodes become outside
- * nodes and vice versa. The orientation of the cut subhyperplanes is not modified.
+ * nodes and vice versa. The orientations of the node cuts are not modified.
*/
public void complement() {
complementRecursive(getRoot());
@@ -546,7 +546,7 @@ public abstract class AbstractRegionBSPTree<
/** The location for the node. This will only be set on leaf nodes. */
private RegionLocation location;
- /** Object representing the part of the node cut subhyperplane that lies on the
+ /** Object representing the part of the node cut hyperplane subset that lies on the
* region boundary. This is calculated lazily and is only present on internal nodes.
*/
private RegionCutBoundary<P> cutBoundary;
@@ -625,7 +625,7 @@ public abstract class AbstractRegionBSPTree<
}
/** Insert a cut into this node. If the given hyperplane intersects
- * this node's region, then the node's cut is set to the {@link ConvexSubHyperplane}
+ * this node's region, then the node's cut is set to the {@link HyperplaneConvexSubset}
* representing the intersection, new plus and minus child leaf nodes
* are assigned, and true is returned. If the hyperplane does not intersect
* the node's region, then the node's cut and plus and minus child references
@@ -676,9 +676,8 @@ public abstract class AbstractRegionBSPTree<
return getSelf();
}
- /** Get the portion of the node's cut subhyperplane that lies on the boundary of the
- * region.
- * @return the portion of the node's cut subhyperplane that lies on the boundary of
+ /** Get the portion of the node's cut that lies on the boundary of the region.
+ * @return the portion of the node's cut that lies on the boundary of
* the region
*/
public RegionCutBoundary<P> getCutBoundary() {
@@ -693,34 +692,33 @@ public abstract class AbstractRegionBSPTree<
return cutBoundary;
}
- /** Compute the portion of the node's cut subhyperplane that lies on the boundary of
- * the region. This method must only be called on internal nodes.
- * @return object representing the portions of the node's cut subhyperplane that lie
- * on the region's boundary
+ /** Compute the portion of the node's cut that lies on the boundary of the region.
+ * This method must only be called on internal nodes.
+ * @return object representing the portions of the node's cut that lie on the region's boundary
*/
private RegionCutBoundary<P> computeBoundary() {
- ConvexSubHyperplane<P> sub = getCut();
+ HyperplaneConvexSubset<P> sub = getCut();
// find the portions of the node cut sub-hyperplane that touch inside and
// outside cells in the minus sub-tree
- SubHyperplane.Builder<P> minusInBuilder = sub.builder();
- SubHyperplane.Builder<P> minusOutBuilder = sub.builder();
+ HyperplaneSubset.Builder<P> minusInBuilder = sub.builder();
+ HyperplaneSubset.Builder<P> minusOutBuilder = sub.builder();
- characterizeSubHyperplane(sub, getMinus(), minusInBuilder, minusOutBuilder);
+ characterizeHyperplaneSubset(sub, getMinus(), minusInBuilder, minusOutBuilder);
- List<? extends ConvexSubHyperplane<P>> minusIn = minusInBuilder.build().toConvex();
- List<? extends ConvexSubHyperplane<P>> minusOut = minusOutBuilder.build().toConvex();
+ List<? extends HyperplaneConvexSubset<P>> minusIn = minusInBuilder.build().toConvex();
+ List<? extends HyperplaneConvexSubset<P>> minusOut = minusOutBuilder.build().toConvex();
// create the result boundary builders
- SubHyperplane.Builder<P> insideFacing = sub.builder();
- SubHyperplane.Builder<P> outsideFacing = sub.builder();
+ HyperplaneSubset.Builder<P> insideFacing = sub.builder();
+ HyperplaneSubset.Builder<P> outsideFacing = sub.builder();
if (!minusIn.isEmpty()) {
// Add to the boundary anything that touches an inside cell in the minus sub-tree
// and an outside cell in the plus sub-tree. These portions are oriented with their
// plus side pointing to the outside of the region.
- for (ConvexSubHyperplane<P> minusInFragment : minusIn) {
- characterizeSubHyperplane(minusInFragment, getPlus(), null, outsideFacing);
+ for (HyperplaneConvexSubset<P> minusInFragment : minusIn) {
+ characterizeHyperplaneSubset(minusInFragment, getPlus(), null, outsideFacing);
}
}
@@ -728,25 +726,26 @@ public abstract class AbstractRegionBSPTree<
// Add to the boundary anything that touches an outside cell in the minus sub-tree
// and an inside cell in the plus sub-tree. These portions are oriented with their
// plus side pointing to the inside of the region.
- for (ConvexSubHyperplane<P> minusOutFragment : minusOut) {
- characterizeSubHyperplane(minusOutFragment, getPlus(), insideFacing, null);
+ for (HyperplaneConvexSubset<P> minusOutFragment : minusOut) {
+ characterizeHyperplaneSubset(minusOutFragment, getPlus(), insideFacing, null);
}
}
return new RegionCutBoundary<>(insideFacing.build(), outsideFacing.build());
}
- /** Recursive method to characterize a convex subhyperplane with respect to the region's
+ /** Recursive method to characterize a hyperplane convex subset with respect to the region's
* boundaries.
- * @param sub the subhyperplane to characterize
- * @param node the node to characterize the subhyperplane against
- * @param in the builder that will receive the portions of the subhyperplane that lie in the inside
+ * @param sub the hyperplane convex subset to characterize
+ * @param node the node to characterize the hyperplane convex subset against
+ * @param in the builder that will receive the portions of the subset that lie in the inside
* of the region; may be null
- * @param out the builder that will receive the portions of the subhyperplane that lie on the outside
+ * @param out the builder that will receive the portions of the subset that lie on the outside
* of the region; may be null
*/
- private void characterizeSubHyperplane(final ConvexSubHyperplane<P> sub, final AbstractRegionNode<P, N> node,
- final SubHyperplane.Builder<P> in, final SubHyperplane.Builder<P> out) {
+ private void characterizeHyperplaneSubset(final HyperplaneConvexSubset<P> sub,
+ final AbstractRegionNode<P, N> node, final HyperplaneSubset.Builder<P> in,
+ final HyperplaneSubset.Builder<P> out) {
if (sub != null) {
if (node.isLeaf()) {
@@ -756,16 +755,16 @@ public abstract class AbstractRegionBSPTree<
out.add(sub);
}
} else {
- final Split<? extends ConvexSubHyperplane<P>> split = sub.split(node.getCutHyperplane());
+ final Split<? extends HyperplaneConvexSubset<P>> split = sub.split(node.getCutHyperplane());
- // Continue further on down the subtree with the same subhyperplane if the
- // subhyperplane lies directly on the current node's cut
+ // Continue further on down the subtree with the same subset if the
+ // subset lies directly on the current node's cut
if (split.getLocation() == SplitLocation.NEITHER) {
- characterizeSubHyperplane(sub, node.getPlus(), in, out);
- characterizeSubHyperplane(sub, node.getMinus(), in, out);
+ characterizeHyperplaneSubset(sub, node.getPlus(), in, out);
+ characterizeHyperplaneSubset(sub, node.getMinus(), in, out);
} else {
- characterizeSubHyperplane(split.getPlus(), node.getPlus(), in, out);
- characterizeSubHyperplane(split.getMinus(), node.getMinus(), in, out);
+ characterizeHyperplaneSubset(split.getPlus(), node.getPlus(), in, out);
+ characterizeHyperplaneSubset(split.getMinus(), node.getMinus(), in, out);
}
}
}
@@ -848,16 +847,16 @@ public abstract class AbstractRegionBSPTree<
return Result.CONTINUE;
}
- /** Return true if the given node cut subhyperplane is a possible candidate for containing the
- * closest region boundary point to the target.
- * @param cut the node cut subhyperplane to test
+ /** Return true if the given node cut is a possible candidate for containing the closest region
+ * boundary point to the target.
+ * @param cut the node cut to test
* @param target the target point being projected
* @param currentMinDist the smallest distance found so far to a region boundary; this value is guaranteed
* to be non-negative
- * @return true if the subhyperplane is a possible candidate for containing the closest region
+ * @return true if the cut is a possible candidate for containing the closest region
* boundary point to the target
*/
- protected boolean isPossibleClosestCut(final SubHyperplane<P> cut, final P target,
+ protected boolean isPossibleClosestCut(final HyperplaneSubset<P> cut, final P target,
final double currentMinDist) {
return Math.abs(cut.getHyperplane().offset(target)) <= currentMinDist;
}
@@ -1093,26 +1092,26 @@ public abstract class AbstractRegionBSPTree<
}
}
- /** Class that iterates over the boundary convex subhyperplanes from a set of region nodes.
+ /** Class that iterates over the boundary hyperplane convex subsets from a set of region nodes.
* @param <P> Point implementation type
- * @param <C> Boundary convex subhyperplane implementation type
+ * @param <C> Boundary hyperplane convex subset implementation type
* @param <N> BSP tree node implementation type
*/
private static final class RegionBoundaryIterator<
P extends Point<P>,
- C extends ConvexSubHyperplane<P>,
+ C extends HyperplaneConvexSubset<P>,
N extends AbstractRegionNode<P, N>>
extends IteratorTransform<N, C> {
- /** Function that converts from the convex subhyperplane type to the output type. */
- private final Function<ConvexSubHyperplane<P>, C> typeConverter;
+ /** Function that converts from the convex subset type to the output type. */
+ private final Function<HyperplaneConvexSubset<P>, C> typeConverter;
/** Simple constructor.
* @param inputIterator iterator that will provide all nodes in the tree
- * @param typeConverter function that converts from the convex subhyperplane type to the output type
+ * @param typeConverter function that converts from the convex subset type to the output type
*/
RegionBoundaryIterator(final Iterator<N> inputIterator,
- final Function<ConvexSubHyperplane<P>, C> typeConverter) {
+ final Function<HyperplaneConvexSubset<P>, C> typeConverter) {
super(inputIterator);
this.typeConverter = typeConverter;
@@ -1124,18 +1123,18 @@ public abstract class AbstractRegionBSPTree<
if (input.isInternal()) {
final RegionCutBoundary<P> cutBoundary = input.getCutBoundary();
- final SubHyperplane<P> outsideFacing = cutBoundary.getOutsideFacing();
- final SubHyperplane<P> insideFacing = cutBoundary.getInsideFacing();
+ final HyperplaneSubset<P> outsideFacing = cutBoundary.getOutsideFacing();
+ final HyperplaneSubset<P> insideFacing = cutBoundary.getInsideFacing();
if (outsideFacing != null && !outsideFacing.isEmpty()) {
- for (ConvexSubHyperplane<P> boundary : outsideFacing.toConvex()) {
+ for (HyperplaneConvexSubset<P> boundary : outsideFacing.toConvex()) {
addOutput(typeConverter.apply(boundary));
}
}
if (insideFacing != null && !insideFacing.isEmpty()) {
- for (ConvexSubHyperplane<P> boundary : insideFacing.toConvex()) {
- ConvexSubHyperplane<P> reversed = boundary.reverse();
+ for (HyperplaneConvexSubset<P> boundary : insideFacing.toConvex()) {
+ HyperplaneConvexSubset<P> reversed = boundary.reverse();
addOutput(typeConverter.apply(reversed));
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/BSPTree.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/BSPTree.java
index c359173..a94c4ca 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/BSPTree.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/BSPTree.java
@@ -18,7 +18,7 @@ package org.apache.commons.geometry.core.partitioning.bsp;
import org.apache.commons.geometry.core.Point;
import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
/** Interface for Binary Space Partitioning (BSP) trees. BSP trees are spatial data
@@ -42,7 +42,7 @@ public interface BSPTree<P extends Point<P>, N extends BSPTree.Node<P, N>>
extends BSPSubtree<P, N> {
/** Enum specifying possible behaviors when a point used to locate a node
- * falls directly on the cut subhyperplane of an internal node.
+ * falls directly on the cut of an internal node.
*/
enum FindNodeCutRule {
@@ -81,9 +81,9 @@ public interface BSPTree<P extends Point<P>, N extends BSPTree.Node<P, N>>
return findNode(pt, FindNodeCutRule.MINUS);
}
- /** Find a node in this subtree containing the given point on it interior or boundary. The
+ /** Find a node in this subtree containing the given point on its interior or boundary. The
* search should always return a leaf node except in the cases where the given point lies
- * exactly on the cut subhyperplane of an internal node. In this case, it is unclear whether
+ * exactly on the cut of an internal node. In this case, it is unclear whether
* the search should continue with the minus child, the plus child, or end with the internal
* node. The {@code cutRule} argument specifies what should happen in this case.
* <ul>
@@ -93,7 +93,7 @@ public interface BSPTree<P extends Point<P>, N extends BSPTree.Node<P, N>>
* </ul>
* @param pt test point used to locate a node in the tree
* @param cutRule value used to determine the search behavior when the test point lies
- * exactly on the cut subhyperplane of an internal node
+ * exactly on the cut of an internal node
* @return node containing the point on its interior or boundary
* @see #findNode(Point)
*/
@@ -110,7 +110,7 @@ public interface BSPTree<P extends Point<P>, N extends BSPTree.Node<P, N>>
*/
void extract(N node);
- /** Transform this tree. Each cut subhyperplane in the tree is transformed in place using
+ /** Transform this tree. Each cut in the tree is transformed in place using
* the given {@link Transform}.
* @param transform the transform to apply
*/
@@ -139,17 +139,18 @@ public interface BSPTree<P extends Point<P>, N extends BSPTree.Node<P, N>>
*/
N getParent();
- /** Get the cut for the node. This is a convex subhyperplane that splits
+ /** Get the cut for the node. This is a hyperplane convex subset that splits
* the region for the cell into two disjoint regions, namely the plus and
* minus regions. This will be null for leaf nodes.
* @see #getPlus()
* @see #getMinus()
- * @return the cut subhyperplane for the cell
+ * @return the cut for the cell
+ * @see #getCutHyperplane()
*/
- ConvexSubHyperplane<P> getCut();
+ HyperplaneConvexSubset<P> getCut();
- /** Get the hyperplane belonging to the node cut, if it exists.
- * @return the hyperplane belonging to the node cut, or null if
+ /** Get the hyperplane containing the node cut, if it exists.
+ * @return the hyperplane containing the node cut, or null if
* the node does not have a cut
* @see #getCut()
*/
@@ -191,14 +192,14 @@ public interface BSPTree<P extends Point<P>, N extends BSPTree.Node<P, N>>
*/
boolean isPlus();
- /** Trim the given subhyperplane to the region defined by this node by cutting
+ /** Trim the given hyperplane subset to the region defined by this node by cutting
* the argument with the cut hyperplanes (binary partitioners) of all parent nodes
- * up to the root. Null is returned if the subhyperplane lies outside of the region
+ * up to the root. Null is returned if the hyperplane subset lies outside of the region
* defined by the node.
- * @param sub the convex subhyperplane to trim
- * @return the trimmed convex subhyperplane or null if no part of the argument lies
+ * @param sub the hyperplane subset to trim
+ * @return the trimmed hyperplane subset or null if no part of the argument lies
* within the node's region
*/
- ConvexSubHyperplane<P> trim(ConvexSubHyperplane<P> sub);
+ HyperplaneConvexSubset<P> trim(HyperplaneConvexSubset<P> sub);
}
}
diff --git a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundary.java b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundary.java
index 3469afa..2a7fb84 100644
--- a/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundary.java
+++ b/commons-geometry-core/src/main/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundary.java
@@ -17,55 +17,51 @@
package org.apache.commons.geometry.core.partitioning.bsp;
import org.apache.commons.geometry.core.Point;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
/** Class representing the portion of an
- * {@link AbstractRegionBSPTree.AbstractRegionNode AbstractRegionNode}'s cut subhyperplane that
- * lies on the boundary of the region. Portions of this subhyperplane
- * may be oriented so that the plus side of the subhyperplane points toward
+ * {@link AbstractRegionBSPTree.AbstractRegionNode AbstractRegionNode}'s cut that
+ * lies on the boundary of the region. Portions of this hyperplane subset
+ * may be oriented so that the plus side of the hyperplane subset points toward
* the outside of the region ({@link #getOutsideFacing()}) and other portions
- * of the same subhyperplane may be oriented so that the plus side points
+ * of the same hyperplane subset may be oriented so that the plus side points
* toward the inside of the region ({@link #getInsideFacing()}).
*
* @param <P> Point implementation type
*/
public final class RegionCutBoundary<P extends Point<P>> {
- /** Portion of the region cut subhyperplane with its plus side facing the
- * inside of the region.
+ /** Portion of the cut with its plus side facing the inside of the region.
*/
- private final SubHyperplane<P> insideFacing;
+ private final HyperplaneSubset<P> insideFacing;
- /** Portion of the region cut subhyperplane with its plus side facing the
- * outside of the region.
+ /** Portion of the cut with its plus side facing the outside of the region.
*/
- private final SubHyperplane<P> outsideFacing;
+ private final HyperplaneSubset<P> outsideFacing;
/** Simple constructor.
- * @param insideFacing portion of the region cut subhyperplane with its plus side facing the
+ * @param insideFacing portion of the cut with its plus side facing the
* inside of the region
- * @param outsideFacing portion of the region cut subhyperplane with its plus side facing the
+ * @param outsideFacing portion of the cut with its plus side facing the
* outside of the region
*/
- public RegionCutBoundary(final SubHyperplane<P> insideFacing, final SubHyperplane<P> outsideFacing) {
+ public RegionCutBoundary(final HyperplaneSubset<P> insideFacing, final HyperplaneSubset<P> outsideFacing) {
this.insideFacing = insideFacing;
this.outsideFacing = outsideFacing;
}
- /** Get the portion of the region cut subhyperplane with its plus side facing the
- * inside of the region.
- * @return the portion of the region cut subhyperplane with its plus side facing the
+ /** Get the portion of the cut with its plus side facing the inside of the region.
+ * @return the portion of the cut with its plus side facing the
* inside of the region
*/
- public SubHyperplane<P> getInsideFacing() {
+ public HyperplaneSubset<P> getInsideFacing() {
return insideFacing;
}
- /** Get the portion of the region cut subhyperplane with its plus side facing the
- * outside of the region.
- * @return the portion of the region cut subhyperplane with its plus side facing the
+ /** Get the portion of the cut with its plus side facing the outside of the region.
+ * @return the portion of the cut with its plus side facing the
* outside of the region
*/
- public SubHyperplane<P> getOutsideFacing() {
+ public HyperplaneSubset<P> getOutsideFacing() {
return outsideFacing;
}
@@ -73,7 +69,7 @@ public final class RegionCutBoundary<P extends Point<P>> {
* portions of the cut boundary.
* @param pt the reference point
* @return the point in the cut boundary closest to the reference point
- * @see SubHyperplane#closest(Point)
+ * @see HyperplaneSubset#closest(Point)
*/
public P closest(final P pt) {
final P insideFacingPt = (insideFacing != null) ? insideFacing.closest(pt) : null;
@@ -94,7 +90,7 @@ public final class RegionCutBoundary<P extends Point<P>> {
* inside facing portion or the outside facing portion.
* @param pt point to test
* @return true if the point is contained in the boundary
- * @see SubHyperplane#contains(Point)
+ * @see HyperplaneSubset#contains(Point)
*/
public boolean contains(final P pt) {
return (insideFacing != null && insideFacing.contains(pt)) ||
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/RegionEmbeddingTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/RegionEmbeddingTest.java
new file mode 100644
index 0000000..667bea3
--- /dev/null
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/RegionEmbeddingTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.commons.geometry.core;
+
+import org.apache.commons.geometry.core.partition.test.TestPoint1D;
+import org.apache.commons.geometry.core.partition.test.TestPoint2D;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RegionEmbeddingTest {
+
+ private static final double TEST_EPS = 1e-10;
+
+ @Test
+ public void testGetSize() {
+ // arrange
+ StubRegionEmbedding finite = new StubRegionEmbedding(2.0);
+ StubRegionEmbedding infinite = new StubRegionEmbedding(Double.POSITIVE_INFINITY);
+ StubRegionEmbedding nan = new StubRegionEmbedding(Double.NaN);
+
+ // act/assert
+ Assert.assertEquals(2.0, finite.getSize(), TEST_EPS);
+ Assert.assertTrue(finite.isFinite());
+ Assert.assertFalse(finite.isInfinite());
+
+ GeometryTestUtils.assertPositiveInfinity(infinite.getSize());
+ Assert.assertFalse(infinite.isFinite());
+ Assert.assertTrue(infinite.isInfinite());
+
+ Assert.assertTrue(Double.isNaN(nan.getSize()));
+ Assert.assertFalse(nan.isFinite());
+ Assert.assertFalse(nan.isInfinite());
+ }
+
+ private static class StubRegionEmbedding implements RegionEmbedding<TestPoint2D, TestPoint1D> {
+
+ private final StubRegion1D subspaceRegion;
+
+ StubRegionEmbedding(final double size) {
+ subspaceRegion = new StubRegion1D(size);
+ }
+
+ @Override
+ public TestPoint1D toSubspace(TestPoint2D pt) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TestPoint2D toSpace(TestPoint1D pt) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Region<TestPoint1D> getSubspaceRegion() {
+ return subspaceRegion;
+ }
+ }
+
+ private static class StubRegion1D implements Region<TestPoint1D> {
+
+ private final double size;
+
+ StubRegion1D(final double size) {
+ this.size = size;
+ }
+
+ @Override
+ public double getSize() {
+ return size;
+ }
+
+ @Override
+ public boolean isFull() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getBoundarySize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TestPoint1D getBarycenter() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RegionLocation classify(TestPoint1D pt) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TestPoint1D project(TestPoint1D pt) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/SizedTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/SizedTest.java
new file mode 100644
index 0000000..d1a0128
--- /dev/null
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/SizedTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.commons.geometry.core;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SizedTest {
+
+ @Test
+ public void testProperties() {
+ // arrange
+ Sized finite = new StubSized(1);
+ Sized infinite = new StubSized(Double.POSITIVE_INFINITY);
+ Sized nan = new StubSized(Double.NaN);
+
+ // act/assert
+ Assert.assertTrue(finite.isFinite());
+ Assert.assertFalse(finite.isInfinite());
+
+ Assert.assertFalse(infinite.isFinite());
+ Assert.assertTrue(infinite.isInfinite());
+
+ Assert.assertFalse(nan.isFinite());
+ Assert.assertFalse(nan.isInfinite());
+ }
+
+ private static class StubSized implements Sized {
+
+ private final double size;
+
+ StubSized(final double size) {
+ this.size = size;
+ }
+
+ @Override
+ public double getSize() {
+ return size;
+ }
+ }
+}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestBSPTree.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestBSPTree.java
index 65cdf29..f976fd1 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestBSPTree.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestBSPTree.java
@@ -17,9 +17,9 @@
package org.apache.commons.geometry.core.partition.test;
import org.apache.commons.geometry.core.partitioning.BoundarySource;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
import org.apache.commons.geometry.core.partitioning.bsp.AbstractBSPTree;
/** BSP Tree implementation class for testing purposes.
@@ -32,15 +32,15 @@ public class TestBSPTree extends AbstractBSPTree<TestPoint2D, TestBSPTree.TestNo
return new TestNode(this);
}
- public void insert(final SubHyperplane<TestPoint2D> sub) {
+ public void insert(final HyperplaneSubset<TestPoint2D> sub) {
insert(sub.toConvex());
}
- public void insert(final ConvexSubHyperplane<TestPoint2D> sub) {
+ public void insert(final HyperplaneConvexSubset<TestPoint2D> sub) {
insert(sub, root -> { });
}
- public void insert(final Iterable<? extends ConvexSubHyperplane<TestPoint2D>> subs) {
+ public void insert(final Iterable<? extends HyperplaneConvexSubset<TestPoint2D>> subs) {
subs.forEach(this::insert);
}
@@ -60,6 +60,11 @@ public class TestBSPTree extends AbstractBSPTree<TestPoint2D, TestBSPTree.TestNo
super.splitIntoTrees(splitter, minus, plus);
}
+ @Override
+ protected void copyNodeProperties(final TestNode src, final TestNode dst) {
+ // do nothing
+ }
+
/** BSP Tree node class for {@link TestBSPTree}.
*/
public static class TestNode extends AbstractBSPTree.AbstractNode<TestPoint2D, TestNode> {
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegment.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegment.java
index 011e010..896b286 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegment.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegment.java
@@ -21,15 +21,15 @@ import java.util.List;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.Split;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
/** Class representing a line segment in two dimensional Euclidean space. This
* class should only be used for testing purposes.
*/
-public class TestLineSegment implements ConvexSubHyperplane<TestPoint2D> {
+public class TestLineSegment implements HyperplaneConvexSubset<TestPoint2D> {
/** Abscissa of the line segment start point. */
private final double start;
@@ -169,7 +169,7 @@ public class TestLineSegment implements ConvexSubHyperplane<TestPoint2D> {
/** {@inheritDoc} */
@Override
- public List<ConvexSubHyperplane<TestPoint2D>> toConvex() {
+ public List<HyperplaneConvexSubset<TestPoint2D>> toConvex() {
return Arrays.asList(this);
}
@@ -193,13 +193,13 @@ public class TestLineSegment implements ConvexSubHyperplane<TestPoint2D> {
/** {@inheritDoc} */
@Override
- public SubHyperplane.Builder<TestPoint2D> builder() {
+ public HyperplaneSubset.Builder<TestPoint2D> builder() {
return new TestLineSegmentCollectionBuilder(line);
}
/** {@inheritDoc} */
@Override
- public ConvexSubHyperplane<TestPoint2D> transform(Transform<TestPoint2D> transform) {
+ public HyperplaneConvexSubset<TestPoint2D> transform(Transform<TestPoint2D> transform) {
if (!isInfinite()) {
// simple case; just transform the points directly
TestPoint2D p1 = transform.apply(getStartPoint());
@@ -239,7 +239,7 @@ public class TestLineSegment implements ConvexSubHyperplane<TestPoint2D> {
/** Method used to split the instance with the given line when the instance has
* infinite size.
* @param splitter the splitter line
- * @return the split convex subhyperplane
+ * @return the split convex subset
*/
private Split<TestLineSegment> splitInfinite(TestLine splitter) {
final TestPoint2D intersection = splitter.intersection(line);
@@ -282,7 +282,7 @@ public class TestLineSegment implements ConvexSubHyperplane<TestPoint2D> {
/** Method used to split the instance with the given line when the instance has
* finite size.
* @param splitter the splitter line
- * @return the split convex subhyperplane
+ * @return the split convex subset
*/
private Split<TestLineSegment> splitFinite(TestLine splitter) {
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollection.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollection.java
index 1c9b60e..a036d9d 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollection.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollection.java
@@ -22,16 +22,16 @@ import java.util.List;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.Split;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
/** Class containing a collection line segments. This class should only be used for
* testing purposes.
*/
-public class TestLineSegmentCollection implements SubHyperplane<TestPoint2D> {
- /** The collection of line-segments making up the subhyperplane.
+public class TestLineSegmentCollection implements HyperplaneSubset<TestPoint2D> {
+ /** The collection of line-segments making up the subset.
*/
private final List<TestLineSegment> segments;
@@ -174,19 +174,19 @@ public class TestLineSegmentCollection implements SubHyperplane<TestPoint2D> {
/** {@inheritDoc} */
@Override
- public List<ConvexSubHyperplane<TestPoint2D>> toConvex() {
+ public List<HyperplaneConvexSubset<TestPoint2D>> toConvex() {
return new ArrayList<>(segments);
}
/** {@inheritDoc} */
@Override
- public SubHyperplane<TestPoint2D> transform(Transform<TestPoint2D> transform) {
+ public HyperplaneSubset<TestPoint2D> transform(Transform<TestPoint2D> transform) {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override
- public SubHyperplane.Builder<TestPoint2D> builder() {
+ public HyperplaneSubset.Builder<TestPoint2D> builder() {
return new TestLineSegmentCollectionBuilder(segments.get(0).getHyperplane());
}
}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollectionBuilder.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollectionBuilder.java
index 4deeb2a..7589574 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollectionBuilder.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestLineSegmentCollectionBuilder.java
@@ -20,10 +20,10 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
-public class TestLineSegmentCollectionBuilder implements SubHyperplane.Builder<TestPoint2D> {
+public class TestLineSegmentCollectionBuilder implements HyperplaneSubset.Builder<TestPoint2D> {
private final TestLine line;
@@ -35,22 +35,22 @@ public class TestLineSegmentCollectionBuilder implements SubHyperplane.Builder<T
/** {@inheritDoc} */
@Override
- public void add(SubHyperplane<TestPoint2D> sub) {
- for (ConvexSubHyperplane<TestPoint2D> convex : sub.toConvex()) {
+ public void add(HyperplaneSubset<TestPoint2D> sub) {
+ for (HyperplaneConvexSubset<TestPoint2D> convex : sub.toConvex()) {
add(convex);
}
}
/** {@inheritDoc} */
@Override
- public void add(ConvexSubHyperplane<TestPoint2D> convex) {
+ public void add(HyperplaneConvexSubset<TestPoint2D> convex) {
TestLineSegment seg = (TestLineSegment) convex;
addSegment(seg.getStart(), seg.getEnd());
}
/** {@inheritDoc} */
@Override
- public SubHyperplane<TestPoint2D> build() {
+ public HyperplaneSubset<TestPoint2D> build() {
List<TestLineSegment> segments = new ArrayList<>();
for (SegmentInterval interval : intervals) {
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestRegionBSPTree.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestRegionBSPTree.java
index d4cbf5c..5b46c41 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestRegionBSPTree.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partition/test/TestRegionBSPTree.java
@@ -17,7 +17,7 @@
package org.apache.commons.geometry.core.partition.test;
import org.apache.commons.geometry.core.RegionLocation;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.partitioning.bsp.AbstractBSPTree;
@@ -39,7 +39,7 @@ public final class TestRegionBSPTree extends AbstractRegionBSPTree<TestPoint2D,
/**
* Expose the direct node cut method for easier creation of test tree structures.
*/
- public void cutNode(final TestRegionNode node, final ConvexSubHyperplane<TestPoint2D> cut) {
+ public void cutNode(final TestRegionNode node, final HyperplaneConvexSubset<TestPoint2D> cut) {
super.setNodeCut(node, cut, getSubtreeInitializer(RegionCutRule.MINUS_INSIDE));
}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegionTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegionTest.java
index bd73f02..ccebc49 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegionTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractConvexHyperplaneBoundedRegionTest.java
@@ -579,8 +579,8 @@ public class AbstractConvexHyperplaneBoundedRegionTest {
}
@Override
- public TestLineSegment trim(ConvexSubHyperplane<TestPoint2D> convexSubHyperplane) {
- return (TestLineSegment) super.trim(convexSubHyperplane);
+ public TestLineSegment trim(HyperplaneConvexSubset<TestPoint2D> subset) {
+ return (TestLineSegment) super.trim(subset);
}
@Override
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractHyperplaneTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractHyperplaneTest.java
index 98fe31f..9b41cf0 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractHyperplaneTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractHyperplaneTest.java
@@ -100,7 +100,7 @@ public class AbstractHyperplaneTest {
}
@Override
- public ConvexSubHyperplane<TestPoint2D> span() {
+ public HyperplaneConvexSubset<TestPoint2D> span() {
return null;
}
}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractEmbeddingSubHyperplaneTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractRegionEmbeddingHyperplaneSubsetTest.java
similarity index 80%
rename from commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractEmbeddingSubHyperplaneTest.java
rename to commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractRegionEmbeddingHyperplaneSubsetTest.java
index d91f2f8..4dc0863 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractEmbeddingSubHyperplaneTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/AbstractRegionEmbeddingHyperplaneSubsetTest.java
@@ -27,12 +27,12 @@ import org.apache.commons.geometry.core.partition.test.TestPoint2D;
import org.junit.Assert;
import org.junit.Test;
-public class AbstractEmbeddingSubHyperplaneTest {
+public class AbstractRegionEmbeddingHyperplaneSubsetTest {
@Test
public void testSimpleProperties() {
// arrange
- StubSubHyperplane sub = new StubSubHyperplane(1.0);
+ StubHyperplaneSubset sub = new StubHyperplaneSubset(1.0);
// act/assert
Assert.assertTrue(sub.isFull());
@@ -46,9 +46,9 @@ public class AbstractEmbeddingSubHyperplaneTest {
@Test
public void testFiniteAndInfinite() {
// arrange
- StubSubHyperplane finite = new StubSubHyperplane(1.0);
- StubSubHyperplane inf = new StubSubHyperplane(Double.POSITIVE_INFINITY);
- StubSubHyperplane nan = new StubSubHyperplane(Double.NaN);
+ StubHyperplaneSubset finite = new StubHyperplaneSubset(1.0);
+ StubHyperplaneSubset inf = new StubHyperplaneSubset(Double.POSITIVE_INFINITY);
+ StubHyperplaneSubset nan = new StubHyperplaneSubset(Double.NaN);
// act/assert
Assert.assertTrue(finite.isFinite());
@@ -62,9 +62,19 @@ public class AbstractEmbeddingSubHyperplaneTest {
}
@Test
+ public void testSpaceConversions() {
+ // arrange
+ StubHyperplaneSubset sub = new StubHyperplaneSubset();
+
+ // act/assert
+ Assert.assertEquals(2.0, sub.toSubspace(new TestPoint2D(2.0, 3.0)).getX(), PartitionTestUtils.EPS);
+ PartitionTestUtils.assertPointsEqual(new TestPoint2D(2.0, 0.0), sub.toSpace(new TestPoint1D(2.0)));
+ }
+
+ @Test
public void testClassify() {
// arrange
- StubSubHyperplane sub = new StubSubHyperplane();
+ StubHyperplaneSubset sub = new StubHyperplaneSubset();
// act/assert
Assert.assertEquals(RegionLocation.INSIDE, sub.classify(new TestPoint2D(-1, 0)));
@@ -78,7 +88,7 @@ public class AbstractEmbeddingSubHyperplaneTest {
@Test
public void testClosest() {
// arrange
- StubSubHyperplane sub = new StubSubHyperplane();
+ StubHyperplaneSubset sub = new StubHyperplaneSubset();
// act/assert
PartitionTestUtils.assertPointsEqual(new TestPoint2D(-1, 0), sub.closest(new TestPoint2D(-1, 0)));
@@ -95,22 +105,23 @@ public class AbstractEmbeddingSubHyperplaneTest {
@Test
public void testClosest_nullSubspaceRegionProjection() {
// arrange
- StubSubHyperplane sub = new StubSubHyperplane();
+ StubHyperplaneSubset sub = new StubHyperplaneSubset();
sub.region.projected = null;
// act/assert
Assert.assertNull(sub.closest(new TestPoint2D(1, 1)));
}
- private static class StubSubHyperplane extends AbstractEmbeddingSubHyperplane<TestPoint2D, TestPoint1D, TestLine> {
+ private static class StubHyperplaneSubset
+ extends AbstractRegionEmbeddingHyperplaneSubset<TestPoint2D, TestPoint1D, TestLine> {
private final StubRegion1D region;
- StubSubHyperplane() {
+ StubHyperplaneSubset() {
this(0);
}
- StubSubHyperplane(final double size) {
+ StubHyperplaneSubset(final double size) {
this.region = new StubRegion1D(size);
}
@@ -120,7 +131,7 @@ public class AbstractEmbeddingSubHyperplaneTest {
}
@Override
- public List<? extends ConvexSubHyperplane<TestPoint2D>> toConvex() {
+ public List<? extends HyperplaneConvexSubset<TestPoint2D>> toConvex() {
return null;
}
@@ -135,12 +146,12 @@ public class AbstractEmbeddingSubHyperplaneTest {
}
@Override
- public Split<StubSubHyperplane> split(Hyperplane<TestPoint2D> splitter) {
+ public Split<StubHyperplaneSubset> split(Hyperplane<TestPoint2D> splitter) {
return null;
}
@Override
- public SubHyperplane<TestPoint2D> transform(Transform<TestPoint2D> transform) {
+ public HyperplaneSubset<TestPoint2D> transform(Transform<TestPoint2D> transform) {
return null;
}
}
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTreeTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTreeTest.java
index 8885be3..a79cab1 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTreeTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractBSPTreeTest.java
@@ -675,7 +675,7 @@ public class AbstractBSPTreeTest {
}
@Test
- public void testInsert_subhyperplane_concaveRegion() {
+ public void testInsert_hyperplaneSubset_concaveRegion() {
// arrange
TestBSPTree tree = new TestBSPTree();
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTreeTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTreeTest.java
index 0dbd048..3bbf64f 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTreeTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/AbstractRegionBSPTreeTest.java
@@ -34,10 +34,10 @@ import org.apache.commons.geometry.core.partition.test.TestRegionBSPTree;
import org.apache.commons.geometry.core.partition.test.TestRegionBSPTree.TestRegionNode;
import org.apache.commons.geometry.core.partition.test.TestTransform2D;
import org.apache.commons.geometry.core.partitioning.BoundarySource;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.partitioning.SplitLocation;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
import org.apache.commons.geometry.core.partitioning.bsp.AbstractRegionBSPTree.RegionSizeProperties;
import org.junit.Assert;
import org.junit.Before;
@@ -109,7 +109,7 @@ public class AbstractRegionBSPTreeTest {
}
@Test
- public void testInsert_subhyperplanes_mixedCutRules() {
+ public void testInsert_hyperplaneSubsets_mixedCutRules() {
// act/assert
checkMixedCutRuleInsertion(segs -> {
tree.insert(new TestLineSegmentCollection(Arrays.asList(segs[0])), RegionCutRule.PLUS_INSIDE);
@@ -122,7 +122,7 @@ public class AbstractRegionBSPTreeTest {
}
@Test
- public void testInsert_convexSubhyperplanes_mixedCutRules() {
+ public void testInsert_hyperplaneConvexSubsets_mixedCutRules() {
// act/assert
checkMixedCutRuleInsertion(segs -> {
tree.insert(segs[0], RegionCutRule.PLUS_INSIDE);
@@ -134,7 +134,7 @@ public class AbstractRegionBSPTreeTest {
}
@Test
- public void testInsert_convexSubhyperplaneList_mixedCutRules() {
+ public void testInsert_hyperplaneConvexSubsetList_mixedCutRules() {
// act/assert
checkMixedCutRuleInsertion(segs -> {
tree.insert(Arrays.asList(segs[0]), RegionCutRule.PLUS_INSIDE);
@@ -162,7 +162,7 @@ public class AbstractRegionBSPTreeTest {
});
}
- /** Helper function to check the insertion of subhyperplanes using different region cut rules.
+ /** Helper function to check the insertion of hyperplane subsets using different region cut rules.
* @param fn
*/
private void checkMixedCutRuleInsertion(Consumer<TestLineSegment[]> fn) {
@@ -440,7 +440,7 @@ public class AbstractRegionBSPTreeTest {
// act
List<TestLineSegment> segments = new ArrayList<>();
- for (ConvexSubHyperplane<TestPoint2D> sub : tree.boundaries()) {
+ for (HyperplaneConvexSubset<TestPoint2D> sub : tree.boundaries()) {
segments.add((TestLineSegment) sub);
}
@@ -461,7 +461,7 @@ public class AbstractRegionBSPTreeTest {
// act
List<TestLineSegment> segments = new ArrayList<>();
- for (ConvexSubHyperplane<TestPoint2D> sub : tree.boundaries()) {
+ for (HyperplaneConvexSubset<TestPoint2D> sub : tree.boundaries()) {
segments.add((TestLineSegment) sub);
}
@@ -491,7 +491,7 @@ public class AbstractRegionBSPTreeTest {
// act
List<TestLineSegment> segments = new ArrayList<>();
- for (ConvexSubHyperplane<TestPoint2D> sub : tree.getBoundaries()) {
+ for (HyperplaneConvexSubset<TestPoint2D> sub : tree.getBoundaries()) {
segments.add((TestLineSegment) sub);
}
@@ -512,7 +512,7 @@ public class AbstractRegionBSPTreeTest {
// act
List<TestLineSegment> segments = new ArrayList<>();
- for (ConvexSubHyperplane<TestPoint2D> sub : tree.getBoundaries()) {
+ for (HyperplaneConvexSubset<TestPoint2D> sub : tree.getBoundaries()) {
segments.add((TestLineSegment) sub);
}
@@ -1552,7 +1552,7 @@ public class AbstractRegionBSPTreeTest {
new TestLineSegment(new TestPoint2D(-4, -5), new TestPoint2D(1, 0))));
}
- private static void assertCutBoundarySegment(final SubHyperplane<TestPoint2D> boundary, final TestPoint2D start,
+ private static void assertCutBoundarySegment(final HyperplaneSubset<TestPoint2D> boundary, final TestPoint2D start,
final TestPoint2D end) {
Assert.assertFalse("Expected boundary to not be empty", boundary.isEmpty());
diff --git a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundaryTest.java b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundaryTest.java
index 45fee2c..5b305ce 100644
--- a/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundaryTest.java
+++ b/commons-geometry-core/src/test/java/org/apache/commons/geometry/core/partitioning/bsp/RegionCutBoundaryTest.java
@@ -133,7 +133,7 @@ public class RegionCutBoundaryTest {
}
@Test
- public void testContains_nullSubHyperplanes() {
+ public void testContains_nullHyperplaneSubsets() {
// arrange
RegionCutBoundary<TestPoint2D> boundary = new RegionCutBoundary<>(null, null);
diff --git a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java
index 0aab6d3..246a579 100644
--- a/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java
+++ b/commons-geometry-enclosing/src/main/java/org/apache/commons/geometry/enclosing/euclidean/threed/SphereGenerator.java
@@ -25,6 +25,7 @@ import org.apache.commons.geometry.enclosing.EnclosingBall;
import org.apache.commons.geometry.enclosing.SupportBallGenerator;
import org.apache.commons.geometry.enclosing.euclidean.twod.DiskGenerator;
import org.apache.commons.geometry.euclidean.threed.Plane;
+import org.apache.commons.geometry.euclidean.threed.Planes;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
import org.apache.commons.numbers.fraction.BigFraction;
@@ -61,7 +62,7 @@ public class SphereGenerator implements SupportBallGenerator<Vector3D> {
}
final Vector3D vC = support.get(2);
if (support.size() < 4) {
- final Plane p = Plane.fromPoints(vA, vB, vC, precision);
+ final Plane p = Planes.fromPoints(vA, vB, vC, precision);
final EnclosingBall<Vector2D> disk =
new DiskGenerator().ballOnSupport(Arrays.asList(p.toSubspace(vA),
p.toSubspace(vB),
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/AbstractPathConnector.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/AbstractPathConnector.java
index fee4343..2fbe770 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/AbstractPathConnector.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/internal/AbstractPathConnector.java
@@ -95,14 +95,14 @@ public abstract class AbstractPathConnector<E extends AbstractPathConnector.Conn
* @return a list of root elements for the computed connected paths
*/
protected List<E> computePathRoots() {
- for (final E segment : pathElements) {
- followForwardConnections(segment);
+ for (final E element : pathElements) {
+ followForwardConnections(element);
}
final List<E> rootEntries = new ArrayList<>();
E root;
- for (final E segment : pathElements) {
- root = segment.exportPath();
+ for (final E element : pathElements) {
+ root = element.exportPath();
if (root != null) {
rootEntries.add(root);
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Interval.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Interval.java
index 9d3470e..57a2dd6 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Interval.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/Interval.java
@@ -117,6 +117,7 @@ public final class Interval implements HyperplaneBoundedRegion<Vector1D> {
* does not exist.
* @return true if the region is infinite
*/
+ @Override
public boolean isInfinite() {
return minBoundary == null || maxBoundary == null;
}
@@ -125,6 +126,7 @@ public final class Interval implements HyperplaneBoundedRegion<Vector1D> {
* boundaries exist and the region size is finite.
* @return true if the region is finite
*/
+ @Override
public boolean isFinite() {
return !isInfinite();
}
@@ -312,9 +314,9 @@ public final class Interval implements HyperplaneBoundedRegion<Vector1D> {
low = this;
} else {
// the interval is split in two
- low = new Interval(minBoundary, OrientedPoint.createPositiveFacing(
+ low = new Interval(minBoundary, OrientedPoints.createPositiveFacing(
splitPoint, splitOrientedPoint.getPrecision()));
- high = new Interval(OrientedPoint.createNegativeFacing(
+ high = new Interval(OrientedPoints.createNegativeFacing(
splitPoint, splitOrientedPoint.getPrecision()), maxBoundary);
}
}
@@ -365,11 +367,11 @@ public final class Interval implements HyperplaneBoundedRegion<Vector1D> {
final double max = Math.max(a, b);
final OrientedPoint minBoundary = Double.isFinite(min) ?
- OrientedPoint.fromLocationAndDirection(min, false, precision) :
+ OrientedPoints.fromLocationAndDirection(min, false, precision) :
null;
final OrientedPoint maxBoundary = Double.isFinite(max) ?
- OrientedPoint.fromLocationAndDirection(max, true, precision) :
+ OrientedPoints.fromLocationAndDirection(max, true, precision) :
null;
if (minBoundary == null && maxBoundary == null) {
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java
index 704c0ab..0463139 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoint.java
@@ -16,18 +16,18 @@
*/
package org.apache.commons.geometry.euclidean.oned;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.partitioning.AbstractHyperplane;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.HyperplaneLocation;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
import org.apache.commons.geometry.core.partitioning.Split;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
/** This class represents a 1D oriented hyperplane.
@@ -36,6 +36,7 @@ import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
* boolean indicating if the direction is positive or negative.</p>
*
* <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see OrientedPoints
*/
public final class OrientedPoint extends AbstractHyperplane<Vector1D>
implements Hyperplane<Vector1D> {
@@ -51,7 +52,7 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
* otherwise, it will point toward negative infinity.
* @param precision precision context used to compare floating point values
*/
- private OrientedPoint(final Vector1D point, final boolean positiveFacing, final DoublePrecisionContext precision) {
+ OrientedPoint(final Vector1D point, final boolean positiveFacing, final DoublePrecisionContext precision) {
super(precision);
this.point = point;
@@ -116,7 +117,7 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
transformedDir = transformedPoint.vectorTo(transformedPointPlusDir);
}
- return OrientedPoint.fromPointAndDirection(
+ return OrientedPoints.fromPointAndDirection(
transformedPoint,
transformedDir,
getPrecision()
@@ -177,10 +178,15 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
return this.point;
}
- /** {@inheritDoc} */
+ /** {@inheritDoc}
+ *
+ * <p>Since there are no subspaces in 1D, this method effectively returns a stub implementation of
+ * {@link HyperplaneConvexSubset}, the main purpose of which is to support the proper functioning
+ * of the partitioning code.</p>
+ */
@Override
- public SubOrientedPoint span() {
- return new SubOrientedPoint(this);
+ public HyperplaneConvexSubset<Vector1D> span() {
+ return new OrientedPointConvexSubset(this);
}
/** Return true if this instance should be considered equivalent to the argument, using the
@@ -243,97 +249,18 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
return sb.toString();
}
- /** Create a new instance from the given location and boolean direction value.
- * @param location the location of the hyperplane
- * @param positiveFacing if true, the hyperplane will face toward positive infinity;
- * otherwise, it will point toward negative infinity.
- * @param precision precision context used to compare floating point values
- * @return a new instance
- */
- public static OrientedPoint fromLocationAndDirection(final double location, final boolean positiveFacing,
- final DoublePrecisionContext precision) {
- return fromPointAndDirection(Vector1D.of(location), positiveFacing, precision);
- }
-
- /** Create a new instance from the given point and boolean direction value.
- * @param point the location of the hyperplane
- * @param positiveFacing if true, the hyperplane will face toward positive infinity;
- * otherwise, it will point toward negative infinity.
- * @param precision precision context used to compare floating point values
- * @return a new instance
- */
- public static OrientedPoint fromPointAndDirection(final Vector1D point, final boolean positiveFacing,
- final DoublePrecisionContext precision) {
- return new OrientedPoint(point, positiveFacing, precision);
- }
-
- /** Create a new instance from the given point and direction.
- * @param point the location of the hyperplane
- * @param direction the direction of the plus side of the hyperplane
- * @param precision precision context used to compare floating point values
- * @return a new instance oriented in the given direction
- * @throws IllegalArgumentException if the direction is zero as evaluated by the
- * given precision context
- */
- public static OrientedPoint fromPointAndDirection(final Vector1D point, final Vector1D direction,
- final DoublePrecisionContext precision) {
- if (direction.isZero(precision)) {
- throw new IllegalArgumentException("Oriented point direction cannot be zero");
- }
-
- final boolean positiveFacing = direction.getX() > 0;
-
- return new OrientedPoint(point, positiveFacing, precision);
- }
-
- /** Create a new instance at the given point, oriented so that it is facing positive infinity.
- * @param point the location of the hyperplane
- * @param precision precision context used to compare floating point values
- * @return a new instance oriented toward positive infinity
- */
- public static OrientedPoint createPositiveFacing(final Vector1D point, final DoublePrecisionContext precision) {
- return new OrientedPoint(point, true, precision);
- }
-
- /** Create a new instance at the given location, oriented so that it is facing positive infinity.
- * @param location the location of the hyperplane
- * @param precision precision context used to compare floating point values
- * @return a new instance oriented toward positive infinity
- */
- public static OrientedPoint createPositiveFacing(final double location, final DoublePrecisionContext precision) {
- return new OrientedPoint(Vector1D.of(location), true, precision);
- }
-
- /** Create a new instance at the given point, oriented so that it is facing negative infinity.
- * @param point the location of the hyperplane
- * @param precision precision context used to compare floating point values
- * @return a new instance oriented toward negative infinity
- */
- public static OrientedPoint createNegativeFacing(final Vector1D point, final DoublePrecisionContext precision) {
- return new OrientedPoint(point, false, precision);
- }
-
- /** Create a new instance at the given location, oriented so that it is facing negative infinity.
- * @param location the location of the hyperplane
- * @param precision precision context used to compare floating point values
- * @return a new instance oriented toward negative infinity
- */
- public static OrientedPoint createNegativeFacing(final double location, final DoublePrecisionContext precision) {
- return new OrientedPoint(Vector1D.of(location), false, precision);
- }
-
- /** {@link ConvexSubHyperplane} implementation for Euclidean 1D space. Since there are no subspaces in 1D,
+ /** {@link HyperplaneConvexSubset} implementation for Euclidean 1D space. Since there are no subspaces in 1D,
* this is effectively a stub implementation, its main use being to allow for the correct functioning of
* partitioning code.
*/
- public static class SubOrientedPoint implements ConvexSubHyperplane<Vector1D> {
+ private static class OrientedPointConvexSubset implements HyperplaneConvexSubset<Vector1D> {
/** The underlying hyperplane for this instance. */
private final OrientedPoint hyperplane;
/** Simple constructor.
* @param hyperplane underlying hyperplane instance
*/
- public SubOrientedPoint(final OrientedPoint hyperplane) {
+ OrientedPointConvexSubset(final OrientedPoint hyperplane) {
this.hyperplane = hyperplane;
}
@@ -411,11 +338,11 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
/** {@inheritDoc} */
@Override
- public Split<SubOrientedPoint> split(final Hyperplane<Vector1D> splitter) {
+ public Split<OrientedPointConvexSubset> split(final Hyperplane<Vector1D> splitter) {
final HyperplaneLocation side = splitter.classify(hyperplane.getPoint());
- SubOrientedPoint minus = null;
- SubOrientedPoint plus = null;
+ OrientedPointConvexSubset minus = null;
+ OrientedPointConvexSubset plus = null;
if (side == HyperplaneLocation.MINUS) {
minus = this;
@@ -428,26 +355,26 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
/** {@inheritDoc} */
@Override
- public List<SubOrientedPoint> toConvex() {
- return Arrays.asList(this);
+ public List<OrientedPointConvexSubset> toConvex() {
+ return Collections.singletonList(this);
}
/** {@inheritDoc} */
@Override
- public SubOrientedPoint transform(final Transform<Vector1D> transform) {
- return getHyperplane().transform(transform).span();
+ public OrientedPointConvexSubset transform(final Transform<Vector1D> transform) {
+ return new OrientedPointConvexSubset(getHyperplane().transform(transform));
}
/** {@inheritDoc} */
@Override
- public SubOrientedPointBuilder builder() {
- return new SubOrientedPointBuilder(this);
+ public OrientedPointSubsetBuilder builder() {
+ return new OrientedPointSubsetBuilder(this);
}
/** {@inheritDoc} */
@Override
- public SubOrientedPoint reverse() {
- return new SubOrientedPoint(hyperplane.reverse());
+ public OrientedPointConvexSubset reverse() {
+ return new OrientedPointConvexSubset(hyperplane.reverse());
}
/** {@inheritDoc} */
@@ -463,36 +390,36 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
}
}
- /** {@link SubHyperplane.Builder} implementation for Euclidean 1D space. Similar to {@link SubOrientedPoint},
- * this is effectively a stub implementation since there are no subspaces of 1D space. Its primary use is to allow
- * for the correct functioning of partitioning code.
+ /** {@link HyperplaneSubset.Builder} implementation for Euclidean 1D space. Similar to
+ * {@link OrientedPointConvexSubset}, this is effectively a stub implementation since there are no subspaces
+ * of 1D space. Its primary use is to allow for the correct functioning of partitioning code.
*/
- public static final class SubOrientedPointBuilder implements SubHyperplane.Builder<Vector1D> {
- /** Base subhyperplane for the builder. */
- private final SubOrientedPoint base;
+ private static final class OrientedPointSubsetBuilder implements HyperplaneSubset.Builder<Vector1D> {
+ /** Base hyperplane subset for the builder. */
+ private final OrientedPointConvexSubset base;
- /** Construct a new instance using the given base subhyperplane.
- * @param base base subhyperplane for the instance
+ /** Construct a new instance using the given base hyperplane subset.
+ * @param base base hyperplane subset for the instance
*/
- private SubOrientedPointBuilder(final SubOrientedPoint base) {
+ OrientedPointSubsetBuilder(final OrientedPointConvexSubset base) {
this.base = base;
}
/** {@inheritDoc} */
@Override
- public void add(final SubHyperplane<Vector1D> sub) {
+ public void add(final HyperplaneSubset<Vector1D> sub) {
validateHyperplane(sub);
}
/** {@inheritDoc} */
@Override
- public void add(final ConvexSubHyperplane<Vector1D> sub) {
+ public void add(final HyperplaneConvexSubset<Vector1D> sub) {
validateHyperplane(sub);
}
/** {@inheritDoc} */
@Override
- public SubOrientedPoint build() {
+ public OrientedPointConvexSubset build() {
return base;
}
@@ -508,12 +435,12 @@ public final class OrientedPoint extends AbstractHyperplane<Vector1D>
return sb.toString();
}
- /** Validate the given subhyperplane lies on the same hyperplane.
- * @param sub subhyperplane to validate
+ /** Validate that the given hyperplane subset lies on the same hyperplane as this instance.
+ * @param sub hyperplane subset to validate
* @throws IllegalArgumentException if the argument does not lie on
* the same hyperplane as this instance
*/
- private void validateHyperplane(final SubHyperplane<Vector1D> sub) {
+ private void validateHyperplane(final HyperplaneSubset<Vector1D> sub) {
final OrientedPoint baseHyper = base.getHyperplane();
final OrientedPoint inputHyper = (OrientedPoint) sub.getHyperplane();
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoints.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoints.java
new file mode 100644
index 0000000..8bece35
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/oned/OrientedPoints.java
@@ -0,0 +1,107 @@
+/*
+ * 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.commons.geometry.euclidean.oned;
+
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+
+/** Class containing factory methods for constructing {@link OrientedPoint} instances.
+ */
+public final class OrientedPoints {
+
+ /** Utility class; no instantiation. */
+ private OrientedPoints() {
+ }
+
+ /** Create a new instance from the given location and boolean direction value.
+ * @param location the location of the hyperplane
+ * @param positiveFacing if true, the hyperplane will face toward positive infinity;
+ * otherwise, it will point toward negative infinity.
+ * @param precision precision context used to compare floating point values
+ * @return a new instance
+ */
+ public static OrientedPoint fromLocationAndDirection(final double location, final boolean positiveFacing,
+ final DoublePrecisionContext precision) {
+ return fromPointAndDirection(Vector1D.of(location), positiveFacing, precision);
+ }
+
+ /** Create a new instance from the given point and boolean direction value.
+ * @param point the location of the hyperplane
+ * @param positiveFacing if true, the hyperplane will face toward positive infinity;
+ * otherwise, it will point toward negative infinity.
+ * @param precision precision context used to compare floating point values
+ * @return a new instance
+ */
+ public static OrientedPoint fromPointAndDirection(final Vector1D point, final boolean positiveFacing,
+ final DoublePrecisionContext precision) {
+ return new OrientedPoint(point, positiveFacing, precision);
+ }
+
+ /** Create a new instance from the given point and direction.
+ * @param point the location of the hyperplane
+ * @param direction the direction of the plus side of the hyperplane
+ * @param precision precision context used to compare floating point values
+ * @return a new instance oriented in the given direction
+ * @throws IllegalArgumentException if the direction is zero as evaluated by the
+ * given precision context
+ */
+ public static OrientedPoint fromPointAndDirection(final Vector1D point, final Vector1D direction,
+ final DoublePrecisionContext precision) {
+ if (direction.isZero(precision)) {
+ throw new IllegalArgumentException("Oriented point direction cannot be zero");
+ }
+
+ final boolean positiveFacing = direction.getX() > 0;
+
+ return new OrientedPoint(point, positiveFacing, precision);
+ }
+
+ /** Create a new instance at the given point, oriented so that it is facing positive infinity.
+ * @param point the location of the hyperplane
+ * @param precision precision context used to compare floating point values
+ * @return a new instance oriented toward positive infinity
+ */
+ public static OrientedPoint createPositiveFacing(final Vector1D point, final DoublePrecisionContext precision) {
+ return new OrientedPoint(point, true, precision);
+ }
+
+ /** Create a new instance at the given location, oriented so that it is facing positive infinity.
+ * @param location the location of the hyperplane
+ * @param precision precision context used to compare floating point values
+ * @return a new instance oriented toward positive infinity
+ */
+ public static OrientedPoint createPositiveFacing(final double location, final DoublePrecisionContext precision) {
+ return new OrientedPoint(Vector1D.of(location), true, precision);
+ }
+
+ /** Create a new instance at the given point, oriented so that it is facing negative infinity.
+ * @param point the location of the hyperplane
+ * @param precision precision context used to compare floating point values
+ * @return a new instance oriented toward negative infinity
+ */
+ public static OrientedPoint createNegativeFacing(final Vector1D point, final DoublePrecisionContext precision) {
+ return new OrientedPoint(point, false, precision);
+ }
+
+ /** Create a new instance at the given location, oriented so that it is facing negative infinity.
+ * @param location the location of the hyperplane
+ * @param precision precision context used to compare floating point values
+ * @return a new instance oriented toward negative infinity
+ */
+ public static OrientedPoint createNegativeFacing(final double location, final DoublePrecisionContext precision) {
+ return new OrientedPoint(Vector1D.of(location), false, precision);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AbstractSubLine3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AbstractSubLine3D.java
deleted file mode 100644
index 35f8631..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AbstractSubLine3D.java
+++ /dev/null
@@ -1,56 +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.commons.geometry.euclidean.threed;
-
-import org.apache.commons.geometry.core.Region;
-import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
-import org.apache.commons.geometry.euclidean.oned.Vector1D;
-
-/** Internal base class for 3 dimensional subline implementations.
- * @param <R> 1D subspace region type
- */
-abstract class AbstractSubLine3D<R extends Region<Vector1D>> {
- /** The line that this instance belongs to. */
- private final Line3D line;
-
- /** Construct a new instance belonging to the given line.
- * @param line line the instance belongs to
- */
- protected AbstractSubLine3D(final Line3D line) {
- this.line = line;
- }
-
- /** Get the line that this subline belongs to.
- * @return the line that this subline belongs to.
- */
- public Line3D getLine() {
- return line;
- }
-
- /** Get the precision object used to perform floating point
- * comparisons for this instance.
- * @return the precision object for this instance
- */
- public DoublePrecisionContext getPrecision() {
- return line.getPrecision();
- }
-
- /** Get the subspace region for the subline.
- * @return the subspace region for the subline
- */
- public abstract R getSubspaceRegion();
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySource3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySource3D.java
index cc912a1..791d7f4 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySource3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySource3D.java
@@ -18,13 +18,16 @@ package org.apache.commons.geometry.euclidean.threed;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import org.apache.commons.geometry.core.partitioning.BoundarySource;
+import org.apache.commons.geometry.euclidean.threed.line.LineConvexSubset3D;
+import org.apache.commons.geometry.euclidean.threed.line.LinecastPoint3D;
+import org.apache.commons.geometry.euclidean.threed.line.Linecastable3D;
-/** Extension of the {@link BoundarySource} interface for Euclidean 3D
- * space.
+/** Extension of the {@link BoundarySource} interface for Euclidean 3D space.
*/
-public interface BoundarySource3D extends BoundarySource<ConvexSubPlane> {
+public interface BoundarySource3D extends BoundarySource<PlaneConvexSubset>, Linecastable3D {
/** Return a BSP tree constructed from the boundaries contained in this instance.
* The default implementation creates a new, empty tree and inserts the
@@ -38,20 +41,32 @@ public interface BoundarySource3D extends BoundarySource<ConvexSubPlane> {
return tree;
}
+ /** {@inheritDoc} */
+ @Override
+ default List<LinecastPoint3D> linecast(final LineConvexSubset3D subset) {
+ return new BoundarySourceLinecaster3D(this).linecast(subset);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ default LinecastPoint3D linecastFirst(final LineConvexSubset3D subset) {
+ return new BoundarySourceLinecaster3D(this).linecastFirst(subset);
+ }
+
/** Return a {@link BoundarySource3D} instance containing the given boundaries.
* @param boundaries boundaries to include in the boundary source
* @return a boundary source containing the given boundaries
*/
- static BoundarySource3D from(final ConvexSubPlane... boundaries) {
+ static BoundarySource3D from(final PlaneConvexSubset... boundaries) {
return from(Arrays.asList(boundaries));
}
/** Return a {@link BoundarySource3D} instance containing the given boundaries. The given
- * collection is used directly as the source of the subplanes; no copy is made.
+ * collection is used directly as the source of the boundaries; no copy is made.
* @param boundaries boundaries to include in the boundary source
* @return a boundary source containing the given boundaries
*/
- static BoundarySource3D from(final Collection<ConvexSubPlane> boundaries) {
+ static BoundarySource3D from(final Collection<PlaneConvexSubset> boundaries) {
return boundaries::stream;
}
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySourceLinecaster3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySourceLinecaster3D.java
index 73b0448..56caf89 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySourceLinecaster3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/BoundarySourceLinecaster3D.java
@@ -22,9 +22,13 @@ import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.apache.commons.geometry.euclidean.threed.line.LineConvexSubset3D;
+import org.apache.commons.geometry.euclidean.threed.line.LinecastPoint3D;
+import org.apache.commons.geometry.euclidean.threed.line.Linecastable3D;
+
/** Class that performs linecast operations against arbitrary {@link BoundarySource3D}
* instances. This class performs a brute-force computation of the intersections of the
- * line or line segment against all boundaries. Some data structures may support more
+ * line or line convex subset against all boundaries. Some data structures may support more
* efficient algorithms and should therefore prefer those instead.
*/
final class BoundarySourceLinecaster3D implements Linecastable3D {
@@ -41,8 +45,8 @@ final class BoundarySourceLinecaster3D implements Linecastable3D {
/** {@inheritDoc} */
@Override
- public List<LinecastPoint3D> linecast(final Segment3D segment) {
- final List<LinecastPoint3D> results = getIntersectionStream(segment)
+ public List<LinecastPoint3D> linecast(final LineConvexSubset3D subset) {
+ final List<LinecastPoint3D> results = getIntersectionStream(subset)
.collect(Collectors.toCollection(ArrayList::new));
LinecastPoint3D.sortAndFilter(results);
@@ -52,37 +56,38 @@ final class BoundarySourceLinecaster3D implements Linecastable3D {
/** {@inheritDoc} */
@Override
- public LinecastPoint3D linecastFirst(final Segment3D segment) {
- return getIntersectionStream(segment)
+ public LinecastPoint3D linecastFirst(final LineConvexSubset3D subset) {
+ return getIntersectionStream(subset)
.min(LinecastPoint3D.ABSCISSA_ORDER)
.orElse(null);
}
/** Return a stream containing intersections between the boundary source and the
- * given line segment.
- * @param segment segment to intersect
+ * given line convex subset.
+ * @param subset line subset to intersect
* @return a stream containing linecast intersections
*/
- private Stream<LinecastPoint3D> getIntersectionStream(final Segment3D segment) {
+ private Stream<LinecastPoint3D> getIntersectionStream(final LineConvexSubset3D subset) {
return boundarySrc.boundaryStream()
- .map(boundary -> computeIntersection(boundary, segment))
+ .map(boundary -> computeIntersection(boundary, subset))
.filter(Objects::nonNull);
}
- /** Compute the intersection between a boundary subplane and segment. Null is
+ /** Compute the intersection between a boundary plane subset and line subset. Null is
* returned if no intersection is discovered.
- * @param subplane subplane from the boundary source
- * @param segment linecast segment to intersect with
+ * @param planeSubset plane subset from the boundary source
+ * @param lineSubset line subset to intersect with
* @return the linecast intersection between the two arguments or null if there is no such
* intersection
*/
- private LinecastPoint3D computeIntersection(final ConvexSubPlane subplane, final Segment3D segment) {
- final Vector3D intersectionPt = subplane.intersection(segment);
+ private LinecastPoint3D computeIntersection(final PlaneConvexSubset planeSubset,
+ final LineConvexSubset3D lineSubset) {
+ final Vector3D intersectionPt = planeSubset.intersection(lineSubset);
if (intersectionPt != null) {
- final Vector3D normal = subplane.getPlane().getNormal();
+ final Vector3D normal = planeSubset.getPlane().getNormal();
- return new LinecastPoint3D(intersectionPt, normal, segment.getLine());
+ return new LinecastPoint3D(intersectionPt, normal, lineSubset.getLine());
}
return null; // no intersection
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/ConvexSubPlane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/ConvexSubPlane.java
deleted file mode 100644
index ab48979..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/ConvexSubPlane.java
+++ /dev/null
@@ -1,195 +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.commons.geometry.euclidean.threed;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
-import org.apache.commons.geometry.core.partitioning.Hyperplane;
-import org.apache.commons.geometry.core.partitioning.Split;
-import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
-import org.apache.commons.geometry.euclidean.threed.Plane.SubspaceTransform;
-import org.apache.commons.geometry.euclidean.twod.AffineTransformMatrix2D;
-import org.apache.commons.geometry.euclidean.twod.ConvexArea;
-import org.apache.commons.geometry.euclidean.twod.Vector2D;
-
-/** Class representing a convex subhyperplane in 3 dimensional Euclidean space, meaning
- * a 2D convex area embedded in a plane. The subhyperplane may be finite or infinite.
- */
-public final class ConvexSubPlane extends AbstractSubPlane<ConvexArea>
- implements ConvexSubHyperplane<Vector3D> {
- /** The embedded 2D area. */
- private final ConvexArea area;
-
- /** Create a new instance from its component parts.
- * @param plane plane the the convex area is embedded in
- * @param area the embedded convex area
- */
- private ConvexSubPlane(final Plane plane, final ConvexArea area) {
- super(plane);
-
- this.area = area;
- }
-
- /** {@inheritDoc} */
- @Override
- public List<ConvexSubPlane> toConvex() {
- return Arrays.asList(this);
- }
-
- /** {@inheritDoc} */
- @Override
- public ConvexSubPlane reverse() {
- final Plane plane = getPlane();
- final Plane rPlane = plane.reverse();
-
- final Vector2D rU = rPlane.toSubspace(plane.toSpace(Vector2D.Unit.PLUS_X));
- final Vector2D rV = rPlane.toSubspace(plane.toSpace(Vector2D.Unit.PLUS_Y));
-
- final AffineTransformMatrix2D transform =
- AffineTransformMatrix2D.fromColumnVectors(rU, rV);
-
- return new ConvexSubPlane(rPlane, area.transform(transform));
- }
-
- /** {@inheritDoc} */
- @Override
- public ConvexSubPlane transform(final Transform<Vector3D> transform) {
- final SubspaceTransform st = getPlane().subspaceTransform(transform);
- final ConvexArea tArea = area.transform(st.getTransform());
-
- return fromConvexArea(st.getPlane(), tArea);
- }
-
- /** {@inheritDoc} */
- @Override
- public ConvexArea getSubspaceRegion() {
- return area;
- }
-
- /** {@inheritDoc} */
- @Override
- public Split<ConvexSubPlane> split(final Hyperplane<Vector3D> splitter) {
- return splitInternal(splitter, this, (p, r) -> new ConvexSubPlane(p, (ConvexArea) r));
- }
-
- /** Get the unique intersection of this subplane with the given line. Null is
- * returned if no unique intersection point exists (ie, the line and plane are
- * parallel or coincident) or the line does not intersect the subplane.
- * @param line line to intersect with this subplane
- * @return the unique intersection point between the line and this subplane
- * or null if no such point exists.
- * @see Plane#intersection(Line3D)
- */
- public Vector3D intersection(final Line3D line) {
- final Vector3D pt = getPlane().intersection(line);
- return (pt != null && contains(pt)) ? pt : null;
- }
-
- /** Get the unique intersection of this subplane with the given segment. Null
- * is returned if the underlying line and plane do not have a unique intersection
- * point (ie, they are parallel or coincident) or the intersection point is unique
- * but is not contained in both the segment and subplane.
- * @param segment segment to intersect with
- * @return the unique intersection point between this subplane and the argument or
- * null if no such point exists.
- * @see Plane#intersection(Line3D)
- */
- public Vector3D intersection(final Segment3D segment) {
- final Vector3D pt = intersection(segment.getLine());
- return (pt != null && segment.contains(pt)) ? pt : null;
- }
-
- /** Get the vertices for the subplane. The vertices lie at the intersections of the
- * 2D area bounding lines.
- * @return the vertices for the subplane
- */
- public List<Vector3D> getVertices() {
- return getPlane().toSpace(area.getVertices());
- }
-
- /** Create a new instance from a plane and an embedded convex subspace area.
- * @param plane embedding plane for the area
- * @param area area embedded in the plane
- * @return a new convex sub plane instance
- */
- public static ConvexSubPlane fromConvexArea(final Plane plane, final ConvexArea area) {
- return new ConvexSubPlane(plane, area);
- }
-
- /** Create a new instance from the given sequence of points. The points must define a unique plane, meaning that
- * at least 3 unique vertices must be given. In contrast with the
- * {@link #fromVertices(Collection, DoublePrecisionContext)} method, the first point in the sequence is included
- * at the end if needed, in order to form a closed loop.
- * @param pts collection of points defining the subplane
- * @param precision precision context used to compare floating point values
- * @return a new instance defined by the given sequence of vertices
- * @throws IllegalArgumentException if fewer than 3 vertices are given or the vertices do not define a
- * unique plane
- * @see #fromVertices(Collection, DoublePrecisionContext)
- * @see #fromVertices(Collection, boolean, DoublePrecisionContext)
- * @see Plane#fromPoints(Collection, DoublePrecisionContext)
- */
- public static ConvexSubPlane fromVertexLoop(final Collection<Vector3D> pts,
- final DoublePrecisionContext precision) {
- return fromVertices(pts, true, precision);
- }
-
- /** Create a new instance from the given sequence of points. The points must define a unique plane, meaning that
- * at least 3 unique vertices must be given.
- * @param pts collection of points defining the subplane
- * @param precision precision context used to compare floating point values
- * @return a new instance defined by the given sequence of vertices
- * @throws IllegalArgumentException if fewer than 3 vertices are given or the vertices do not define a
- * unique plane
- * @see #fromVertexLoop(Collection, DoublePrecisionContext)
- * @see #fromVertices(Collection, boolean, DoublePrecisionContext)
- * @see Plane#fromPoints(Collection, DoublePrecisionContext)
- */
- public static ConvexSubPlane fromVertices(final Collection<Vector3D> pts,
- final DoublePrecisionContext precision) {
- return fromVertices(pts, false, precision);
- }
-
- /** Create a new instance from the given sequence of points. The points must define a unique plane, meaning that
- * at least 3 unique vertices must be given. If {@code close} is true, the vertices are made into a closed loop
- * by including the start point at the end if needed.
- * @param pts collection of points
- * @param close if true, the point sequence will implicitly include the start point again at the end; otherwise
- * the vertex sequence is taken as-is
- * @param precision precision context used to compare floating point values
- * @return a new subplane instance
- * @throws IllegalArgumentException if fewer than 3 vertices are given or the vertices do not define a
- * unique plane
- * @see #fromVertexLoop(Collection, DoublePrecisionContext)
- * @see #fromVertices(Collection, DoublePrecisionContext)
- * @see Plane#fromPoints(Collection, DoublePrecisionContext)
- */
- public static ConvexSubPlane fromVertices(final Collection<Vector3D> pts, final boolean close,
- final DoublePrecisionContext precision) {
-
- final Plane plane = Plane.fromPoints(pts, precision);
-
- final List<Vector2D> subspacePts = plane.toSubspace(pts);
- final ConvexArea area = ConvexArea.fromVertices(subspacePts, close, precision);
-
- return new ConvexSubPlane(plane, area);
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/ConvexVolume.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/ConvexVolume.java
index 4daedab..57949c3 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/ConvexVolume.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/ConvexVolume.java
@@ -23,16 +23,16 @@ import java.util.stream.Stream;
import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.partitioning.AbstractConvexHyperplaneBoundedRegion;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.euclidean.twod.ConvexArea;
/** Class representing a finite or infinite convex volume in Euclidean 3D space.
- * The boundaries of this area, if any, are composed of convex subplanes.
+ * The boundaries of this area, if any, are composed of plane convex subsets.
*/
-public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D, ConvexSubPlane>
- implements BoundarySource3D, Linecastable3D {
+public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D, PlaneConvexSubset>
+ implements BoundarySource3D {
/** Instance representing the full 3D volume. */
private static final ConvexVolume FULL = new ConvexVolume(Collections.emptyList());
@@ -41,13 +41,13 @@ public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D
* represents the boundary of a convex area. No validation is performed.
* @param boundaries the boundaries of the convex area
*/
- protected ConvexVolume(final List<ConvexSubPlane> boundaries) {
+ protected ConvexVolume(final List<PlaneConvexSubset> boundaries) {
super(boundaries);
}
/** {@inheritDoc} */
@Override
- public Stream<ConvexSubPlane> boundaryStream() {
+ public Stream<PlaneConvexSubset> boundaryStream() {
return getBoundaries().stream();
}
@@ -60,7 +60,7 @@ public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D
double volumeSum = 0.0;
- for (final ConvexSubPlane boundary : getBoundaries()) {
+ for (final PlaneConvexSubset boundary : getBoundaries()) {
if (boundary.isInfinite()) {
return Double.POSITIVE_INFINITY;
}
@@ -87,7 +87,7 @@ public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D
double sumY = 0.0;
double sumZ = 0.0;
- for (final ConvexSubPlane boundary : getBoundaries()) {
+ for (final PlaneConvexSubset boundary : getBoundaries()) {
if (boundary.isInfinite()) {
return null;
}
@@ -126,7 +126,7 @@ public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D
/** {@inheritDoc} */
@Override
public Split<ConvexVolume> split(final Hyperplane<Vector3D> splitter) {
- return splitInternal(splitter, this, ConvexSubPlane.class, ConvexVolume::new);
+ return splitInternal(splitter, this, PlaneConvexSubset.class, ConvexVolume::new);
}
/** Return a BSP tree representing the same region as this instance.
@@ -138,20 +138,8 @@ public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D
/** {@inheritDoc} */
@Override
- public List<LinecastPoint3D> linecast(final Segment3D segment) {
- return new BoundarySourceLinecaster3D(this).linecast(segment);
- }
-
- /** {@inheritDoc} */
- @Override
- public LinecastPoint3D linecastFirst(final Segment3D segment) {
- return new BoundarySourceLinecaster3D(this).linecastFirst(segment);
- }
-
- /** {@inheritDoc} */
- @Override
- public ConvexSubPlane trim(final ConvexSubHyperplane<Vector3D> convexSubHyperplane) {
- return (ConvexSubPlane) super.trim(convexSubHyperplane);
+ public PlaneConvexSubset trim(final HyperplaneConvexSubset<Vector3D> convexSubset) {
+ return (PlaneConvexSubset) super.trim(convexSubset);
}
/** Return a new instance transformed by the argument.
@@ -159,7 +147,7 @@ public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D
* @return a new instance transformed by the argument
*/
public ConvexVolume transform(final Transform<Vector3D> transform) {
- return transformInternal(transform, this, ConvexSubPlane.class, ConvexVolume::new);
+ return transformInternal(transform, this, PlaneConvexSubset.class, ConvexVolume::new);
}
/** Return an instance representing the full 3D volume.
@@ -196,7 +184,7 @@ public class ConvexVolume extends AbstractConvexHyperplaneBoundedRegion<Vector3D
* meaning that there is no region that is on the minus side of all of the bounding planes.
*/
public static ConvexVolume fromBounds(final Iterable<Plane> boundingPlanes) {
- final List<ConvexSubPlane> facets = new ConvexRegionBoundaryBuilder<>(ConvexSubPlane.class)
+ final List<PlaneConvexSubset> facets = new ConvexRegionBoundaryBuilder<>(PlaneConvexSubset.class)
.build(boundingPlanes);
return facets.isEmpty() ? full() : new ConvexVolume(facets);
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubPlane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/EmbeddedTreePlaneSubset.java
similarity index 54%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubPlane.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/EmbeddedTreePlaneSubset.java
index e09d1b4..5c49f6f 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubPlane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/EmbeddedTreePlaneSubset.java
@@ -20,45 +20,45 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
import org.apache.commons.geometry.core.partitioning.Split;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
import org.apache.commons.geometry.euclidean.twod.ConvexArea;
import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
-/** Class representing an arbitrary region of a plane. This class can represent
- * both convex and non-convex regions of its underlying plane.
+/** Class representing an arbitrary subset of a plane using a {@link RegionBSPTree2D}.
+ * This class can represent convex, non-convex, finite, infinite, and empty regions.
*
* <p>This class is mutable and <em>not</em> thread safe.</p>
*/
-public final class SubPlane extends AbstractSubPlane<RegionBSPTree2D> {
+public final class EmbeddedTreePlaneSubset extends PlaneSubset {
/** The 2D region representing the area on the plane. */
private final RegionBSPTree2D region;
- /** Construct a new, empty subplane for the given plane.
- * @param plane plane defining the subplane
+ /** Construct a new, empty plane subset for the given plane.
+ * @param plane plane defining the subset
*/
- public SubPlane(final Plane plane) {
+ public EmbeddedTreePlaneSubset(final Plane plane) {
this(plane, false);
}
- /** Construct a new subplane for the given plane. If {@code full}
- * is true, then the subplane will cover the entire plane; otherwise,
+ /** Construct a new subset for the given plane. If {@code full}
+ * is true, then the subset will cover the entire plane; otherwise,
* it will be empty.
- * @param plane plane defining the subplane
- * @param full if true, the subplane will cover the entire space;
+ * @param plane plane defining the subset
+ * @param full if true, the subset will cover the entire space;
* otherwise it will be empty
*/
- public SubPlane(final Plane plane, boolean full) {
+ public EmbeddedTreePlaneSubset(final Plane plane, boolean full) {
this(plane, new RegionBSPTree2D(full));
}
/** Construct a new instance from its defining plane and subspace region.
- * @param plane plane defining the subplane
- * @param region subspace region for the subplane
+ * @param plane plane defining the subset
+ * @param region subspace region for the plane subset
*/
- public SubPlane(final Plane plane, final RegionBSPTree2D region) {
+ public EmbeddedTreePlaneSubset(final Plane plane, final RegionBSPTree2D region) {
super(plane);
this.region = region;
@@ -66,14 +66,14 @@ public final class SubPlane extends AbstractSubPlane<RegionBSPTree2D> {
/** {@inheritDoc} */
@Override
- public List<ConvexSubPlane> toConvex() {
+ public List<PlaneConvexSubset> toConvex() {
final List<ConvexArea> areas = region.toConvex();
final Plane plane = getPlane();
- final List<ConvexSubPlane> facets = new ArrayList<>(areas.size());
+ final List<PlaneConvexSubset> facets = new ArrayList<>(areas.size());
for (final ConvexArea area : areas) {
- facets.add(ConvexSubPlane.fromConvexArea(plane, area));
+ facets.add(Planes.subsetFromConvexArea(plane, area));
}
return facets;
@@ -84,14 +84,14 @@ public final class SubPlane extends AbstractSubPlane<RegionBSPTree2D> {
* <p>In all cases, the current instance is not modified. However, In order to avoid
* unnecessary copying, this method will use the current instance as the split value when
* the instance lies entirely on the plus or minus side of the splitter. For example, if
- * this instance lies entirely on the minus side of the splitter, the subplane
+ * this instance lies entirely on the minus side of the splitter, the plane subset
* returned by {@link Split#getMinus()} will be this instance. Similarly, {@link Split#getPlus()}
* will return the current instance if it lies entirely on the plus side. Callers need to make
* special note of this, since this class is mutable.</p>
*/
@Override
- public Split<SubPlane> split(final Hyperplane<Vector3D> splitter) {
- return splitInternal(splitter, this, (p, r) -> new SubPlane(p, (RegionBSPTree2D) r));
+ public Split<EmbeddedTreePlaneSubset> split(final Hyperplane<Vector3D> splitter) {
+ return splitInternal(splitter, this, (p, r) -> new EmbeddedTreePlaneSubset(p, (RegionBSPTree2D) r));
}
/** {@inheritDoc} */
@@ -102,40 +102,40 @@ public final class SubPlane extends AbstractSubPlane<RegionBSPTree2D> {
/** {@inheritDoc} */
@Override
- public SubPlane transform(final Transform<Vector3D> transform) {
+ public EmbeddedTreePlaneSubset transform(final Transform<Vector3D> transform) {
final Plane.SubspaceTransform subTransform = getPlane().subspaceTransform(transform);
final RegionBSPTree2D tRegion = RegionBSPTree2D.empty();
tRegion.copy(region);
tRegion.transform(subTransform.getTransform());
- return new SubPlane(subTransform.getPlane(), tRegion);
+ return new EmbeddedTreePlaneSubset(subTransform.getPlane(), tRegion);
}
- /** Add a convex subplane to this instance.
- * @param subplane convex subplane to add
- * @throws IllegalArgumentException if the given subplane is not from
+ /** Add a plane convex subset to this instance.
+ * @param subset plane convex subset to add
+ * @throws IllegalArgumentException if the given plane subset is not from
* a plane equivalent to this instance
*/
- public void add(final ConvexSubPlane subplane) {
- validatePlane(subplane.getPlane());
+ public void add(final PlaneConvexSubset subset) {
+ validatePlane(subset.getPlane());
- region.add(subplane.getSubspaceRegion());
+ region.add(subset.getSubspaceRegion());
}
- /** Add a subplane to this instance.
- * @param subplane subplane to add
- * @throws IllegalArgumentException if the given subplane is not from
+ /** Add a plane subset to this instance.
+ * @param subset plane subset to add
+ * @throws IllegalArgumentException if the given plane subset is not from
* a plane equivalent to this instance
*/
- public void add(final SubPlane subplane) {
- validatePlane(subplane.getPlane());
+ public void add(final EmbeddedTreePlaneSubset subset) {
+ validatePlane(subset.getPlane());
- region.union(subplane.getSubspaceRegion());
+ region.union(subset.getSubspaceRegion());
}
/** Validate that the given plane is equivalent to the plane
- * defining this subplane.
+ * defining this instance.
* @param inputPlane plane to validate
* @throws IllegalArgumentException if the given plane is not equivalent
* to the plane for this instance
@@ -150,48 +150,48 @@ public final class SubPlane extends AbstractSubPlane<RegionBSPTree2D> {
}
}
- /** {@link Builder} implementation for sublines.
+ /** {@link HyperplaneSubset.Builder} implementation for plane subsets.
*/
- public static class SubPlaneBuilder implements SubHyperplane.Builder<Vector3D> {
+ public static class Builder implements HyperplaneSubset.Builder<Vector3D> {
- /** Subplane instance created by this builder. */
- private final SubPlane subplane;
+ /** Plane subset instance created by this builder. */
+ private final EmbeddedTreePlaneSubset subset;
- /** Construct a new instance for building subplane region for the given plane.
- * @param plane the underlying plane for the subplane region
+ /** Construct a new instance for building a subset region for the given plane.
+ * @param plane the underlying plane for the subset
*/
- public SubPlaneBuilder(final Plane plane) {
- this.subplane = new SubPlane(plane);
+ public Builder(final Plane plane) {
+ this.subset = new EmbeddedTreePlaneSubset(plane);
}
/** {@inheritDoc} */
@Override
- public void add(final SubHyperplane<Vector3D> sub) {
+ public void add(final HyperplaneSubset<Vector3D> sub) {
addInternal(sub);
}
/** {@inheritDoc} */
@Override
- public void add(final ConvexSubHyperplane<Vector3D> sub) {
+ public void add(final HyperplaneConvexSubset<Vector3D> sub) {
addInternal(sub);
}
/** {@inheritDoc} */
@Override
- public SubPlane build() {
- return subplane;
+ public EmbeddedTreePlaneSubset build() {
+ return subset;
}
- /** Internal method for adding subhyperplanes to this builder.
- * @param sub the subhyperplane to add; either convex or non-convex
+ /** Internal method for adding hyperplane subsets to this builder.
+ * @param sub the hyperplane subset to add; either convex or non-convex
*/
- private void addInternal(final SubHyperplane<Vector3D> sub) {
- if (sub instanceof ConvexSubPlane) {
- subplane.add((ConvexSubPlane) sub);
- } else if (sub instanceof SubPlane) {
- subplane.add((SubPlane) sub);
+ private void addInternal(final HyperplaneSubset<Vector3D> sub) {
+ if (sub instanceof PlaneConvexSubset) {
+ subset.add((PlaneConvexSubset) sub);
+ } else if (sub instanceof EmbeddedTreePlaneSubset) {
+ subset.add((EmbeddedTreePlaneSubset) sub);
} else {
- throw new IllegalArgumentException("Unsupported subhyperplane type: " + sub.getClass().getName());
+ throw new IllegalArgumentException("Unsupported plane subset type: " + sub.getClass().getName());
}
}
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
index 35781b8..4601680 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Plane.java
@@ -16,9 +16,6 @@
*/
package org.apache.commons.geometry.euclidean.threed;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
import java.util.Objects;
import org.apache.commons.geometry.core.Transform;
@@ -27,12 +24,15 @@ import org.apache.commons.geometry.core.partitioning.EmbeddingHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.euclidean.oned.Vector1D;
+import org.apache.commons.geometry.euclidean.threed.line.Line3D;
+import org.apache.commons.geometry.euclidean.threed.line.Lines3D;
import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
import org.apache.commons.geometry.euclidean.twod.AffineTransformMatrix2D;
import org.apache.commons.geometry.euclidean.twod.ConvexArea;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
/** Class representing a plane in 3 dimensional Euclidean space.
+ * @see Planes
*/
public final class Plane extends AbstractHyperplane<Vector3D>
implements EmbeddingHyperplane<Vector3D, Vector2D> {
@@ -57,7 +57,7 @@ public final class Plane extends AbstractHyperplane<Vector3D>
* @param originOffset offset of the origin with respect to the plane.
* @param precision precision context used to compare floating point values
*/
- private Plane(final Vector3D u, final Vector3D v, final Vector3D w, double originOffset,
+ Plane(final Vector3D u, final Vector3D v, final Vector3D w, double originOffset,
final DoublePrecisionContext precision) {
super(precision);
@@ -169,7 +169,7 @@ public final class Plane extends AbstractHyperplane<Vector3D>
final Vector3D p1 = project(line.getOrigin());
final Vector3D p2 = p1.add(projectedLineDirection);
- return Line3D.fromPoints(p1, p2, getPrecision());
+ return Lines3D.fromPoints(p1, p2, getPrecision());
}
/**
@@ -223,7 +223,7 @@ public final class Plane extends AbstractHyperplane<Vector3D>
final Vector3D p2 = transform.apply(origin.add(u));
final Vector3D p3 = transform.apply(origin.add(v));
- return fromPoints(p1, p2, p3, getPrecision());
+ return Planes.fromPoints(p1, p2, p3, getPrecision());
}
/** Get an object containing the current plane transformed by the argument along with a
@@ -255,7 +255,7 @@ public final class Plane extends AbstractHyperplane<Vector3D>
final Vector3D p2 = transform.apply(origin.add(u));
final Vector3D p3 = transform.apply(origin.add(v));
- final Plane tPlane = fromPoints(p1, p2, p3, getPrecision());
+ final Plane tPlane = Planes.fromPoints(p1, p2, p3, getPrecision());
final Vector2D tSubspaceOrigin = tPlane.toSubspace(p1);
final Vector2D tSubspaceU = tSubspaceOrigin.vectorTo(tPlane.toSubspace(p2));
@@ -374,8 +374,8 @@ public final class Plane extends AbstractHyperplane<Vector3D>
if (getPrecision().eqZero(direction.norm())) {
return null;
}
- final Vector3D point = intersection(this, other, Plane.fromNormal(direction, getPrecision()));
- return Line3D.fromPointAndDirection(point, direction, getPrecision());
+ final Vector3D point = intersection(this, other, Planes.fromNormal(direction, getPrecision()));
+ return Lines3D.fromPointAndDirection(point, direction, getPrecision());
}
/**
@@ -426,8 +426,8 @@ public final class Plane extends AbstractHyperplane<Vector3D>
/** {@inheritDoc} */
@Override
- public ConvexSubPlane span() {
- return ConvexSubPlane.fromConvexArea(this, ConvexArea.full());
+ public PlaneConvexSubset span() {
+ return Planes.subsetFromConvexArea(this, ConvexArea.full());
}
/**
@@ -565,168 +565,6 @@ public final class Plane extends AbstractHyperplane<Vector3D>
return sb.toString();
}
- /**
- * Build a plane from a point and two (on plane) vectors.
- * @param p the provided point (on plane)
- * @param u u vector (on plane)
- * @param v v vector (on plane)
- * @param precision precision context used to compare floating point values
- * @return a new plane
- * @throws IllegalArgumentException if the norm of the given values is zero, NaN, or infinite.
- */
- public static Plane fromPointAndPlaneVectors(final Vector3D p, final Vector3D u, final Vector3D v,
- final DoublePrecisionContext precision) {
- final Vector3D uNorm = u.normalize();
- final Vector3D vNorm = uNorm.orthogonal(v);
- final Vector3D wNorm = uNorm.cross(vNorm).normalize();
- final double originOffset = -p.dot(wNorm);
-
- return new Plane(uNorm, vNorm, wNorm, originOffset, precision);
- }
-
- /**
- * Build a plane from a normal.
- * Chooses origin as point on plane.
- * @param normal normal direction to the plane
- * @param precision precision context used to compare floating point values
- * @return a new plane
- * @throws IllegalArgumentException if the norm of the given values is zero, NaN, or infinite.
- */
- public static Plane fromNormal(final Vector3D normal, final DoublePrecisionContext precision) {
- return fromPointAndNormal(Vector3D.ZERO, normal, precision);
- }
-
- /**
- * Build a plane from a point and a normal.
- *
- * @param p point belonging to the plane
- * @param normal normal direction to the plane
- * @param precision precision context used to compare floating point values
- * @return a new plane
- * @throws IllegalArgumentException if the norm of the given values is zero, NaN, or infinite.
- */
- public static Plane fromPointAndNormal(final Vector3D p, final Vector3D normal,
- final DoublePrecisionContext precision) {
- final Vector3D w = normal.normalize();
- final double originOffset = -p.dot(w);
-
- final Vector3D u = w.orthogonal();
- final Vector3D v = w.cross(u);
-
- return new Plane(u, v, w, originOffset, precision);
- }
-
- /**
- * Build a plane from three points.
- * <p>
- * The plane is oriented in the direction of {@code (p2-p1) ^ (p3-p1)}
- * </p>
- *
- * @param p1 first point belonging to the plane
- * @param p2 second point belonging to the plane
- * @param p3 third point belonging to the plane
- * @param precision precision context used to compare floating point values
- * @return a new plane
- * @throws IllegalArgumentException if the points do not define a unique plane
- */
- public static Plane fromPoints(final Vector3D p1, final Vector3D p2, final Vector3D p3,
- final DoublePrecisionContext precision) {
- return Plane.fromPoints(Arrays.asList(p1, p2, p3), precision);
- }
-
- /** Construct a plane from a collection of points lying on the plane. The plane orientation is
- * determined by the overall orientation of the point sequence. For example, if the points wind
- * around the z-axis in a counter-clockwise direction, then the plane normal will point up the
- * +z axis. If the points wind in the opposite direction, then the plane normal will point down
- * the -z axis. The {@code u} vector for the plane is set to the first non-zero vector between
- * points in the sequence (ie, the first direction in the path).
- *
- * @param pts collection of sequenced points lying on the plane
- * @param precision precision context used to compare floating point values
- * @return a new plane containing the given points
- * @throws IllegalArgumentException if the given collection does not contain at least 3 points or the
- * points do not define a unique plane
- */
- public static Plane fromPoints(final Collection<Vector3D> pts, final DoublePrecisionContext precision) {
-
- if (pts.size() < 3) {
- throw new IllegalArgumentException("At least 3 points are required to define a plane; " +
- "argument contains only " + pts.size() + ".");
- }
-
- final Iterator<Vector3D> it = pts.iterator();
-
- final Vector3D startPt = it.next();
-
- Vector3D u = null;
- Vector3D w = null;
-
- Vector3D currentPt;
- Vector3D prevPt = startPt;
-
- Vector3D currentVector = null;
- Vector3D prevVector = null;
-
- Vector3D cross = null;
- double crossNorm;
- double crossSumX = 0.0;
- double crossSumY = 0.0;
- double crossSumZ = 0.0;
-
- boolean nonPlanar = false;
-
- while (it.hasNext()) {
- currentPt = it.next();
-
- if (!currentPt.eq(prevPt, precision)) {
- currentVector = startPt.vectorTo(currentPt);
-
- if (u == null) {
- // save the first non-zero vector as our u vector
- u = currentVector.normalize();
- }
- if (prevVector != null) {
- cross = prevVector.cross(currentVector);
-
- crossSumX += cross.getX();
- crossSumY += cross.getY();
- crossSumZ += cross.getZ();
-
- crossNorm = cross.norm();
-
- if (!precision.eqZero(crossNorm)) {
- // the cross product has non-zero magnitude
- if (w == null) {
- // save the first non-zero cross product as our normal
- w = cross.normalize();
- } else if (!precision.eq(1.0, Math.abs(w.dot(cross) / crossNorm))) {
- // if the normalized dot product is not either +1 or -1, then
- // the points are not coplanar
- nonPlanar = true;
- break;
- }
- }
- }
-
- prevVector = currentVector;
- prevPt = currentPt;
- }
- }
-
- if (u == null || w == null || nonPlanar) {
- throw new IllegalArgumentException("Points do not define a plane: " + pts);
- }
-
- if (w.dot(Vector3D.of(crossSumX, crossSumY, crossSumZ)) < 0) {
- w = w.negate();
- }
-
- final Vector3D v = w.cross(u);
- final double originOffset = -startPt.dot(w);
-
- return new Plane(u, v, w, originOffset, precision);
- }
-
/** Class containing a transformed plane instance along with a subspace (2D) transform. The subspace
* transform produces the equivalent of the 3D transform in 2D.
*/
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PlaneConvexSubset.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PlaneConvexSubset.java
new file mode 100644
index 0000000..82573a5
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PlaneConvexSubset.java
@@ -0,0 +1,128 @@
+/*
+ * 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.commons.geometry.euclidean.threed;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
+import org.apache.commons.geometry.core.partitioning.Split;
+import org.apache.commons.geometry.euclidean.threed.Plane.SubspaceTransform;
+import org.apache.commons.geometry.euclidean.threed.line.Line3D;
+import org.apache.commons.geometry.euclidean.threed.line.LineConvexSubset3D;
+import org.apache.commons.geometry.euclidean.twod.AffineTransformMatrix2D;
+import org.apache.commons.geometry.euclidean.twod.ConvexArea;
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
+
+/** Class representing a convex subset of points in a plane. The subset may be finite
+ * or infinite.
+ * @see Planes
+ */
+public final class PlaneConvexSubset extends PlaneSubset
+ implements HyperplaneConvexSubset<Vector3D> {
+ /** The embedded 2D area. */
+ private final ConvexArea area;
+
+ /** Create a new instance from its component parts.
+ * @param plane plane the the convex area is embedded in
+ * @param area the embedded convex area
+ */
+ PlaneConvexSubset(final Plane plane, final ConvexArea area) {
+ super(plane);
+
+ this.area = area;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public List<PlaneConvexSubset> toConvex() {
+ return Collections.singletonList(this);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public PlaneConvexSubset reverse() {
+ final Plane plane = getPlane();
+ final Plane rPlane = plane.reverse();
+
+ final Vector2D rU = rPlane.toSubspace(plane.toSpace(Vector2D.Unit.PLUS_X));
+ final Vector2D rV = rPlane.toSubspace(plane.toSpace(Vector2D.Unit.PLUS_Y));
+
+ final AffineTransformMatrix2D transform =
+ AffineTransformMatrix2D.fromColumnVectors(rU, rV);
+
+ return new PlaneConvexSubset(rPlane, area.transform(transform));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public PlaneConvexSubset transform(final Transform<Vector3D> transform) {
+ final SubspaceTransform st = getPlane().subspaceTransform(transform);
+ final ConvexArea tArea = area.transform(st.getTransform());
+
+ return Planes.subsetFromConvexArea(st.getPlane(), tArea);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ConvexArea getSubspaceRegion() {
+ return area;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Split<PlaneConvexSubset> split(final Hyperplane<Vector3D> splitter) {
+ return splitInternal(splitter, this, (p, r) -> new PlaneConvexSubset(p, (ConvexArea) r));
+ }
+
+ /** Get the unique intersection of this plane subset with the given line. Null is
+ * returned if no unique intersection point exists (ie, the line and plane are
+ * parallel or coincident) or the line does not intersect the plane subset.
+ * @param line line to intersect with this plane subset
+ * @return the unique intersection point between the line and this plane subset
+ * or null if no such point exists.
+ * @see Plane#intersection(Line3D)
+ */
+ public Vector3D intersection(final Line3D line) {
+ final Vector3D pt = getPlane().intersection(line);
+ return (pt != null && contains(pt)) ? pt : null;
+ }
+
+ /** Get the unique intersection of this plane subset with the given line subset. Null
+ * is returned if the underlying line and plane do not have a unique intersection
+ * point (ie, they are parallel or coincident) or the intersection point is unique
+ * but is not contained in both the line subset and plane subset.
+ * @param lineSubset line subset to intersect with
+ * @return the unique intersection point between this plane subset and the argument or
+ * null if no such point exists.
+ * @see Plane#intersection(Line3D)
+ */
+ public Vector3D intersection(final LineConvexSubset3D lineSubset) {
+ final Vector3D pt = intersection(lineSubset.getLine());
+ return (pt != null && lineSubset.contains(pt)) ? pt : null;
+ }
+
+ /** Get the vertices for the plane subset. The vertices lie at the intersections of the
+ * 2D area bounding lines.
+ * @return the vertices for the plane subset
+ */
+ public List<Vector3D> getVertices() {
+ return getPlane().toSpace(area.getVertices());
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AbstractSubPlane.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PlaneSubset.java
similarity index 79%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AbstractSubPlane.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PlaneSubset.java
index cea56a6..a3a3598 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/AbstractSubPlane.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/PlaneSubset.java
@@ -18,34 +18,35 @@ package org.apache.commons.geometry.euclidean.threed;
import java.util.function.BiFunction;
-import org.apache.commons.geometry.core.partitioning.AbstractEmbeddingSubHyperplane;
+import org.apache.commons.geometry.core.partitioning.AbstractRegionEmbeddingHyperplaneSubset;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.partitioning.SplitLocation;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
-import org.apache.commons.geometry.euclidean.threed.SubPlane.SubPlaneBuilder;
+import org.apache.commons.geometry.euclidean.threed.line.Line3D;
import org.apache.commons.geometry.euclidean.twod.Line;
+import org.apache.commons.geometry.euclidean.twod.Lines;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
-/** Internal base class for subplane implementations.
- * @param <R> Subspace region type
+/** Class representing a subset of points in a 3D Euclidean space. For example, triangles
+ * and other polygons in 3D are plane subsets. Instances may be finite or infinite.
*/
-abstract class AbstractSubPlane<R extends HyperplaneBoundedRegion<Vector2D>>
- extends AbstractEmbeddingSubHyperplane<Vector3D, Vector2D, Plane> {
+public abstract class PlaneSubset
+ extends AbstractRegionEmbeddingHyperplaneSubset<Vector3D, Vector2D, Plane> {
/** The plane defining this instance. */
private final Plane plane;
/** Construct a new instance based on the given plane.
- * @param plane the plane defining the subplane
+ * @param plane the plane defining the subset
*/
- AbstractSubPlane(final Plane plane) {
+ PlaneSubset(final Plane plane) {
this.plane = plane;
}
- /** Get the plane that this subplane lies on. This method is an alias
+ /** Get the plane that this subset lies on. This method is an alias
* for {@link #getHyperplane()}.
- * @return the plane that this subplane lies on
+ * @return the plane that this subset lies on
* @see #getHyperplane()
*/
public Plane getPlane() {
@@ -60,8 +61,8 @@ abstract class AbstractSubPlane<R extends HyperplaneBoundedRegion<Vector2D>>
/** {@inheritDoc} */
@Override
- public SubPlaneBuilder builder() {
- return new SubPlaneBuilder(plane);
+ public EmbeddedTreePlaneSubset.Builder builder() {
+ return new EmbeddedTreePlaneSubset.Builder(plane);
}
/** Return the object used to perform floating point comparisons, which is the
@@ -92,12 +93,12 @@ abstract class AbstractSubPlane<R extends HyperplaneBoundedRegion<Vector2D>>
* @param splitter splitting hyperplane
* @param thisInstance a reference to the current instance; this is passed as
* an argument in order to allow it to be a generic type
- * @param factory function used to create new subhyperplane instances
- * @param <T> Subplane implementation type
+ * @param factory function used to create new hyperplane subset instances
+ * @param <T> Plane subset implementation type
* @return the result of the split operation
*/
- protected <T extends AbstractSubPlane<R>> Split<T> splitInternal(final Hyperplane<Vector3D> splitter,
- final T thisInstance, final BiFunction<Plane, HyperplaneBoundedRegion<Vector2D>, T> factory) {
+ protected <T extends PlaneSubset> Split<T> splitInternal(final Hyperplane<Vector3D> splitter,
+ final T thisInstance, final BiFunction<Plane, HyperplaneBoundedRegion<Vector2D>, T> factory) {
final Plane thisPlane = thisInstance.getPlane();
final Plane splitterPlane = (Plane) splitter;
@@ -123,7 +124,7 @@ abstract class AbstractSubPlane<R extends HyperplaneBoundedRegion<Vector2D>>
final Vector2D subspaceP1 = thisPlane.toSubspace(intersectionOrigin);
final Vector2D subspaceP2 = thisPlane.toSubspace(intersectionOrigin.add(intersection.getDirection()));
- final Line subspaceSplitter = Line.fromPoints(subspaceP1, subspaceP2, getPrecision());
+ final Line subspaceSplitter = Lines.fromPoints(subspaceP1, subspaceP2, getPrecision());
final Split<? extends HyperplaneBoundedRegion<Vector2D>> split =
thisInstance.getSubspaceRegion().split(subspaceSplitter);
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Planes.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Planes.java
new file mode 100644
index 0000000..8a4f275
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Planes.java
@@ -0,0 +1,264 @@
+/*
+ * 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.commons.geometry.euclidean.threed;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.twod.ConvexArea;
+import org.apache.commons.geometry.euclidean.twod.Vector2D;
+
+/** Class containing factory methods for constructing {@link Plane} and {@link PlaneSubset} instances.
+ */
+public final class Planes {
+
+ /** Utility class; no instantiation. */
+ private Planes() {
+ }
+
+ /**
+ * Build a plane from a point and two (on plane) vectors.
+ * @param p the provided point (on plane)
+ * @param u u vector (on plane)
+ * @param v v vector (on plane)
+ * @param precision precision context used to compare floating point values
+ * @return a new plane
+ * @throws IllegalArgumentException if the norm of the given values is zero, NaN, or infinite.
+ */
+ public static Plane fromPointAndPlaneVectors(final Vector3D p, final Vector3D u, final Vector3D v,
+ final DoublePrecisionContext precision) {
+ final Vector3D uNorm = u.normalize();
+ final Vector3D vNorm = uNorm.orthogonal(v);
+ final Vector3D wNorm = uNorm.cross(vNorm).normalize();
+ final double originOffset = -p.dot(wNorm);
+
+ return new Plane(uNorm, vNorm, wNorm, originOffset, precision);
+ }
+
+ /**
+ * Build a plane from a normal.
+ * Chooses origin as point on plane.
+ * @param normal normal direction to the plane
+ * @param precision precision context used to compare floating point values
+ * @return a new plane
+ * @throws IllegalArgumentException if the norm of the given values is zero, NaN, or infinite.
+ */
+ public static Plane fromNormal(final Vector3D normal, final DoublePrecisionContext precision) {
+ return fromPointAndNormal(Vector3D.ZERO, normal, precision);
+ }
+
+ /**
+ * Build a plane from a point and a normal.
+ *
+ * @param p point belonging to the plane
+ * @param normal normal direction to the plane
+ * @param precision precision context used to compare floating point values
+ * @return a new plane
+ * @throws IllegalArgumentException if the norm of the given values is zero, NaN, or infinite.
+ */
+ public static Plane fromPointAndNormal(final Vector3D p, final Vector3D normal,
+ final DoublePrecisionContext precision) {
+ final Vector3D w = normal.normalize();
+ final double originOffset = -p.dot(w);
+
+ final Vector3D u = w.orthogonal();
+ final Vector3D v = w.cross(u);
+
+ return new Plane(u, v, w, originOffset, precision);
+ }
+
+ /**
+ * Build a plane from three points.
+ * <p>
+ * The plane is oriented in the direction of {@code (p2-p1) ^ (p3-p1)}
+ * </p>
+ *
+ * @param p1 first point belonging to the plane
+ * @param p2 second point belonging to the plane
+ * @param p3 third point belonging to the plane
+ * @param precision precision context used to compare floating point values
+ * @return a new plane
+ * @throws IllegalArgumentException if the points do not define a unique plane
+ */
+ public static Plane fromPoints(final Vector3D p1, final Vector3D p2, final Vector3D p3,
+ final DoublePrecisionContext precision) {
+ return fromPoints(Arrays.asList(p1, p2, p3), precision);
+ }
+
+ /** Construct a plane from a collection of points lying on the plane. The plane orientation is
+ * determined by the overall orientation of the point sequence. For example, if the points wind
+ * around the z-axis in a counter-clockwise direction, then the plane normal will point up the
+ * +z axis. If the points wind in the opposite direction, then the plane normal will point down
+ * the -z axis. The {@code u} vector for the plane is set to the first non-zero vector between
+ * points in the sequence (ie, the first direction in the path).
+ *
+ * @param pts collection of sequenced points lying on the plane
+ * @param precision precision context used to compare floating point values
+ * @return a new plane containing the given points
+ * @throws IllegalArgumentException if the given collection does not contain at least 3 points or the
+ * points do not define a unique plane
+ */
+ public static Plane fromPoints(final Collection<Vector3D> pts, final DoublePrecisionContext precision) {
+
+ if (pts.size() < 3) {
+ throw new IllegalArgumentException("At least 3 points are required to define a plane; " +
+ "argument contains only " + pts.size() + ".");
+ }
+
+ final Iterator<Vector3D> it = pts.iterator();
+
+ final Vector3D startPt = it.next();
+
+ Vector3D u = null;
+ Vector3D w = null;
+
+ Vector3D currentPt;
+ Vector3D prevPt = startPt;
+
+ Vector3D currentVector = null;
+ Vector3D prevVector = null;
+
+ Vector3D cross = null;
+ double crossNorm;
+ double crossSumX = 0.0;
+ double crossSumY = 0.0;
+ double crossSumZ = 0.0;
+
+ boolean nonPlanar = false;
+
+ while (it.hasNext()) {
+ currentPt = it.next();
+
+ if (!currentPt.eq(prevPt, precision)) {
+ currentVector = startPt.vectorTo(currentPt);
+
+ if (u == null) {
+ // save the first non-zero vector as our u vector
+ u = currentVector.normalize();
+ }
+ if (prevVector != null) {
+ cross = prevVector.cross(currentVector);
+
+ crossSumX += cross.getX();
+ crossSumY += cross.getY();
+ crossSumZ += cross.getZ();
+
+ crossNorm = cross.norm();
+
+ if (!precision.eqZero(crossNorm)) {
+ // the cross product has non-zero magnitude
+ if (w == null) {
+ // save the first non-zero cross product as our normal
+ w = cross.normalize();
+ } else if (!precision.eq(1.0, Math.abs(w.dot(cross) / crossNorm))) {
+ // if the normalized dot product is not either +1 or -1, then
+ // the points are not coplanar
+ nonPlanar = true;
+ break;
+ }
+ }
+ }
+
+ prevVector = currentVector;
+ prevPt = currentPt;
+ }
+ }
+
+ if (u == null || w == null || nonPlanar) {
+ throw new IllegalArgumentException("Points do not define a plane: " + pts);
+ }
+
+ if (w.dot(Vector3D.of(crossSumX, crossSumY, crossSumZ)) < 0) {
+ w = w.negate();
+ }
+
+ final Vector3D v = w.cross(u);
+ final double originOffset = -startPt.dot(w);
+
+ return new Plane(u, v, w, originOffset, precision);
+ }
+
+ /** Create a new plane subset from a plane and an embedded convex subspace area.
+ * @param plane embedding plane for the area
+ * @param area area embedded in the plane
+ * @return a new convex sub plane instance
+ */
+ public static PlaneConvexSubset subsetFromConvexArea(final Plane plane, final ConvexArea area) {
+ return new PlaneConvexSubset(plane, area);
+ }
+
+ /** Create a new plane subset from the given sequence of points. The points must define a unique plane,
+ * meaning that at least 3 unique vertices must be given. In contrast with the
+ * {@link #subsetFromVertices(Collection, DoublePrecisionContext)} method, the first point in the sequence
+ * is included at the end if needed, in order to form a closed loop.
+ * @param pts collection of points defining the plane subset
+ * @param precision precision context used to compare floating point values
+ * @return a new plane subset defined by the given sequence of vertices
+ * @throws IllegalArgumentException if fewer than 3 vertices are given or the vertices do not define a
+ * unique plane
+ * @see #subsetFromVertices(Collection, boolean, DoublePrecisionContext)
+ * @see #fromPoints(Collection, DoublePrecisionContext)
+ */
+ public static PlaneConvexSubset subsetFromVertexLoop(final Collection<Vector3D> pts,
+ final DoublePrecisionContext precision) {
+ return subsetFromVertices(pts, true, precision);
+ }
+
+ /** Create a new plane subset from the given sequence of points. The points must define a unique plane,
+ * meaning that at least 3 unique vertices must be given.
+ * @param pts collection of points defining the plane subset
+ * @param precision precision context used to compare floating point values
+ * @return a new plane subset defined by the given sequence of vertices
+ * @throws IllegalArgumentException if fewer than 3 vertices are given or the vertices do not define a
+ * unique plane
+ * @see #subsetFromVertexLoop(Collection, DoublePrecisionContext)
+ * @see #subsetFromVertices(Collection, boolean, DoublePrecisionContext)
+ * @see #fromPoints(Collection, DoublePrecisionContext)
+ */
+ public static PlaneConvexSubset subsetFromVertices(final Collection<Vector3D> pts,
+ final DoublePrecisionContext precision) {
+ return subsetFromVertices(pts, false, precision);
+ }
+
+ /** Create a new plane subset from the given sequence of points. The points must define a unique plane,
+ * meaning that at least 3 unique vertices must be given. If {@code close} is true, the vertices are made
+ * into a closed loop by including the start point at the end if needed.
+ * @param pts collection of points
+ * @param close if true, the point sequence will implicitly include the start point again at the end; otherwise
+ * the vertex sequence is taken as-is
+ * @param precision precision context used to compare floating point values
+ * @return a new plane subset instance
+ * @throws IllegalArgumentException if fewer than 3 vertices are given or the vertices do not define a
+ * unique plane
+ * @see #subsetFromVertexLoop(Collection, DoublePrecisionContext)
+ * @see #subsetFromVertices(Collection, boolean, DoublePrecisionContext)
+ * @see #fromPoints(Collection, DoublePrecisionContext)
+ */
+ public static PlaneConvexSubset subsetFromVertices(final Collection<Vector3D> pts, final boolean close,
+ final DoublePrecisionContext precision) {
+
+ final Plane plane = Planes.fromPoints(pts, precision);
+
+ final List<Vector2D> subspacePts = plane.toSubspace(pts);
+ final ConvexArea area = ConvexArea.fromVertices(subspacePts, close, precision);
+
+ return new PlaneConvexSubset(plane, area);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3D.java
index 8e6e9c2..177ded8 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/RegionBSPTree3D.java
@@ -22,12 +22,15 @@ import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
import org.apache.commons.geometry.core.partitioning.Split;
-import org.apache.commons.geometry.core.partitioning.SubHyperplane;
import org.apache.commons.geometry.core.partitioning.bsp.AbstractBSPTree;
import org.apache.commons.geometry.core.partitioning.bsp.AbstractRegionBSPTree;
import org.apache.commons.geometry.core.partitioning.bsp.BSPTreeVisitor;
import org.apache.commons.geometry.core.partitioning.bsp.RegionCutBoundary;
+import org.apache.commons.geometry.euclidean.threed.line.Line3D;
+import org.apache.commons.geometry.euclidean.threed.line.LineConvexSubset3D;
+import org.apache.commons.geometry.euclidean.threed.line.LinecastPoint3D;
import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
import org.apache.commons.geometry.euclidean.twod.Vector2D;
@@ -35,7 +38,7 @@ import org.apache.commons.geometry.euclidean.twod.Vector2D;
* Euclidean space.
*/
public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, RegionBSPTree3D.RegionNode3D>
- implements BoundarySource3D, Linecastable3D {
+ implements BoundarySource3D {
/** Create a new, empty region. */
public RegionBSPTree3D() {
@@ -64,20 +67,20 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
/** {@inheritDoc} */
@Override
- public Iterable<ConvexSubPlane> boundaries() {
- return createBoundaryIterable(b -> (ConvexSubPlane) b);
+ public Iterable<PlaneConvexSubset> boundaries() {
+ return createBoundaryIterable(b -> (PlaneConvexSubset) b);
}
/** {@inheritDoc} */
@Override
- public Stream<ConvexSubPlane> boundaryStream() {
+ public Stream<PlaneConvexSubset> boundaryStream() {
return StreamSupport.stream(boundaries().spliterator(), false);
}
/** {@inheritDoc} */
@Override
- public List<ConvexSubPlane> getBoundaries() {
- return createBoundaryList(b -> (ConvexSubPlane) b);
+ public List<PlaneConvexSubset> getBoundaries() {
+ return createBoundaryList(b -> (PlaneConvexSubset) b);
}
/** Return a list of {@link ConvexVolume}s representing the same region
@@ -144,8 +147,8 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
/** {@inheritDoc} */
@Override
- public List<LinecastPoint3D> linecast(final Segment3D segment) {
- final LinecastVisitor visitor = new LinecastVisitor(segment, false);
+ public List<LinecastPoint3D> linecast(final LineConvexSubset3D subset) {
+ final LinecastVisitor visitor = new LinecastVisitor(subset, false);
accept(visitor);
return visitor.getResults();
@@ -153,8 +156,8 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
/** {@inheritDoc} */
@Override
- public LinecastPoint3D linecastFirst(final Segment3D segment) {
- final LinecastVisitor visitor = new LinecastVisitor(segment, true);
+ public LinecastPoint3D linecastFirst(final LineConvexSubset3D subset) {
+ final LinecastVisitor visitor = new LinecastVisitor(subset, true);
accept(visitor);
return visitor.getFirstResult();
@@ -202,7 +205,7 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
* @return a new tree instance constructed from the given boundaries
* @see #from(Iterable, boolean)
*/
- public static RegionBSPTree3D from(final Iterable<ConvexSubPlane> boundaries) {
+ public static RegionBSPTree3D from(final Iterable<PlaneConvexSubset> boundaries) {
return from(boundaries, false);
}
@@ -213,7 +216,7 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
* @param full if true, the initial tree will contain the entire space
* @return a new tree instance constructed from the given boundaries
*/
- public static RegionBSPTree3D from(final Iterable<ConvexSubPlane> boundaries, final boolean full) {
+ public static RegionBSPTree3D from(final Iterable<PlaneConvexSubset> boundaries, final boolean full) {
final RegionBSPTree3D tree = new RegionBSPTree3D(full);
tree.insert(boundaries);
@@ -349,9 +352,9 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
* @param boundary node cut boundary
* @param reverse if true, the boundary contribution is reversed before being added to the total.
*/
- private void addBoundaryContribution(final SubHyperplane<Vector3D> boundary, boolean reverse) {
- final SubPlane subplane = (SubPlane) boundary;
- final RegionBSPTree2D base = subplane.getSubspaceRegion();
+ private void addBoundaryContribution(final HyperplaneSubset<Vector3D> boundary, boolean reverse) {
+ final EmbeddedTreePlaneSubset boundarySubset = (EmbeddedTreePlaneSubset) boundary;
+ final RegionBSPTree2D base = boundarySubset.getSubspaceRegion();
final double area = base.getSize();
final Vector2D baseBarycenter = base.getBarycenter();
@@ -359,7 +362,7 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
if (Double.isInfinite(area)) {
volumeSum = Double.POSITIVE_INFINITY;
} else if (baseBarycenter != null) {
- final Plane plane = subplane.getPlane();
+ final Plane plane = boundarySubset.getPlane();
final Vector3D facetBarycenter = plane.toSpace(base.getBarycenter());
// the volume here is actually 3x the actual pyramid volume; we'll apply
@@ -382,8 +385,8 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
*/
private static final class LinecastVisitor implements BSPTreeVisitor<Vector3D, RegionNode3D> {
- /** The line segment to intersect with the boundaries of the BSP tree. */
- private final Segment3D linecastSegment;
+ /** The line subset to intersect with the boundaries of the BSP tree. */
+ private final LineConvexSubset3D linecastSubset;
/** If true, the visitor will stop visiting the tree once the first linecast
* point is determined.
@@ -396,13 +399,13 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
/** List of results from the linecast operation. */
private final List<LinecastPoint3D> results = new ArrayList<>();
- /** Create a new instance with the given intersecting line segment.
- * @param linecastSegment segment to intersect with the BSP tree region boundary
+ /** Create a new instance with the given intersecting line convex subset.
+ * @param linecastSubset line subset to intersect with the BSP tree region boundary
* @param firstOnly if true, the visitor will stop visiting the tree once the first
* linecast point is determined
*/
- LinecastVisitor(final Segment3D linecastSegment, final boolean firstOnly) {
- this.linecastSegment = linecastSegment;
+ LinecastVisitor(final LineConvexSubset3D linecastSubset, final boolean firstOnly) {
+ this.linecastSubset = linecastSubset;
this.firstOnly = firstOnly;
}
@@ -431,7 +434,7 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
@Override
public Order visitOrder(final RegionNode3D internalNode) {
final Plane cut = (Plane) internalNode.getCutHyperplane();
- final Line3D line = linecastSegment.getLine();
+ final Line3D line = linecastSubset.getLine();
final boolean plusIsNear = line.getDirection().dot(cut.getNormal()) < 0;
@@ -444,8 +447,8 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
@Override
public Result visit(final RegionNode3D node) {
if (node.isInternal()) {
- // check if the line segment intersects the cut subhyperplane
- final Line3D line = linecastSegment.getLine();
+ // check if the line subset intersects the node cut hyperplane
+ final Line3D line = linecastSubset.getLine();
final Vector3D pt = ((Plane) node.getCutHyperplane()).intersection(line);
if (pt != null) {
@@ -454,7 +457,7 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
// we have results and we are now sure that no other intersection points will be
// found that are closer or at the same position on the intersecting line.
return Result.TERMINATE;
- } else if (linecastSegment.contains(pt)) {
+ } else if (linecastSubset.contains(pt)) {
// we've potentially found a new linecast point; add it to the list of potential
// results
final LinecastPoint3D potentialResult = computeLinecastPoint(pt, node);
@@ -474,8 +477,7 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
/** Compute the linecast point for the given intersection point and tree node, returning null
* if the point does not actually lie on the region boundary.
* @param pt intersection point
- * @param node node containing the cut subhyperplane that the linecast line
- * intersected with
+ * @param node node containing the cut that the linecast line intersected with
* @return a new linecast point instance or null if the intersection point does not lie
* on the region boundary
*/
@@ -501,7 +503,7 @@ public final class RegionBSPTree3D extends AbstractRegionBSPTree<Vector3D, Regio
normal = normal.negate();
}
- return new LinecastPoint3D(pt, normal, linecastSegment.getLine());
+ return new LinecastPoint3D(pt, normal, linecastSubset.getLine());
}
return null;
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Segment3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Segment3D.java
deleted file mode 100644
index e94ceef..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Segment3D.java
+++ /dev/null
@@ -1,267 +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.commons.geometry.euclidean.threed;
-
-import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
-import org.apache.commons.geometry.euclidean.oned.Interval;
-import org.apache.commons.geometry.euclidean.oned.Vector1D;
-import org.apache.commons.geometry.euclidean.threed.Line3D.SubspaceTransform;
-
-/** Class representing a line segment in 3 dimensional Euclidean space.
- *
- * <p>This class is guaranteed to be immutable.</p>
- */
-public final class Segment3D extends AbstractSubLine3D<Interval> {
- /** String used to indicate the start point of the segment in the toString() representation. */
- private static final String START_STR = "start= ";
-
- /** String used to indicate the direction the segment in the toString() representation. */
- private static final String DIR_STR = "direction= ";
-
- /** String used to indicate the end point of the segment in the toString() representation. */
- private static final String END_STR = "end= ";
-
- /** String used as a separator value in the toString() representation. */
- private static final String SEP_STR = ", ";
-
- /** The interval representing the region of the line contained in
- * the line segment.
- */
- private final Interval interval;
-
- /** Construct a line segment from an underlying line and a 1D interval
- * on it.
- * @param line the underlying line
- * @param interval 1D interval on the line defining the line segment
- */
- private Segment3D(final Line3D line, final Interval interval) {
- super(line);
-
- this.interval = interval;
- }
-
- /** Get the start value in the 1D subspace of the line.
- * @return the start value in the 1D subspace of the line.
- */
- public double getSubspaceStart() {
- return interval.getMin();
- }
-
- /** Get the end value in the 1D subspace of the line.
- * @return the end value in the 1D subspace of the line
- */
- public double getSubspaceEnd() {
- return interval.getMax();
- }
-
- /** Get the start point of the line segment or null if no start point
- * exists (ie, the segment is infinite).
- * @return the start point of the line segment or null if no start point
- * exists
- */
- public Vector3D getStartPoint() {
- return interval.hasMinBoundary() ? getLine().toSpace(interval.getMin()) : null;
- }
-
- /** Get the end point of the line segment or null if no end point
- * exists (ie, the segment is infinite).
- * @return the end point of the line segment or null if no end point
- * exists
- */
- public Vector3D getEndPoint() {
- return interval.hasMaxBoundary() ? getLine().toSpace(interval.getMax()) : null;
- }
-
- /** Return true if the segment is infinite.
- * @return true if the segment is infinite.
- */
- public boolean isInfinite() {
- return interval.isInfinite();
- }
-
- /** Return true if the segment is finite.
- * @return true if the segment is finite.
- */
- public boolean isFinite() {
- return interval.isFinite();
- }
-
- /** Return the 1D interval for the line segment.
- * @return the 1D interval for the line segment
- * @see #getSubspaceRegion()
- */
- public Interval getInterval() {
- return interval;
- }
-
- /** {@inheritDoc}
- *
- * <p>This is an alias for {@link #getInterval()}.</p>
- */
- @Override
- public Interval getSubspaceRegion() {
- return getInterval();
- }
-
- /** Return true if the given point lies in the segment.
- * @param pt point to check
- * @return true if the point lies in the segment
- */
- public boolean contains(final Vector3D pt) {
- final Line3D line = getLine();
- return line.contains(pt) && interval.contains(line.toSubspace(pt));
- }
-
- /** Transform this instance.
- * @param transform the transform to apply
- * @return a new, transformed instance
- */
- public Segment3D transform(final Transform<Vector3D> transform) {
- final SubspaceTransform st = getLine().subspaceTransform(transform);
-
- return new Segment3D(st.getLine(), interval.transform(st.getTransform()));
- }
-
- /** Return a string representation of the segment.
- *
- * <p>In order to keep the representation short but informative, the exact format used
- * depends on the properties of the instance, as demonstrated in the examples
- * below.
- * <ul>
- * <li>Infinite segment -
- * {@code "Segment3D[lineOrigin= (0.0, 0.0, 0.0), lineDirection= (1.0, 0.0, 0.0)]}"</li>
- * <li>Start point but no end point -
- * {@code "Segment3D[start= (0.0, 0.0, 0.0), direction= (1.0, 0.0, 0.0)]}"</li>
- * <li>End point but no start point -
- * {@code "Segment3D[direction= (1.0, 0.0, 0.0), end= (0.0, 0.0, 0.0)]}"</li>
- * <li>Start point and end point -
- * {@code "Segment3D[start= (0.0, 0.0, 0.0), end= (1.0, 0.0, 0.0)]}"</li>
- * </ul>
- */
- @Override
- public String toString() {
- final Vector3D startPoint = getStartPoint();
- final Vector3D endPoint = getEndPoint();
-
- final StringBuilder sb = new StringBuilder();
- sb.append(this.getClass().getSimpleName())
- .append('[');
-
- if (startPoint != null && endPoint != null) {
- sb.append(START_STR)
- .append(startPoint)
- .append(SEP_STR)
- .append(END_STR)
- .append(endPoint);
- } else if (startPoint != null) {
- sb.append(START_STR)
- .append(startPoint)
- .append(SEP_STR)
- .append(DIR_STR)
- .append(getLine().getDirection());
- } else if (endPoint != null) {
- sb.append(DIR_STR)
- .append(getLine().getDirection())
- .append(SEP_STR)
- .append(END_STR)
- .append(endPoint);
- } else {
- final Line3D line = getLine();
-
- sb.append("lineOrigin= ")
- .append(line.getOrigin())
- .append(SEP_STR)
- .append("lineDirection= ")
- .append(line.getDirection());
- }
-
- sb.append(']');
-
- return sb.toString();
- }
-
- /** Create a line segment between two points. The underlying line points in the direction from {@code start}
- * to {@code end}.
- * @param start start point for the line segment
- * @param end end point for the line segment
- * @param precision precision context used to determine floating point equality
- * @return a new line segment between {@code start} and {@code end}.
- */
- public static Segment3D fromPoints(final Vector3D start, final Vector3D end,
- final DoublePrecisionContext precision) {
-
- final Line3D line = Line3D.fromPoints(start, end, precision);
- return fromPointsOnLine(line, start, end);
- }
-
- /** Construct a line segment from a starting point and a direction that the line should extend to
- * infinity from. This is equivalent to constructing a ray.
- * @param start start point for the segment
- * @param direction direction that the line should extend from the segment
- * @param precision precision context used to determine floating point equality
- * @return a new line segment starting from the given point and extending to infinity in the
- * specified direction
- */
- public static Segment3D fromPointAndDirection(final Vector3D start, final Vector3D direction,
- final DoublePrecisionContext precision) {
- final Line3D line = Line3D.fromPointAndDirection(start, direction, precision);
- return fromInterval(line, Interval.min(line.toSubspace(start).getX(), precision));
- }
-
- /** Create a line segment from an underlying line and a 1D interval on the line.
- * @param line the line that the line segment will belong to
- * @param interval 1D interval on the line
- * @return a line segment defined by the given line and interval
- */
- public static Segment3D fromInterval(final Line3D line, final Interval interval) {
- return new Segment3D(line, interval);
- }
-
- /** Create a line segment from an underlying line and a 1D interval on the line.
- * @param line the line that the line segment will belong to
- * @param a first 1D location on the line
- * @param b second 1D location on the line
- * @return a line segment defined by the given line and interval
- */
- public static Segment3D fromInterval(final Line3D line, final double a, final double b) {
- return fromInterval(line, Interval.of(a, b, line.getPrecision()));
- }
-
- /** Create a line segment from an underlying line and a 1D interval on the line.
- * @param line the line that the line segment will belong to
- * @param a first 1D point on the line; must not be null
- * @param b second 1D point on the line; must not be null
- * @return a line segment defined by the given line and interval
- */
- public static Segment3D fromInterval(final Line3D line, final Vector1D a, final Vector1D b) {
- return fromInterval(line, a.getX(), b.getX());
- }
-
- /** Create a new line segment from a line and points known to lie on the line.
- * @param line the line that the line segment will belong to
- * @param start line segment start point known to lie on the line
- * @param end line segment end poitn known to lie on the line
- * @return a new line segment created from the line and points
- */
- private static Segment3D fromPointsOnLine(final Line3D line, final Vector3D start, final Vector3D end) {
- final double subspaceStart = line.toSubspace(start).getX();
- final double subspaceEnd = line.toSubspace(end).getX();
-
- return fromInterval(line, subspaceStart, subspaceEnd);
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/EmbeddedTreeLineSubset3D.java
similarity index 61%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine3D.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/EmbeddedTreeLineSubset3D.java
index 925da52..8d5188c 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SubLine3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/EmbeddedTreeLineSubset3D.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.euclidean.threed;
+package org.apache.commons.geometry.euclidean.threed.line;
import java.util.ArrayList;
import java.util.List;
@@ -22,40 +22,42 @@ import java.util.List;
import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.euclidean.oned.Interval;
import org.apache.commons.geometry.euclidean.oned.RegionBSPTree1D;
-import org.apache.commons.geometry.euclidean.threed.Line3D.SubspaceTransform;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.geometry.euclidean.threed.line.Line3D.SubspaceTransform;
-/** Class representing an arbitrary region of a 3 dimensional line. This class can represent
- * both convex and non-convex regions of its underlying line.
+/** Class representing an arbitrary subset of a line in 3D Euclidean space using a
+ * {@link RegionBSPTree1D}. This class can represent convex, non-convex, finite,
+ * infinite, and empty regions.
*
* <p>This class is mutable and <em>not</em> thread safe.</p>
*/
-public final class SubLine3D extends AbstractSubLine3D<RegionBSPTree1D> {
+public final class EmbeddedTreeLineSubset3D extends LineSubset3D {
/** The 1D region representing the area on the line. */
private final RegionBSPTree1D region;
- /** Construct a new, empty subline for the given line.
- * @param line line defining the subline
+ /** Construct a new, empty subset for the given line.
+ * @param line line defining the subset
*/
- public SubLine3D(final Line3D line) {
+ public EmbeddedTreeLineSubset3D(final Line3D line) {
this(line, false);
}
- /** Construct a new subline for the given line. If {@code full}
- * is true, then the subline will cover the entire line; otherwise,
+ /** Construct a new subset for the given line. If {@code full}
+ * is true, then the subset will cover the entire line; otherwise,
* it will be empty.
- * @param line line defining the subline
- * @param full if true, the subline will cover the entire space;
+ * @param line line defining the subset
+ * @param full if true, the subset will cover the entire space;
* otherwise it will be empty
*/
- public SubLine3D(final Line3D line, boolean full) {
+ public EmbeddedTreeLineSubset3D(final Line3D line, boolean full) {
this(line, new RegionBSPTree1D(full));
}
/** Construct a new instance from its defining line and subspace region.
- * @param line line defining the subline
- * @param region subspace region for the subline
+ * @param line line defining the subset
+ * @param region subspace region for the subset
*/
- public SubLine3D(final Line3D line, final RegionBSPTree1D region) {
+ public EmbeddedTreeLineSubset3D(final Line3D line, final RegionBSPTree1D region) {
super(line);
this.region = region;
@@ -65,32 +67,32 @@ public final class SubLine3D extends AbstractSubLine3D<RegionBSPTree1D> {
* @param transform the transform to apply
* @return a new, transformed instance
*/
- public SubLine3D transform(final Transform<Vector3D> transform) {
+ public EmbeddedTreeLineSubset3D transform(final Transform<Vector3D> transform) {
final SubspaceTransform st = getLine().subspaceTransform(transform);
final RegionBSPTree1D tRegion = RegionBSPTree1D.empty();
tRegion.copy(region);
tRegion.transform(st.getTransform());
- return new SubLine3D(st.getLine(), tRegion);
+ return new EmbeddedTreeLineSubset3D(st.getLine(), tRegion);
}
- /** Return a list of {@link Segment3D} instances representing the same region
- * as this subline.
- * @return a list of {@link Segment3D} instances representing the same region
+ /** Return a list of {@link LineConvexSubset3D} instances representing the same region
+ * as this instance.
+ * @return a list of {@link LineConvexSubset3D} instances representing the same region
* as this instance.
*/
- public List<Segment3D> toConvex() {
+ public List<LineConvexSubset3D> toConvex() {
final List<Interval> intervals = region.toIntervals();
final Line3D line = getLine();
- final List<Segment3D> segments = new ArrayList<>(intervals.size());
+ final List<LineConvexSubset3D> convex = new ArrayList<>(intervals.size());
for (final Interval interval : intervals) {
- segments.add(Segment3D.fromInterval(line, interval));
+ convex.add(Lines3D.subsetFromInterval(line, interval));
}
- return segments;
+ return convex;
}
/** {@inheritDoc} */
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Line3D.java
similarity index 74%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line3D.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Line3D.java
index c44d9ff..12d5743 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Line3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Line3D.java
@@ -14,22 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.euclidean.threed;
+package org.apache.commons.geometry.euclidean.threed.line;
+import java.text.MessageFormat;
import java.util.Objects;
import org.apache.commons.geometry.core.Embedding;
import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.euclidean.oned.AffineTransformMatrix1D;
-import org.apache.commons.geometry.euclidean.oned.Interval;
import org.apache.commons.geometry.euclidean.oned.Vector1D;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
/** Class representing a line in 3D space.
*
* <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see Lines3D
*/
public final class Line3D implements Embedding<Vector3D, Vector1D> {
+
+ /** Format string for creating line string representations. */
+ static final String TO_STRING_FORMAT = "{0}[origin= {1}, direction= {2}]";
+
/** Line point closest to the origin. */
private final Vector3D origin;
@@ -45,7 +51,7 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
* @param direction the direction of the line
* @param precision precision context used to compare floating point numbers
*/
- private Line3D(final Vector3D origin, final Vector3D direction, final DoublePrecisionContext precision) {
+ Line3D(final Vector3D origin, final Vector3D direction, final DoublePrecisionContext precision) {
this.origin = origin;
this.direction = direction;
this.precision = precision;
@@ -89,7 +95,7 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
final Vector3D p1 = transform.apply(origin);
final Vector3D p2 = transform.apply(origin.add(direction));
- return fromPoints(p1, p2, precision);
+ return Lines3D.fromPoints(p1, p2, precision);
}
/** Get an object containing the current line transformed by the argument along with a
@@ -118,7 +124,7 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
final Vector3D p1 = transform.apply(origin);
final Vector3D p2 = transform.apply(origin.add(direction));
- final Line3D tLine = fromPoints(p1, p2, precision);
+ final Line3D tLine = Lines3D.fromPoints(p1, p2, precision);
final Vector1D tSubspaceOrigin = tLine.toSubspace(p1);
final Vector1D tSubspaceDirection = tSubspaceOrigin.vectorTo(tLine.toSubspace(p2));
@@ -137,12 +143,12 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
* 2D space). Abscissa values increase in the direction of the line. This method
* is exactly equivalent to {@link #toSubspace(Vector3D)} except that this method
* returns a double instead of a {@link Vector1D}.
- * @param point point to compute the abscissa for
+ * @param pt point to compute the abscissa for
* @return abscissa value of the point
* @see #toSubspace(Vector3D)
*/
- public double abscissa(final Vector3D point) {
- return point.subtract(origin).dot(direction);
+ public double abscissa(final Vector3D pt) {
+ return pt.subtract(origin).dot(direction);
}
/** Get one point from the line.
@@ -155,13 +161,13 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
/** {@inheritDoc} */
@Override
- public Vector1D toSubspace(Vector3D pt) {
+ public Vector1D toSubspace(final Vector3D pt) {
return Vector1D.of(abscissa(pt));
}
/** {@inheritDoc} */
@Override
- public Vector3D toSpace(Vector1D pt) {
+ public Vector3D toSpace(final Vector1D pt) {
return toSpace(pt.getX());
}
@@ -258,65 +264,85 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
return line.contains(closestPt) ? closestPt : null;
}
- /** Return a new infinite segment representing the entire line.
- * @return a new infinite segment representing the entire line
+ /** Return a new infinite line subset representing the entire line.
+ * @return a new infinite line subset representing the entire line
+ * @see Lines3D#span(Line3D)
*/
- public Segment3D span() {
- return Segment3D.fromInterval(this, Interval.full());
+ public LineConvexSubset3D span() {
+ return Lines3D.span(this);
}
- /** Create a new line segment from the given interval.
- * @param interval interval representing the 1D region for the line segment
- * @return a new line segment on this line
- */
- public Segment3D segment(final Interval interval) {
- return Segment3D.fromInterval(this, interval);
- }
-
- /** Create a new line segment from the given interval.
+ /** Create a new line segment from the given 1D interval. The returned line
+ * segment consists of all points between the two locations, regardless of the order the
+ * arguments are given.
* @param a first 1D location for the interval
* @param b second 1D location for the interval
* @return a new line segment on this line
+ * @throws IllegalArgumentException if either of the locations is NaN or infinite
+ * @see Lines3D#segmentFromLocations(Line3D, double, double)
*/
public Segment3D segment(final double a, final double b) {
- return Segment3D.fromInterval(this, a, b);
+ return Lines3D.segmentFromLocations(this, a, b);
}
- /** Create a new line segment between the projections of the two
- * given points onto this line.
+ /** Create a new line segment from two points. The returned segment represents all points on this line
+ * between the projected locations of {@code a} and {@code b}. The points may be given in any order.
* @param a first point
* @param b second point
* @return a new line segment on this line
+ * @throws IllegalArgumentException if either point contains NaN or infinite coordinate values
+ * @see Lines3D#segmentFromPoints(Line3D, Vector3D, Vector3D)
*/
public Segment3D segment(final Vector3D a, final Vector3D b) {
- return Segment3D.fromInterval(this, toSubspace(a), toSubspace(b));
+ return Lines3D.segmentFromPoints(this, a, b);
}
- /** Create a new line segment that starts at infinity and continues along
- * the line up to the projection of the given point.
- * @param pt point defining the end point of the line segment; the end point
+ /** Create a new line convex subset that starts at infinity and continues along
+ * the line up to the projection of the given end point.
+ * @param endPoint point defining the end point of the line subset; the end point
* is equal to the projection of this point onto the line
- * @return a new, half-open line segment
+ * @return a new, half-open line subset that ends at the given point
+ * @throws IllegalArgumentException if any coordinate in {@code endPoint} is NaN or infinite
+ * @see Lines3D#reverseRayFromPoint(Line3D, Vector3D)
+ */
+ public ReverseRay3D reverseRayTo(final Vector3D endPoint) {
+ return Lines3D.reverseRayFromPoint(this, endPoint);
+ }
+
+ /** Create a new line convex subset that starts at infinity and continues along
+ * the line up to the given 1D location.
+ * @param endLocation the 1D location of the end of the half-line
+ * @return a new, half-open line subset that ends at the given 1D location
+ * @throws IllegalArgumentException if {@code endLocation} is NaN or infinite
+ * @see Lines3D#reverseRayFromLocation(Line3D, double)
*/
- public Segment3D segmentTo(final Vector3D pt) {
- return segment(Double.NEGATIVE_INFINITY, toSubspace(pt).getX());
+ public ReverseRay3D reverseRayTo(final double endLocation) {
+ return Lines3D.reverseRayFromLocation(this, endLocation);
}
- /** Create a new line segment that starts at the projection of the given point
- * and continues in the direction of the line to infinity, similar to a ray.
- * @param pt point defining the start point of the line segment; the start point
+ /** Create a new ray instance that starts at the projection of the given point
+ * and continues in the direction of the line to infinity.
+ * @param startPoint point defining the start point of the ray; the start point
* is equal to the projection of this point onto the line
- * @return a new, half-open line segment
+ * @return a ray starting at the projected point and extending along this line
+ * to infinity
+ * @throws IllegalArgumentException if any coordinate in {@code startPoint} is NaN or infinite
+ * @see Lines3D#rayFromPoint(Line3D, Vector3D)
*/
- public Segment3D segmentFrom(final Vector3D pt) {
- return segment(toSubspace(pt).getX(), Double.POSITIVE_INFINITY);
+ public Ray3D rayFrom(final Vector3D startPoint) {
+ return Lines3D.rayFromPoint(this, startPoint);
}
- /** Create a new, empty subline based on this line.
- * @return a new, empty subline based on this line
+ /** Create a new ray instance that starts at the given 1D location and continues in
+ * the direction of the line to infinity.
+ * @param startLocation 1D location defining the start point of the ray
+ * @return a ray starting at the given 1D location and extending along this line
+ * to infinity
+ * @throws IllegalArgumentException if {@code startLocation} is NaN or infinite
+ * @see Lines3D#rayFromLocation(Line3D, double)
*/
- public SubLine3D subline() {
- return new SubLine3D(this);
+ public Ray3D rayFrom(final double startLocation) {
+ return Lines3D.rayFromLocation(this, startLocation);
}
/** Return true if this instance should be considered equivalent to the argument, using the
@@ -356,46 +382,10 @@ public final class Line3D implements Embedding<Vector3D, Vector1D> {
/** {@inheritDoc} */
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append(getClass().getSimpleName())
- .append("[origin= ")
- .append(origin)
- .append(", direction= ")
- .append(direction)
- .append("]");
-
- return sb.toString();
- }
-
- /** Create a new line instance from two points that lie on the line. The line
- * direction points from the first point to the second point.
- * @param p1 first point on the line
- * @param p2 second point on the line
- * @param precision floating point precision context
- * @return a new line instance that contains both of the given point and that has
- * a direction going from the first point to the second point
- * @throws IllegalArgumentException if the points lie too close to reate a non-zero direction vector
- */
- public static Line3D fromPoints(final Vector3D p1, final Vector3D p2,
- final DoublePrecisionContext precision) {
- return fromPointAndDirection(p1, p1.directionTo(p2), precision);
- }
-
- /** Create a new line instance from a point and a direction.
- * @param pt a point lying on the line
- * @param direction the direction of the line
- * @param precision floating point precision context
- * @return a new line instance that contains the given point and points in the
- * given direction
- * @throws IllegalArgumentException if the direction cannot be normalized
- */
- public static Line3D fromPointAndDirection(final Vector3D pt, final Vector3D direction,
- final DoublePrecisionContext precision) {
-
- final Vector3D normDirection = direction.normalize();
- final Vector3D origin = pt.reject(normDirection);
-
- return new Line3D(origin, normDirection, precision);
+ return MessageFormat.format(TO_STRING_FORMAT,
+ getClass().getSimpleName(),
+ getOrigin(),
+ getDirection());
}
/** Class containing a transformed line instance along with a subspace (1D) transform. The subspace
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineConvexSubset3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineConvexSubset3D.java
new file mode 100644
index 0000000..e205b16
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineConvexSubset3D.java
@@ -0,0 +1,115 @@
+/*
+ * 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.commons.geometry.euclidean.threed.line;
+
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.euclidean.oned.Interval;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
+/** Class representing a convex subset of a line in 3D Euclidean space. Instances
+ * need not be finite, in which case the start or end point (or both) will be null.
+ * @see Lines3D
+ */
+public abstract class LineConvexSubset3D extends LineSubset3D {
+
+ /** Construct a new instance for the given line.
+ * @param line line containing this convex subset
+ */
+ LineConvexSubset3D(final Line3D line) {
+ super(line);
+ }
+
+ /** Return true if the line subset is infinite.
+ * @return true if the line subset is infinite.
+ */
+ @Override
+ public abstract boolean isInfinite();
+
+ /** Return true if the line subset is finite.
+ * @return true if the line subset is finite.
+ */
+ @Override
+ public abstract boolean isFinite();
+
+ /** Get the start point for the line subset.
+ * @return the start point for the line subset, or null if no start point exists
+ */
+ public abstract Vector3D getStartPoint();
+
+ /** Get the 1D start location of the line subset or {@link Double#NEGATIVE_INFINITY} if
+ * no start location exists.
+ * @return the 1D start location of the line subset or {@link Double#NEGATIVE_INFINITY} if
+ * no start location exists.
+ */
+ public abstract double getSubspaceStart();
+
+ /** Get the end point for the line subset.
+ * @return the end point for the line subset, or null if no end point exists.
+ */
+ public abstract Vector3D getEndPoint();
+
+ /** Get the 1D end location of the line subset or {@link Double#POSITIVE_INFINITY} if
+ * no end location exists.
+ * @return the 1D end location of the line subset or {@link Double#POSITIVE_INFINITY} if
+ * no end location exists
+ */
+ public abstract double getSubspaceEnd();
+
+ /** Get the size (length) of the line subset.
+ * @return the size of the line subset
+ */
+ @Override
+ public abstract double getSize();
+
+ /** {@inheritDoc} */
+ @Override
+ public Interval getSubspaceRegion() {
+ final double start = getSubspaceStart();
+ final double end = getSubspaceEnd();
+
+ return Interval.of(start, end, getLine().getPrecision());
+ }
+
+ /** Get the 1D interval for the line subset. This method is an alias for {@link #getSubspaceRegion()}.
+ * @return the 1D interval for the line subset.
+ */
+ public Interval getInterval() {
+ return getSubspaceRegion();
+ }
+
+ /** Return true if the given point lies in the line subset.
+ * @param pt point to check
+ * @return true if the point lies in the line subset
+ */
+ public boolean contains(final Vector3D pt) {
+ final Line3D line = getLine();
+ return line.contains(pt) && containsAbscissa(line.abscissa(pt));
+ }
+
+ /** Transform this instance.
+ * @param transform the transform to apply
+ * @return a new, transformed instance
+ */
+ public abstract LineConvexSubset3D transform(Transform<Vector3D> transform);
+
+ /** Return true if the given abscissa value is contained in the line subset (ie, in the subspace region
+ * or one of its 1D boundaries).
+ * @param abscissa abscissa to check
+ * @return true if {@code abscissa} lies on the inside or boundary of the subspace region
+ */
+ abstract boolean containsAbscissa(double abscissa);
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineSpanningSubset3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineSpanningSubset3D.java
new file mode 100644
index 0000000..373e74b
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineSpanningSubset3D.java
@@ -0,0 +1,123 @@
+/*
+ * 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.commons.geometry.euclidean.threed.line;
+
+import java.text.MessageFormat;
+
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
+/** Class representing the span of a line in 3D Euclidean space. This is the set of all points
+ * contained by the line.
+ *
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ */
+final class LineSpanningSubset3D extends LineConvexSubset3D {
+
+ /** Construct a new instance for the given line.
+ * @param line line to construct the span for
+ */
+ LineSpanningSubset3D(final Line3D line) {
+ super(line);
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return true;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFinite() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSize() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector3D getStartPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#NEGATIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceStart() {
+ return Double.NEGATIVE_INFINITY;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector3D getEndPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceEnd() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public LineSpanningSubset3D transform(final Transform<Vector3D> transform) {
+ return new LineSpanningSubset3D(getLine().transform(transform));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final Line3D line = getLine();
+
+ return MessageFormat.format(Line3D.TO_STRING_FORMAT,
+ getClass().getSimpleName(),
+ line.getOrigin(),
+ line.getDirection());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ boolean containsAbscissa(final double abscissa) {
+ return true;
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineSubset3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineSubset3D.java
new file mode 100644
index 0000000..0a27e98
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LineSubset3D.java
@@ -0,0 +1,62 @@
+/*
+ * 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.commons.geometry.euclidean.threed.line;
+
+import org.apache.commons.geometry.core.RegionEmbedding;
+import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
+import org.apache.commons.geometry.euclidean.oned.Vector1D;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
+/** Class representing a subset of a line in 3D Euclidean space. For example, line segments,
+ * rays, and disjoint combinations of the two are line subsets. Line subsets may be finite or infinite.
+ */
+public abstract class LineSubset3D implements RegionEmbedding<Vector3D, Vector1D> {
+ /** The line containing this instance. */
+ private final Line3D line;
+
+ /** Construct a new instance based on the given line.
+ * @param line line containing the instance
+ */
+ LineSubset3D(final Line3D line) {
+ this.line = line;
+ }
+
+ /** Get the line containing this subset.
+ * @return the line containing this subset
+ */
+ public Line3D getLine() {
+ return line;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector3D toSpace(final Vector1D pt) {
+ return line.toSpace(pt);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector1D toSubspace(final Vector3D pt) {
+ return line.toSubspace(pt);
+ }
+
+ /** Get the subspace region for the instance.
+ * @return the subspace region for the instance
+ */
+ @Override
+ public abstract HyperplaneBoundedRegion<Vector1D> getSubspaceRegion();
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/LinecastPoint3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LinecastPoint3D.java
similarity index 97%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/LinecastPoint3D.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LinecastPoint3D.java
index 35f5d66..1e1c46d 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/LinecastPoint3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/LinecastPoint3D.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.euclidean.threed;
+package org.apache.commons.geometry.euclidean.threed.line;
import java.util.ArrayList;
import java.util.Collections;
@@ -24,6 +24,7 @@ import java.util.ListIterator;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.euclidean.AbstractLinecastPoint;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
/** Class representing intersections resulting from linecast operations in Euclidean
* 3D space. This class contains the intersection point along with the boundary normal
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Linecastable3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Linecastable3D.java
similarity index 76%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Linecastable3D.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Linecastable3D.java
index 43f2cbb..1e9cfc7 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/Linecastable3D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Linecastable3D.java
@@ -14,18 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.euclidean.threed;
+package org.apache.commons.geometry.euclidean.threed.line;
import java.util.List;
/** Interface for objects that support linecast operations in Euclidean 3D space.
*
* <p>
- * Linecasting is a process that takes a line or line segment and intersects it with
+ * Linecasting is a process that takes a line or line convex subset and intersects it with
* the boundaries of a region. This is similar to
* <a href="https://en.wikipedia.org/wiki/Ray_casting">raycasting</a> used
* for collision detection with the exception that the intersecting element can be a
- * line or line segment and not just a ray.
+ * line or line convex subset and not just a ray.
* </p>
*/
public interface Linecastable3D {
@@ -41,14 +41,14 @@ public interface Linecastable3D {
return linecast(line.span());
}
- /** Intersect the given line segment against the boundaries in this instance, returning
- * a list of all intersections in order of increasing distance along the line. An empty
- * list is returned if no intersections are discovered.
- * @param segment segment to intersect
+ /** Intersect the given line convex subset against the boundaries in this instance, returning
+ * a list of all intersections in order of increasing distance along the line. An empty list is
+ * returned if no intersections are discovered.
+ * @param subset line subset to intersect
* @return a list of computed intersections in order of increasing distance
* along the line
*/
- List<LinecastPoint3D> linecast(Segment3D segment);
+ List<LinecastPoint3D> linecast(LineConvexSubset3D subset);
/** Intersect the given line against the boundaries in this instance, returning the first
* intersection found when traveling in the direction of the line from infinity.
@@ -60,12 +60,12 @@ public interface Linecastable3D {
return linecastFirst(line.span());
}
- /** Intersect the given line segment against the boundaries in this instance, returning
- * the first intersection found when traveling in the direction of the line segment
- * from its start point.
- * @param segment segment to intersect
+ /** Intersect the given line convex subset against the boundaries in this instance, returning
+ * the first intersection found when traveling in the direction of the line subset from its
+ * start point.
+ * @param subset line subset to intersect
* @return the first intersection found or null if no intersection
* is found
*/
- LinecastPoint3D linecastFirst(Segment3D segment);
+ LinecastPoint3D linecastFirst(LineConvexSubset3D subset);
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Lines3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Lines3D.java
new file mode 100644
index 0000000..6ed1a2a
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Lines3D.java
@@ -0,0 +1,271 @@
+/*
+ * 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.commons.geometry.euclidean.threed.line;
+
+import java.text.MessageFormat;
+
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.oned.Interval;
+import org.apache.commons.geometry.euclidean.oned.Vector1D;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
+/** Class containing factory methods for constructing {@link Line3D} and {@link LineSubset3D} instances.
+ */
+public final class Lines3D {
+
+ /** Utility class; no instantiation. */
+ private Lines3D() {
+ }
+
+ /** Create a new line instance from two points that lie on the line. The line
+ * direction points from the first point to the second point.
+ * @param p1 first point on the line
+ * @param p2 second point on the line
+ * @param precision floating point precision context
+ * @return a new line instance that contains both of the given point and that has
+ * a direction going from the first point to the second point
+ * @throws IllegalArgumentException if the points lie too close to create a non-zero direction vector
+ */
+ public static Line3D fromPoints(final Vector3D p1, final Vector3D p2,
+ final DoublePrecisionContext precision) {
+ return fromPointAndDirection(p1, p1.vectorTo(p2), precision);
+ }
+
+ /** Create a new line instance from a point and a direction.
+ * @param pt a point lying on the line
+ * @param dir the direction of the line
+ * @param precision floating point precision context
+ * @return a new line instance that contains the given point and points in the
+ * given direction
+ * @throws IllegalArgumentException if {@code dir} has zero length, as evaluated by the
+ * given precision context
+ */
+ public static Line3D fromPointAndDirection(final Vector3D pt, final Vector3D dir,
+ final DoublePrecisionContext precision) {
+ if (dir.isZero(precision)) {
+ throw new IllegalArgumentException("Line direction cannot be zero");
+ }
+
+ final Vector3D normDirection = dir.normalize();
+ final Vector3D origin = pt.reject(normDirection);
+
+ return new Line3D(origin, normDirection, precision);
+ }
+
+ /** Construct a ray from a start point and a direction.
+ * @param startPoint ray start point
+ * @param direction ray direction
+ * @param precision precision context used for floating point comparisons
+ * @return a new ray instance with the given start point and direction
+ * @throws IllegalArgumentException If {@code direction} has zero length, as evaluated by the
+ * given precision context
+ * @see Lines3D#fromPointAndDirection(Vector3D, Vector3D, DoublePrecisionContext)
+ */
+ public static Ray3D rayFromPointAndDirection(final Vector3D startPoint, final Vector3D direction,
+ final DoublePrecisionContext precision) {
+ final Line3D line = Lines3D.fromPointAndDirection(startPoint, direction, precision);
+
+ return new Ray3D(line, startPoint);
+ }
+
+ /** Construct a ray starting at the given point and continuing to infinity in the direction
+ * of {@code line}. The given point is projected onto the line.
+ * @param line line for the ray
+ * @param startPoint start point for the ray
+ * @return a new ray instance starting at the given point and continuing in the direction of
+ * {@code line}
+ * @throws IllegalArgumentException if any coordinate in {@code startPoint} is NaN or infinite
+ */
+ public static Ray3D rayFromPoint(final Line3D line, final Vector3D startPoint) {
+ return rayFromLocation(line, line.abscissa(startPoint));
+ }
+
+ /** Construct a ray starting at the given 1D location on {@code line} and continuing in the
+ * direction of the line to infinity.
+ * @param line line for the ray
+ * @param startLocation 1D location of the ray start point
+ * @return a new ray instance starting at the given 1D location and continuing to infinity
+ * along {@code line}
+ * @throws IllegalArgumentException if {@code startLocation} is NaN or infinite
+ */
+ public static Ray3D rayFromLocation(final Line3D line, final double startLocation) {
+ if (!Double.isFinite(startLocation)) {
+ throw new IllegalArgumentException("Invalid ray start location: " + Double.toString(startLocation));
+ }
+
+ return new Ray3D(line, startLocation);
+ }
+
+ /** Construct a reverse ray from an end point and a line direction.
+ * @param endPoint instance end point
+ * @param lineDirection line direction
+ * @param precision precision context used for floating point comparisons
+ * @return a new reverse ray with the given end point and line direction
+ * @throws IllegalArgumentException If {@code lineDirection} has zero length, as evaluated by the
+ * given precision context
+ * @see Lines3D#fromPointAndDirection(Vector3D, Vector3D, DoublePrecisionContext)
+ */
+ public static ReverseRay3D reverseRayFromPointAndDirection(final Vector3D endPoint, final Vector3D lineDirection,
+ final DoublePrecisionContext precision) {
+ final Line3D line = Lines3D.fromPointAndDirection(endPoint, lineDirection, precision);
+
+ return new ReverseRay3D(line, endPoint);
+ }
+
+ /** Construct a reverse ray starting at infinity and continuing in the direction of {@code line}
+ * to the given end point. The point is projected onto the line.
+ * @param line line for the instance
+ * @param endPoint end point for the instance
+ * @return a new reverse ray starting at infinity and continuing along the line to {@code endPoint}
+ * @throws IllegalArgumentException if any coordinate in {@code endPoint} is NaN or infinite
+ */
+ public static ReverseRay3D reverseRayFromPoint(final Line3D line, final Vector3D endPoint) {
+ return reverseRayFromLocation(line, line.abscissa(endPoint));
+ }
+
+ /** Construct a reverse ray starting at infinity and continuing in the direction of {@code line}
+ * to the given 1D end location.
+ * @param line line for the instance
+ * @param endLocation 1D location of the instance end point
+ * @return a new reverse ray starting infinity and continuing in the direction of {@code line}
+ * to the given 1D end location
+ * @throws IllegalArgumentException if {@code endLocation} is NaN or infinite
+ */
+ public static ReverseRay3D reverseRayFromLocation(final Line3D line, final double endLocation) {
+ if (!Double.isFinite(endLocation)) {
+ throw new IllegalArgumentException("Invalid reverse ray end location: " + Double.toString(endLocation));
+ }
+
+ return new ReverseRay3D(line, endLocation);
+ }
+
+ /** Construct a new line segment from two points. A new line is created for the segment and points in the
+ * direction from {@code startPoint} to {@code endPoint}.
+ * @param startPoint segment start point
+ * @param endPoint segment end point
+ * @param precision precision context to use for floating point comparisons
+ * @return a new line segment instance with the given start and end points
+ * @throws IllegalArgumentException If the vector between {@code startPoint} and {@code endPoint} has zero length,
+ * as evaluated by the given precision context
+ * @see Lines3D#fromPoints(Vector3D, Vector3D, DoublePrecisionContext)
+ */
+ public static Segment3D segmentFromPoints(final Vector3D startPoint, final Vector3D endPoint,
+ final DoublePrecisionContext precision) {
+ final Line3D line = Lines3D.fromPoints(startPoint, endPoint, precision);
+
+ // we know that the points lie on the line and are in increasing abscissa order
+ // since they were used to create the line
+ return new Segment3D(line, startPoint, endPoint);
+ }
+
+ /** Construct a new line segment from a line and a pair of points. The returned segment represents
+ * all points on the line between the projected locations of {@code a} and {@code b}. The points may
+ * be given in any order.
+ * @param line line forming the base of the segment
+ * @param a first point
+ * @param b second point
+ * @return a new line segment representing the points between the projected locations of {@code a}
+ * and {@code b} on the given line
+ * @throws IllegalArgumentException if either point contains NaN or infinite coordinate values)
+ */
+ public static Segment3D segmentFromPoints(final Line3D line, final Vector3D a, final Vector3D b) {
+ return segmentFromLocations(line, line.abscissa(a), line.abscissa(b));
+ }
+
+ /** Construct a new line segment from a pair of 1D locations on a line. The returned line
+ * segment consists of all points between the two locations, regardless of the order the
+ * arguments are given.
+ * @param line line forming the base of the segment
+ * @param a first 1D location on the line
+ * @param b second 1D location on the line
+ * @return a new line segment representing the points between {@code a} and {@code b} on
+ * the given line
+ * @throws IllegalArgumentException if either of the locations is NaN or infinite
+ */
+ public static Segment3D segmentFromLocations(final Line3D line, final double a, final double b) {
+
+ if (Double.isFinite(a) && Double.isFinite(b)) {
+ final double min = Math.min(a, b);
+ final double max = Math.max(a, b);
+
+ return new Segment3D(line, min, max);
+ }
+
+ throw new IllegalArgumentException(
+ MessageFormat.format("Invalid line segment locations: {0}, {1}",
+ Double.toString(a), Double.toString(b)));
+ }
+
+ /** Create a {@link LineConvexSubset3D} spanning the entire line. In other words, the returned
+ * subset is infinite and contains all points on the given line.
+ * @param line the line to span
+ * @return a convex subset spanning the entire line
+ */
+ public static LineConvexSubset3D span(final Line3D line) {
+ return new LineSpanningSubset3D(line);
+ }
+
+ /** Create a line convex subset from a line and a 1D interval on the line.
+ * @param line the line containing the subset
+ * @param interval 1D interval on the line
+ * @return a line convex subset defined by the given line and interval
+ */
+ public static LineConvexSubset3D subsetFromInterval(final Line3D line, final Interval interval) {
+ return subsetFromInterval(line, interval.getMin(), interval.getMax());
+ }
+
+ /** Create a line convex subset from a line and a 1D interval on the line.
+ * @param line the line containing the subset
+ * @param a first 1D location on the line
+ * @param b second 1D location on the line
+ * @return a line convex subset defined by the given line and interval
+ */
+ public static LineConvexSubset3D subsetFromInterval(final Line3D line, final double a, final double b) {
+ final double min = Math.min(a, b);
+ final double max = Math.max(a, b);
+
+ final boolean hasMin = Double.isFinite(min);
+ final boolean hasMax = Double.isFinite(max);
+
+ if (hasMin) {
+ if (hasMax) {
+ // has both
+ return new Segment3D(line, min, max);
+ }
+ // min only
+ return new Ray3D(line, min);
+ } else if (hasMax) {
+ // max only
+ return new ReverseRay3D(line, max);
+ } else if (Double.isInfinite(min) && Double.isInfinite(max) && Double.compare(min, max) < 0) {
+ return new LineSpanningSubset3D(line);
+ }
+
+ throw new IllegalArgumentException(MessageFormat.format(
+ "Invalid line convex subset interval: {0}, {1}", Double.toString(a), Double.toString(b)));
+ }
+
+ /** Create a line convex subset from a line and a 1D interval on the line.
+ * @param line the line containing the subset
+ * @param a first 1D point on the line; must not be null
+ * @param b second 1D point on the line; must not be null
+ * @return a line convex subset defined by the given line and interval
+ */
+ public static LineConvexSubset3D subsetFromInterval(final Line3D line, final Vector1D a, final Vector1D b) {
+ return subsetFromInterval(line, a.getX(), b.getX());
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Ray3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Ray3D.java
new file mode 100644
index 0000000..4975d50
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Ray3D.java
@@ -0,0 +1,145 @@
+/*
+ * 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.commons.geometry.euclidean.threed.line;
+
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
+/** Class representing a ray in 3D Euclidean space. A ray is a portion of a line consisting of
+ * a single start point and extending to infinity along the direction of the line.
+ *
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see ReverseRay3D
+ * @see Lines3D
+ * @see <a href="https://en.wikipedia.org/wiki/Line_(geometry)#Ray">Ray</a>
+ */
+public final class Ray3D extends LineConvexSubset3D {
+
+ /** The start abscissa value for the ray. */
+ private final double start;
+
+ /** Construct a ray from a line and a start point. The start point is projected
+ * onto the line. No validation is performed.
+ * @param line line for the ray
+ * @param startPoint start point for the ray
+ */
+ Ray3D(final Line3D line, final Vector3D startPoint) {
+ this(line, line.abscissa(startPoint));
+ }
+
+ /** Construct a ray from a line and a 1D start location. No validation is performed.
+ * @param line line for the ray
+ * @param start 1D start location
+ */
+ Ray3D(final Line3D line, final double start) {
+ super(line);
+
+ this.start = start;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return true;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFinite() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSize() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ @Override
+ public Vector3D getStartPoint() {
+ return getLine().toSpace(start);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSubspaceStart() {
+ return start;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector3D getEndPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceEnd() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** Get the direction of the ray. This is a convenience method for {@code ray.getLine().getDirection()}.
+ * @return the direction of the ray
+ */
+ public Vector3D getDirection() {
+ return getLine().getDirection();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Ray3D transform(final Transform<Vector3D> transform) {
+ final Line3D tLine = getLine().transform(transform);
+ final Vector3D tStart = transform.apply(getStartPoint());
+
+ return new Ray3D(tLine, tStart);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName())
+ .append("[startPoint= ")
+ .append(getStartPoint())
+ .append(", direction= ")
+ .append(getLine().getDirection())
+ .append(']');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ boolean containsAbscissa(final double abscissa) {
+ return getLine().getPrecision().gte(abscissa, start);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/ReverseRay3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/ReverseRay3D.java
new file mode 100644
index 0000000..480efec
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/ReverseRay3D.java
@@ -0,0 +1,139 @@
+/*
+ * 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.commons.geometry.euclidean.threed.line;
+
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
+/** Class representing a portion of a line in 3D Euclidean space that starts at infinity and
+ * continues in the direction of the line up to a single end point. This is equivalent to taking a
+ * {@link Ray3D} and reversing the line direction.
+ *
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see Ray3D
+ * @see Lines3D
+ */
+public final class ReverseRay3D extends LineConvexSubset3D {
+
+ /** The abscissa of the line subset endpoint. */
+ private final double end;
+
+ /** Construct a new instance from the given line and end point. The end point is projected onto
+ * the line. No validation is performed.
+ * @param line line for the instance
+ * @param endPoint end point for the instance
+ */
+ ReverseRay3D(final Line3D line, final Vector3D endPoint) {
+ this(line, line.abscissa(endPoint));
+ }
+
+ /** Construct a new instance from the given line and 1D end location. No validation is performed.
+ * @param line line for the instance
+ * @param end end location for the instance
+ */
+ ReverseRay3D(final Line3D line, final double end) {
+ super(line);
+
+ this.end = end;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return true;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFinite() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSize() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector3D getStartPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#NEGATIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceStart() {
+ return Double.NEGATIVE_INFINITY;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector3D getEndPoint() {
+ return getLine().toSpace(end);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSubspaceEnd() {
+ return end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ReverseRay3D transform(final Transform<Vector3D> transform) {
+ final Line3D tLine = getLine().transform(transform);
+ final Vector3D tEnd = transform.apply(getEndPoint());
+
+ return new ReverseRay3D(tLine, tEnd);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName())
+ .append("[direction= ")
+ .append(getLine().getDirection())
+ .append(", endPoint= ")
+ .append(getEndPoint())
+ .append(']');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ boolean containsAbscissa(final double abscissa) {
+ return getLine().getPrecision().lte(abscissa, end);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Segment3D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Segment3D.java
new file mode 100644
index 0000000..c351c43
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/Segment3D.java
@@ -0,0 +1,141 @@
+/*
+ * 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.commons.geometry.euclidean.threed.line;
+
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.threed.Vector3D;
+
+/** Class representing a line segment in 3D Euclidean space. A line segment is a portion of
+ * a line with finite start and end points.
+ *
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see Lines3D
+ * @see <a href="https://en.wikipedia.org/wiki/Line_segment">Line Segment</a>
+ */
+public final class Segment3D extends LineConvexSubset3D {
+
+ /** Start abscissa for the segment. */
+ private final double start;
+
+ /** End abscissa for the segment. */
+ private final double end;
+
+ /** Construct a new instance from a line and two points on the line. The points are projected onto
+ * the line and must be in order of increasing abscissa. No validation is performed.
+ * @param line line for the segment
+ * @param startPoint segment start point
+ * @param endPoint segment end point
+ */
+ Segment3D(final Line3D line, final Vector3D startPoint, final Vector3D endPoint) {
+ this(line, line.abscissa(startPoint), line.abscissa(endPoint));
+ }
+
+ /** Construct a new instance from a line and two abscissa locations on the line.
+ * The abscissa locations must be in increasing order. No validation is performed.
+ * @param line line for the segment
+ * @param start abscissa start location
+ * @param end abscissa end location
+ */
+ Segment3D(final Line3D line, final double start, final double end) {
+ super(line);
+
+ this.start = start;
+ this.end = end;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isFinite() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector3D getStartPoint() {
+ return getLine().toSpace(start);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSubspaceStart() {
+ return start;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector3D getEndPoint() {
+ return getLine().toSpace(end);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSubspaceEnd() {
+ return end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSize() {
+ return end - start;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Segment3D transform(final Transform<Vector3D> transform) {
+ final Vector3D t1 = transform.apply(getStartPoint());
+ final Vector3D t2 = transform.apply(getEndPoint());
+
+ final Line3D tLine = getLine().transform(transform);
+
+ return new Segment3D(tLine, t1, t2);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName())
+ .append("[startPoint= ")
+ .append(getStartPoint())
+ .append(", endPoint= ")
+ .append(getEndPoint())
+ .append(']');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ boolean containsAbscissa(final double abscissa) {
+ final DoublePrecisionContext precision = getLine().getPrecision();
+ return precision.gte(abscissa, start) &&
+ precision.lte(abscissa, end);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/package-info.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/package-info.java
similarity index 83%
copy from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/package-info.java
copy to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/package-info.java
index 5009b79..028a331 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/package-info.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/line/package-info.java
@@ -15,6 +15,10 @@
* limitations under the License.
*/
/**
- * This package provides utilities for constructing basic 3D shapes.
+ *
+ * <p>
+ * This package provides classes and utilities for lines in 3D Euclidean space.
+ * </p>
+ *
*/
-package org.apache.commons.geometry.euclidean.threed.shapes;
+package org.apache.commons.geometry.euclidean.threed.line;
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/Parallelepiped.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/Parallelepiped.java
similarity index 96%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/Parallelepiped.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/Parallelepiped.java
index 4266be1..fc99ec2 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/Parallelepiped.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/Parallelepiped.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.euclidean.threed.shapes;
+package org.apache.commons.geometry.euclidean.threed.shape;
import java.text.MessageFormat;
import java.util.Arrays;
@@ -24,8 +24,9 @@ import java.util.stream.Collectors;
import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
-import org.apache.commons.geometry.euclidean.threed.ConvexSubPlane;
import org.apache.commons.geometry.euclidean.threed.ConvexVolume;
+import org.apache.commons.geometry.euclidean.threed.PlaneConvexSubset;
+import org.apache.commons.geometry.euclidean.threed.Planes;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
import org.apache.commons.geometry.euclidean.threed.rotation.QuaternionRotation;
@@ -53,7 +54,7 @@ public final class Parallelepiped extends ConvexVolume {
* @param boundaries the boundaries of the parallelepiped; this must be a list
* with 6 elements
*/
- private Parallelepiped(final List<ConvexSubPlane> boundaries) {
+ private Parallelepiped(final List<PlaneConvexSubset> boundaries) {
super(boundaries);
}
@@ -152,7 +153,7 @@ public final class Parallelepiped extends ConvexVolume {
ensureNonZeroSideLength(vertices.get(1), vertices.get(2), precision);
ensureNonZeroSideLength(vertices.get(0), vertices.get(4), precision);
- final List<ConvexSubPlane> boundaries = Arrays.asList(
+ final List<PlaneConvexSubset> boundaries = Arrays.asList(
// planes orthogonal to x
createFace(0, 4, 7, 3, vertices, reverse, precision),
createFace(1, 2, 6, 5, vertices, reverse, precision),
@@ -187,7 +188,7 @@ public final class Parallelepiped extends ConvexVolume {
* @param precision precision context used to create the face
* @return a parallelepiped face created from the indexed vertices
*/
- private static ConvexSubPlane createFace(final int a, final int b, final int c, final int d,
+ private static PlaneConvexSubset createFace(final int a, final int b, final int c, final int d,
final List<Vector3D> vertices, final boolean reverse, final DoublePrecisionContext precision) {
final Vector3D pa = vertices.get(a);
@@ -199,7 +200,7 @@ public final class Parallelepiped extends ConvexVolume {
Arrays.asList(pd, pc, pb, pa) :
Arrays.asList(pa, pb, pc, pd);
- return ConvexSubPlane.fromVertexLoop(loop, precision);
+ return Planes.subsetFromVertexLoop(loop, precision);
}
/** Ensure that the given points defining one side of a parallelepiped face are separated by a non-zero
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/Sphere.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/Sphere.java
similarity index 91%
rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/Sphere.java
rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/Sphere.java
index b6e2253..8c0d789 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/Sphere.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/Sphere.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.commons.geometry.euclidean.threed.shapes;
+package org.apache.commons.geometry.euclidean.threed.shape;
import java.text.MessageFormat;
import java.util.List;
@@ -24,14 +24,14 @@ import java.util.stream.Stream;
import org.apache.commons.geometry.core.partitioning.bsp.RegionCutRule;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.euclidean.AbstractNSphere;
-import org.apache.commons.geometry.euclidean.threed.Line3D;
-import org.apache.commons.geometry.euclidean.threed.LinecastPoint3D;
-import org.apache.commons.geometry.euclidean.threed.Linecastable3D;
-import org.apache.commons.geometry.euclidean.threed.Plane;
+import org.apache.commons.geometry.euclidean.threed.Planes;
import org.apache.commons.geometry.euclidean.threed.RegionBSPTree3D;
-import org.apache.commons.geometry.euclidean.threed.Segment3D;
import org.apache.commons.geometry.euclidean.threed.SphericalCoordinates;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
+import org.apache.commons.geometry.euclidean.threed.line.Line3D;
+import org.apache.commons.geometry.euclidean.threed.line.LineConvexSubset3D;
+import org.apache.commons.geometry.euclidean.threed.line.LinecastPoint3D;
+import org.apache.commons.geometry.euclidean.threed.line.Linecastable3D;
import org.apache.commons.numbers.angle.PlaneAngleRadians;
/** Class representing a 3 dimensional sphere in Euclidean space.
@@ -137,28 +137,28 @@ public final class Sphere extends AbstractNSphere<Vector3D> implements Linecasta
/** {@inheritDoc} */
@Override
- public List<LinecastPoint3D> linecast(final Segment3D segment) {
- return getLinecastStream(segment)
+ public List<LinecastPoint3D> linecast(final LineConvexSubset3D subset) {
+ return getLinecastStream(subset)
.collect(Collectors.toList());
}
/** {@inheritDoc} */
@Override
- public LinecastPoint3D linecastFirst(final Segment3D segment) {
- return getLinecastStream(segment)
+ public LinecastPoint3D linecastFirst(final LineConvexSubset3D subset) {
+ return getLinecastStream(subset)
.findFirst()
.orElse(null);
}
/** Get a stream containing the linecast intersection points of the given
- * segment with this instance.
- * @param segment segment to intersect against this instance
+ * line subset with this instance.
+ * @param subset line subset to intersect against this instance
* @return a stream containing linecast intersection points
*/
- private Stream<LinecastPoint3D> getLinecastStream(final Segment3D segment) {
- return intersections(segment.getLine()).stream()
- .filter(segment::contains)
- .map(pt -> new LinecastPoint3D(pt, getCenter().directionTo(pt), segment.getLine()));
+ private Stream<LinecastPoint3D> getLinecastStream(final LineConvexSubset3D subset) {
+ return intersections(subset.getLine()).stream()
+ .filter(subset::contains)
+ .map(pt -> new LinecastPoint3D(pt, getCenter().directionTo(pt), subset.getLine()));
}
/** Construct a sphere from a center point and radius.
@@ -205,7 +205,7 @@ public final class Sphere extends AbstractNSphere<Vector3D> implements Linecasta
/** Create a new instance for approximating the given sphere.
* @param sphere sphere to approximate
* @param stacks number of "stacks" (sections parallel to the x-y plane) in the approximation
- * @param slices number of "slices" (boundary subplanes per stack) in the approximation
+ * @param slices number of "slices" (boundary plane subsets per stack) in the approximation
* @throws IllegalArgumentException if {@code stacks} is less than 2 or {@code slices} is less than 3
*/
SphereApproximationBuilder(final Sphere sphere, final int stacks, final int slices) {
@@ -258,7 +258,7 @@ public final class Sphere extends AbstractNSphere<Vector3D> implements Linecasta
final int splitIdx = (indexDiff / 2) + polarTopIdx;
final Vector3D splitPt = pointAt(splitIdx, 0);
- node.cut(Plane.fromPointAndNormal(splitPt, Vector3D.Unit.PLUS_Z, sphere.getPrecision()),
+ node.cut(Planes.fromPointAndNormal(splitPt, Vector3D.Unit.PLUS_Z, sphere.getPrecision()),
RegionCutRule.INHERIT);
splitAndInsertStacks(node.getPlus(), polarTopIdx, splitIdx);
@@ -288,7 +288,7 @@ public final class Sphere extends AbstractNSphere<Vector3D> implements Linecasta
final Vector3D p1 = pointAt(polarBottomIdx, splitIdx);
final Vector3D p2 = pointAt(polarBottomIdx - 1, splitIdx);
- splitNode.cut(Plane.fromPoints(p0, p1, p2, sphere.getPrecision()), RegionCutRule.INHERIT);
+ splitNode.cut(Planes.fromPoints(p0, p1, p2, sphere.getPrecision()), RegionCutRule.INHERIT);
splitAndInsertSlices(splitNode.getPlus(), polarBottomIdx, 0, splitIdx);
splitAndInsertSlices(splitNode.getMinus(), polarBottomIdx, splitIdx, sliceEndIdx);
@@ -314,7 +314,7 @@ public final class Sphere extends AbstractNSphere<Vector3D> implements Linecasta
final Vector3D p1 = pointAt(polarBottomIdx, splitIdx);
final Vector3D p2 = pointAt(polarBottomIdx - 1, splitIdx);
- node.cut(Plane.fromPoints(p0, p1, p2, sphere.getPrecision()), RegionCutRule.INHERIT);
+ node.cut(Planes.fromPoints(p0, p1, p2, sphere.getPrecision()), RegionCutRule.INHERIT);
splitAndInsertSlices(node.getPlus(), polarBottomIdx, azimuthStartIdx, splitIdx);
splitAndInsertSlices(node.getMinus(), polarBottomIdx, splitIdx, azimuthStopIdx);
@@ -349,7 +349,7 @@ public final class Sphere extends AbstractNSphere<Vector3D> implements Linecasta
pointAt(polarBottomIdx - 1, i - 1) :
pointAt(polarBottomIdx, i - 1);
- currNode = currNode.cut(Plane.fromPoints(p0, p1, p2, sphere.getPrecision()))
+ currNode = currNode.cut(Planes.fromPoints(p0, p1, p2, sphere.getPrecision()))
.getMinus();
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/package-info.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/package-info.java
similarity index 93%
copy from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/package-info.java
copy to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/package-info.java
index 5009b79..0d21e5f 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shapes/package-info.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/shape/package-info.java
@@ -17,4 +17,4 @@
/**
* This package provides utilities for constructing basic 3D shapes.
*/
-package org.apache.commons.geometry.euclidean.threed.shapes;
+package org.apache.commons.geometry.euclidean.threed.shape;
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AbstractSegmentConnector.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AbstractSegmentConnector.java
deleted file mode 100644
index e6d21b3..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AbstractSegmentConnector.java
+++ /dev/null
@@ -1,298 +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.commons.geometry.euclidean.twod;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import org.apache.commons.geometry.euclidean.internal.AbstractPathConnector;
-import org.apache.commons.numbers.angle.PlaneAngleRadians;
-
-/** Abstract class for joining collections of line segments into connected
- * paths. This class is not thread-safe.
- */
-public abstract class AbstractSegmentConnector
- extends AbstractPathConnector<AbstractSegmentConnector.ConnectableSegment> {
- /** Add a line segment to the connector, leaving it unconnected until a later call to
- * to {@link #connect(Iterable)} or {@link #connectAll()}.
- * @param segment line segment to add
- * @see #connect(Iterable)
- * @see #connectAll()
- */
- public void add(final Segment segment) {
- addPathElement(new ConnectableSegment(segment));
- }
-
- /** Add a collection of line segments to the connector, leaving them unconnected
- * until a later call to {@link #connect(Iterable)} or
- * {@link #connectAll()}.
- * @param segments line segments to add
- * @see #connect(Iterable)
- * @see #connectAll()
- * @see #add(Segment)
- */
- public void add(final Iterable<Segment> segments) {
- for (final Segment segment : segments) {
- add(segment);
- }
- }
-
- /** Add a collection of line segments to the connector and attempt to connect each new
- * segment with existing segments. Connections made at this time will not be
- * overwritten by subsequent calls to this or other connection methods.
- * (eg, {@link #connectAll()}).
- *
- * <p>The connector is not reset by this call. Additional segments can still be added
- * to the current set of paths.</p>
- * @param segments line segments to connect
- * @see #connectAll()
- */
- public void connect(final Iterable<Segment> segments) {
- final List<ConnectableSegment> newEntries = new ArrayList<>();
-
- for (final Segment segment : segments) {
- newEntries.add(new ConnectableSegment(segment));
- }
-
- connectPathElements(newEntries);
- }
-
- /** Add the given line segments to this instance and connect all current
- * segments into polylines (ie, line segment paths). This call is equivalent to
- * <pre>
- * connector.add(segments);
- * List<Polyline> result = connector.connectAll();
- * </pre>
- *
- * <p>The connector is reset after this call. Further calls to
- * add or connect line segments will result in new paths being
- * generated.</p>
- * @param segments line segments to add
- * @return the connected line segment paths
- * @see #add(Iterable)
- * @see #connectAll()
- */
- public List<Polyline> connectAll(final Iterable<Segment> segments) {
- add(segments);
- return connectAll();
- }
-
- /** Connect all current segments into connected paths, returning the result as a
- * list of polylines.
- *
- * <p>The connector is reset after this call. Further calls to
- * add or connect line segments will result in new paths being
- * generated.</p>
- * @return the connected line segments paths
- */
- public List<Polyline> connectAll() {
- final List<ConnectableSegment> roots = computePathRoots();
- final List<Polyline> paths = new ArrayList<>(roots.size());
-
- for (final ConnectableSegment root : roots) {
- paths.add(toPolyline(root));
- }
-
- return paths;
- }
-
- /** Convert the linked list of path elements starting at the argument
- * into a {@link Polyline}.
- * @param root root of a connected path linked list
- * @return a polyline representing the linked list path
- */
- private Polyline toPolyline(final ConnectableSegment root) {
- final Polyline.Builder builder = Polyline.builder(null);
-
- builder.append(root.getSegment());
-
- ConnectableSegment current = root.getNext();
-
- while (current != null && current != root) {
- builder.append(current.getSegment());
- current = current.getNext();
- }
-
- return builder.build();
- }
-
- /** Internal class used to connect line segments together.
- */
- protected static class ConnectableSegment extends AbstractPathConnector.ConnectableElement<ConnectableSegment> {
- /** Segment start point. This will be used to connect to other path elements. */
- private final Vector2D start;
-
- /** Line segment for the entry. */
- private final Segment segment;
-
- /** Create a new instance with the given start point. This constructor is
- * intended only for performing searches for other path elements.
- * @param start start point
- */
- public ConnectableSegment(final Vector2D start) {
- this(start, null);
- }
-
- /** Create a new instance from the given line segment.
- * @param segment line segment
- */
- public ConnectableSegment(final Segment segment) {
- this(segment.getStartPoint(), segment);
- }
-
- /** Create a new instance with the given start point and line segment.
- * @param start start point
- * @param segment line segment
- */
- private ConnectableSegment(final Vector2D start, final Segment segment) {
- this.start = start;
- this.segment = segment;
- }
-
- /** Get the line segment for this instance.
- * @return the line segment for this instance
- */
- public Segment getSegment() {
- return segment;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean hasStart() {
- return start != null;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean hasEnd() {
- return segment != null && segment.getEndPoint() != null;
- }
-
- /** Return true if this instance has a size equivalent to zero.
- * @return true if this instance has a size equivalent to zero.
- */
- public boolean hasZeroSize() {
- return segment != null && segment.getPrecision().eqZero(segment.getSize());
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean endPointsEq(final ConnectableSegment other) {
- if (hasEnd() && other.hasEnd()) {
- return segment.getEndPoint()
- .eq(other.segment.getEndPoint(), segment.getPrecision());
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean canConnectTo(final ConnectableSegment next) {
- final Vector2D end = segment.getEndPoint();
- final Vector2D nextStart = next.start;
-
- return end != null && nextStart != null &&
- end.eq(nextStart, segment.getPrecision());
- }
-
- /** {@inheritDoc} */
- @Override
- public double getRelativeAngle(final ConnectableSegment next) {
- return segment.getLine().angle(next.getSegment().getLine());
- }
-
- /** {@inheritDoc} */
- @Override
- public ConnectableSegment getConnectionSearchKey() {
- return new ConnectableSegment(segment.getEndPoint());
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean shouldContinueConnectionSearch(final ConnectableSegment candidate, final boolean ascending) {
-
- if (candidate.hasStart()) {
- final double candidateX = candidate.getSegment().getStartPoint().getX();
- final double thisX = segment.getEndPoint().getX();
- final int cmp = segment.getPrecision().compare(candidateX, thisX);
-
- return ascending ? cmp <= 0 : cmp >= 0;
- }
-
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- public int compareTo(ConnectableSegment other) {
- // sort by coordinates
- int cmp = Vector2D.COORDINATE_ASCENDING_ORDER.compare(start, other.start);
- if (cmp == 0) {
- // sort entries without segments before ones with segments
- final boolean thisHasSegment = segment != null;
- final boolean otherHasSegment = other.segment != null;
-
- cmp = Boolean.compare(thisHasSegment, otherHasSegment);
-
- if (cmp == 0 && thisHasSegment) {
- // place point-like segments before ones with non-zero length
- cmp = Boolean.compare(this.hasZeroSize(), other.hasZeroSize());
-
- if (cmp == 0) {
- // sort by line angle
- final double aAngle = PlaneAngleRadians.normalizeBetweenMinusPiAndPi(
- this.getSegment().getLine().getAngle());
- final double bAngle = PlaneAngleRadians.normalizeBetweenMinusPiAndPi(
- other.getSegment().getLine().getAngle());
-
- cmp = Double.compare(aAngle, bAngle);
- }
- }
- }
- return cmp;
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return Objects.hash(start, segment);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || !this.getClass().equals(obj.getClass())) {
- return false;
- }
-
- final ConnectableSegment other = (ConnectableSegment) obj;
- return Objects.equals(this.start, other.start) &&
- Objects.equals(this.segment, other.segment);
- }
-
- /** {@inheritDoc} */
- @Override
- protected ConnectableSegment getSelf() {
- return this;
- }
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AbstractSubLine.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AbstractSubLine.java
deleted file mode 100644
index 94ea6ad..0000000
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AbstractSubLine.java
+++ /dev/null
@@ -1,127 +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.commons.geometry.euclidean.twod;
-
-import java.util.function.BiFunction;
-
-import org.apache.commons.geometry.core.partitioning.AbstractEmbeddingSubHyperplane;
-import org.apache.commons.geometry.core.partitioning.Hyperplane;
-import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
-import org.apache.commons.geometry.core.partitioning.Split;
-import org.apache.commons.geometry.core.partitioning.SplitLocation;
-import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
-import org.apache.commons.geometry.euclidean.oned.OrientedPoint;
-import org.apache.commons.geometry.euclidean.oned.Vector1D;
-import org.apache.commons.geometry.euclidean.twod.SubLine.SubLineBuilder;
-
-/** Internal base class for subline implementations.
- */
-abstract class AbstractSubLine extends AbstractEmbeddingSubHyperplane<Vector2D, Vector1D, Line> {
- /** The line defining this instance. */
- private final Line line;
-
- /** Construct a new instance based on the given line.
- * @param line line forming the base of the instance
- */
- AbstractSubLine(final Line line) {
- this.line = line;
- }
-
- /** Get the line that this segment lies on. This method is an alias
- * for {@link #getHyperplane()}.
- * @return the line that this segment lies on
- * @see #getHyperplane()
- */
- public Line getLine() {
- return getHyperplane();
- }
-
- /** {@inheritDoc} */
- @Override
- public Line getHyperplane() {
- return line;
- }
-
- /** {@inheritDoc} */
- @Override
- public SubLineBuilder builder() {
- return new SubLineBuilder(line);
- }
-
- /** Return the object used to perform floating point comparisons, which is the
- * same object used by the underlying {@link Line}).
- * @return precision object used to perform floating point comparisons.
- */
- public DoublePrecisionContext getPrecision() {
- return line.getPrecision();
- }
-
- /** Generic, internal split method. Subclasses should call this from their
- * {@link #split(Hyperplane)} methods.
- * @param splitter splitting hyperplane
- * @param thisInstance a reference to the current instance; this is passed as
- * an argument in order to allow it to be a generic type
- * @param factory function used to create new subhyperplane instances
- * @param <T> Subline implementation type
- * @return the result of the split operation
- */
- protected <T extends AbstractSubLine> Split<T> splitInternal(final Hyperplane<Vector2D> splitter,
- final T thisInstance, final BiFunction<Line, HyperplaneBoundedRegion<Vector1D>, T> factory) {
-
- final Line thisLine = getLine();
- final Line splitterLine = (Line) splitter;
- final DoublePrecisionContext precision = getPrecision();
-
- final Vector2D intersection = splitterLine.intersection(thisLine);
- if (intersection == null) {
- // the lines are parallel or coincident; check which side of
- // the splitter we lie on
- final double offset = splitterLine.offset(thisLine);
- final int comp = precision.compare(offset, 0.0);
-
- if (comp < 0) {
- return new Split<>(thisInstance, null);
- } else if (comp > 0) {
- return new Split<>(null, thisInstance);
- } else {
- return new Split<>(null, null);
- }
- } else {
- // the lines intersect; split the subregion
- final Vector1D splitPt = thisLine.toSubspace(intersection);
- final boolean positiveFacing = thisLine.angle(splitterLine) > 0.0;
-
- final OrientedPoint subspaceSplitter = OrientedPoint.fromPointAndDirection(splitPt,
- positiveFacing, getPrecision());
-
- final Split<? extends HyperplaneBoundedRegion<Vector1D>> split =
- thisInstance.getSubspaceRegion().split(subspaceSplitter);
- final SplitLocation subspaceSplitLoc = split.getLocation();
-
- if (SplitLocation.MINUS == subspaceSplitLoc) {
- return new Split<>(thisInstance, null);
- } else if (SplitLocation.PLUS == subspaceSplitLoc) {
- return new Split<>(null, thisInstance);
- }
-
- final T minus = (split.getMinus() != null) ? factory.apply(thisLine, split.getMinus()) : null;
- final T plus = (split.getPlus() != null) ? factory.apply(thisLine, split.getPlus()) : null;
-
- return new Split<>(minus, plus);
- }
- }
-}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySource2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySource2D.java
index ec0fe30..45cfe7e 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySource2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySource2D.java
@@ -18,13 +18,13 @@ package org.apache.commons.geometry.euclidean.twod;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import org.apache.commons.geometry.core.partitioning.BoundarySource;
-/** Extension of the {@link BoundarySource} interface for Euclidean 2D
- * space.
+/** Extension of the {@link BoundarySource} interface for Euclidean 2D space.
*/
-public interface BoundarySource2D extends BoundarySource<Segment> {
+public interface BoundarySource2D extends BoundarySource<LineConvexSubset>, Linecastable2D {
/** Return a BSP tree constructed from the boundaries contained in this
* instance. The default implementation creates a new, empty tree
@@ -38,20 +38,32 @@ public interface BoundarySource2D extends BoundarySource<Segment> {
return tree;
}
- /** Return a {@link BoundarySource2D} instance containing the given segments.
- * @param boundaries segments to include in the boundary source
+ /** {@inheritDoc} */
+ @Override
+ default List<LinecastPoint2D> linecast(final LineConvexSubset subset) {
+ return new BoundarySourceLinecaster2D(this).linecast(subset);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ default LinecastPoint2D linecastFirst(final LineConvexSubset subset) {
+ return new BoundarySourceLinecaster2D(this).linecastFirst(subset);
+ }
+
+ /** Return a {@link BoundarySource2D} instance containing the given boundaries.
+ * @param boundaries line subsets to include in the boundary source
* @return a boundary source containing the given boundaries
*/
- static BoundarySource2D from(final Segment... boundaries) {
+ static BoundarySource2D from(final LineConvexSubset... boundaries) {
return from(Arrays.asList(boundaries));
}
- /** Return a {@link BoundarySource2D} instance containing the given segments. The given
- * collection is used directly as the source of the segments; no copy is made.
- * @param boundaries segments to include in the boundary source
+ /** Return a {@link BoundarySource2D} instance containing the given boundaries. The given
+ * collection is used directly as the source of the line subsets; no copy is made.
+ * @param boundaries line subsets to include in the boundary source
* @return a boundary source containing the given boundaries
*/
- static BoundarySource2D from(final Collection<Segment> boundaries) {
+ static BoundarySource2D from(final Collection<LineConvexSubset> boundaries) {
return boundaries::stream;
}
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySourceLinecaster2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySourceLinecaster2D.java
index 612c6a1..69a265c 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySourceLinecaster2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/BoundarySourceLinecaster2D.java
@@ -24,7 +24,7 @@ import java.util.stream.Stream;
/** Class that performs linecast operations against arbitrary {@link BoundarySource2D}
* instances. This class performs a brute-force computation of the intersections of the
- * line or line segment against all boundaries. Some data structures may support more
+ * line or line subset against all boundaries. Some data structures may support more
* efficient algorithms and should therefore prefer those instead.
*/
final class BoundarySourceLinecaster2D implements Linecastable2D {
@@ -41,8 +41,8 @@ final class BoundarySourceLinecaster2D implements Linecastable2D {
/** {@inheritDoc} */
@Override
- public List<LinecastPoint2D> linecast(final Segment segment) {
- final List<LinecastPoint2D> results = getIntersectionStream(segment)
+ public List<LinecastPoint2D> linecast(final LineConvexSubset subset) {
+ final List<LinecastPoint2D> results = getIntersectionStream(subset)
.collect(Collectors.toCollection(ArrayList::new));
LinecastPoint2D.sortAndFilter(results);
@@ -52,37 +52,37 @@ final class BoundarySourceLinecaster2D implements Linecastable2D {
/** {@inheritDoc} */
@Override
- public LinecastPoint2D linecastFirst(final Segment segment) {
- return getIntersectionStream(segment)
+ public LinecastPoint2D linecastFirst(final LineConvexSubset subset) {
+ return getIntersectionStream(subset)
.min(LinecastPoint2D.ABSCISSA_ORDER)
.orElse(null);
}
/** Return a stream containing intersections between the boundary source and the
- * given line segment.
- * @param segment segment to intersect
+ * given line subset.
+ * @param subset line subset to intersect
* @return a stream containing linecast intersections
*/
- private Stream<LinecastPoint2D> getIntersectionStream(final Segment segment) {
+ private Stream<LinecastPoint2D> getIntersectionStream(final LineConvexSubset subset) {
return boundarySrc.boundaryStream()
- .map(boundary -> computeIntersection(boundary, segment))
+ .map(boundary -> computeIntersection(boundary, subset))
.filter(Objects::nonNull);
}
- /** Compute the intersection between a boundary segment and linecast intersecting segment. Null is
+ /** Compute the intersection between a boundary line subset and linecast intersecting line subset. Null is
* returned if no intersection is discovered.
* @param boundary boundary from the boundary source
- * @param segment linecast segment to intersect with
+ * @param subset line subset to intersect with
* @return the linecast intersection between the two arguments or null if there is no such
* intersection
*/
- private LinecastPoint2D computeIntersection(final Segment boundary, final Segment segment) {
- final Vector2D intersectionPt = boundary.intersection(segment);
+ private LinecastPoint2D computeIntersection(final LineConvexSubset boundary, final LineConvexSubset subset) {
+ final Vector2D intersectionPt = boundary.intersection(subset);
if (intersectionPt != null) {
final Vector2D normal = boundary.getLine().getOffsetDirection();
- return new LinecastPoint2D(intersectionPt, normal, segment.getLine());
+ return new LinecastPoint2D(intersectionPt, normal, subset.getLine());
}
return null; // no intersection
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/ConvexArea.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/ConvexArea.java
index 9db3fd6..67d0566 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/ConvexArea.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/ConvexArea.java
@@ -26,16 +26,18 @@ import java.util.stream.Stream;
import org.apache.commons.geometry.core.Transform;
import org.apache.commons.geometry.core.partitioning.AbstractConvexHyperplaneBoundedRegion;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.twod.path.InteriorAngleLinePathConnector;
+import org.apache.commons.geometry.euclidean.twod.path.LinePath;
/** Class representing a finite or infinite convex area in Euclidean 2D space.
- * The boundaries of this area, if any, are composed of convex sublines.
+ * The boundaries of this area, if any, are composed of convex line subsets.
*/
-public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D, Segment>
- implements BoundarySource2D, Linecastable2D {
+public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D, LineConvexSubset>
+ implements BoundarySource2D {
/** Instance representing the full 2D plane. */
private static final ConvexArea FULL = new ConvexArea(Collections.emptyList());
@@ -44,32 +46,32 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
* represents the boundary of a convex area. No validation is performed.
* @param boundaries the boundaries of the convex area
*/
- protected ConvexArea(final List<Segment> boundaries) {
+ protected ConvexArea(final List<LineConvexSubset> boundaries) {
super(boundaries);
}
/** {@inheritDoc} */
@Override
- public Stream<Segment> boundaryStream() {
+ public Stream<LineConvexSubset> boundaryStream() {
return getBoundaries().stream();
}
- /** Get the connected line segment paths comprising the boundary of the area. The
- * segments are oriented so that their minus sides point toward the interior of the
+ /** Get the connected line subset paths comprising the boundary of the area. The
+ * line subsets are oriented so that their minus sides point toward the interior of the
* region. The size of the returned list is
* <ul>
* <li><strong>0</strong> if the convex area is full,</li>
* <li><strong>1</strong> if at least one boundary is present and
- * a single path can connect all segments (this will be the case
+ * a single path can connect all line subsets (this will be the case
* for most instances), and</li>
* <li><strong>2</strong> if only two boundaries exist and they are
* parallel to each other (in which case they cannot be connected
* as a single path).</li>
* </ul>
- * @return the line segment paths comprising the boundary of the area.
+ * @return the line subset paths comprising the boundary of the area.
*/
- public List<Polyline> getBoundaryPaths() {
- return InteriorAngleSegmentConnector.connectMinimized(getBoundaries());
+ public List<LinePath> getBoundaryPaths() {
+ return InteriorAngleLinePathConnector.connectMinimized(getBoundaries());
}
/** Get the vertices defining the area. The vertices lie at the intersections of the
@@ -80,12 +82,12 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
* @return the vertices defining the area
*/
public List<Vector2D> getVertices() {
- final List<Polyline> paths = getBoundaryPaths();
+ final List<LinePath> paths = getBoundaryPaths();
// we will only have vertices if we have a single path; otherwise, we have a full
- // area or two non-intersecting infinite segments
+ // area or two non-intersecting infinite line subsets
if (paths.size() == 1) {
- final Polyline path = paths.get(0);
+ final LinePath path = paths.get(0);
final List<Vector2D> vertices = path.getVertexSequence();
if (path.isClosed()) {
@@ -103,13 +105,13 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
* @return a new instance transformed by the argument
*/
public ConvexArea transform(final Transform<Vector2D> transform) {
- return transformInternal(transform, this, Segment.class, ConvexArea::new);
+ return transformInternal(transform, this, LineConvexSubset.class, ConvexArea::new);
}
/** {@inheritDoc} */
@Override
- public Segment trim(final ConvexSubHyperplane<Vector2D> convexSubHyperplane) {
- return (Segment) super.trim(convexSubHyperplane);
+ public LineConvexSubset trim(final HyperplaneConvexSubset<Vector2D> convexSubset) {
+ return (LineConvexSubset) super.trim(convexSubset);
}
/** {@inheritDoc} */
@@ -121,12 +123,12 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
double quadrilateralAreaSum = 0.0;
- for (final Segment segment : getBoundaries()) {
- if (segment.isInfinite()) {
+ for (final LineConvexSubset boundary : getBoundaries()) {
+ if (boundary.isInfinite()) {
return Double.POSITIVE_INFINITY;
}
- quadrilateralAreaSum += segment.getStartPoint().signedArea(segment.getEndPoint());
+ quadrilateralAreaSum += boundary.getStartPoint().signedArea(boundary.getEndPoint());
}
return 0.5 * quadrilateralAreaSum;
@@ -135,7 +137,7 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
/** {@inheritDoc} */
@Override
public Vector2D getBarycenter() {
- final List<Segment> boundaries = getBoundaries();
+ final List<LineConvexSubset> boundaries = getBoundaries();
double quadrilateralAreaSum = 0.0;
double scaledSumX = 0.0;
@@ -145,7 +147,7 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
Vector2D startPoint;
Vector2D endPoint;
- for (final Segment seg : boundaries) {
+ for (final LineConvexSubset seg : boundaries) {
if (seg.isInfinite()) {
// infinite => no barycenter
return null;
@@ -172,7 +174,7 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
/** {@inheritDoc} */
@Override
public Split<ConvexArea> split(final Hyperplane<Vector2D> splitter) {
- return splitInternal(splitter, this, Segment.class, ConvexArea::new);
+ return splitInternal(splitter, this, LineConvexSubset.class, ConvexArea::new);
}
/** Return a BSP tree representing the same region as this instance.
@@ -182,18 +184,6 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
return RegionBSPTree2D.from(getBoundaries(), true);
}
- /** {@inheritDoc} */
- @Override
- public List<LinecastPoint2D> linecast(final Segment segment) {
- return new BoundarySourceLinecaster2D(this).linecast(segment);
- }
-
- /** {@inheritDoc} */
- @Override
- public LinecastPoint2D linecastFirst(final Segment segment) {
- return new BoundarySourceLinecaster2D(this).linecastFirst(segment);
- }
-
/** Return an instance representing the full 2D area.
* @return an instance representing the full 2D area.
*/
@@ -255,14 +245,14 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
}
if (prev != null && !cur.eq(prev, precision)) {
- lines.add(Line.fromPoints(prev, cur, precision));
+ lines.add(Lines.fromPoints(prev, cur, precision));
}
prev = cur;
}
if (close && cur != null && !cur.eq(first, precision)) {
- lines.add(Line.fromPoints(cur, first, precision));
+ lines.add(Lines.fromPoints(cur, first, precision));
}
if (!vertices.isEmpty() && lines.isEmpty()) {
@@ -272,15 +262,15 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
return fromBounds(lines);
}
- /** Construct a convex area from a line segment path. The area represents the intersection of all of the negative
- * half-spaces of the lines in the path. The boundaries of the returned area may therefore not match the line
- * segments in the path.
+ /** Construct a convex area from a line subset path. The area represents the intersection of all of the
+ * negative half-spaces of the lines in the path. The boundaries of the returned area may therefore not
+ * match the line subsets in the path.
* @param path path to construct the area from
- * @return a convex area constructed from the lines in the given path
+ * @return a convex area constructed from the line subsets in the given path
*/
- public static ConvexArea fromPath(final Polyline path) {
+ public static ConvexArea fromPath(final LinePath path) {
final List<Line> lines = path.boundaryStream()
- .map(Segment::getLine)
+ .map(LineConvexSubset::getLine)
.collect(Collectors.toList());
return fromBounds(lines);
@@ -313,7 +303,8 @@ public class ConvexArea extends AbstractConvexHyperplaneBoundedRegion<Vector2D,
* meaning that there is no region that is on the minus side of all of the bounding lines.
*/
public static ConvexArea fromBounds(final Iterable<Line> bounds) {
- final List<Segment> segments = new ConvexRegionBoundaryBuilder<>(Segment.class).build(bounds);
- return segments.isEmpty() ? full() : new ConvexArea(segments);
+ final List<LineConvexSubset> subsets =
+ new ConvexRegionBoundaryBuilder<>(LineConvexSubset.class).build(bounds);
+ return subsets.isEmpty() ? full() : new ConvexArea(subsets);
}
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/EmbeddedTreeLineSubset.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/EmbeddedTreeLineSubset.java
new file mode 100644
index 0000000..9bfb2f8
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/EmbeddedTreeLineSubset.java
@@ -0,0 +1,262 @@
+/*
+ * 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.commons.geometry.euclidean.twod;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.geometry.core.RegionLocation;
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
+import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
+import org.apache.commons.geometry.core.partitioning.Split;
+import org.apache.commons.geometry.core.partitioning.SplitLocation;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.oned.Interval;
+import org.apache.commons.geometry.euclidean.oned.OrientedPoint;
+import org.apache.commons.geometry.euclidean.oned.OrientedPoints;
+import org.apache.commons.geometry.euclidean.oned.RegionBSPTree1D;
+import org.apache.commons.geometry.euclidean.twod.Line.SubspaceTransform;
+
+/** Class representing an arbitrary subset of a line using a {@link RegionBSPTree1D}.
+ * This class can represent convex, non-convex, finite, infinite, and empty regions.
+ *
+ * <p>This class is mutable and <em>not</em> thread safe.</p>
+ */
+public final class EmbeddedTreeLineSubset extends LineSubset {
+ /** The 1D region representing the area on the line. */
+ private final RegionBSPTree1D region;
+
+ /** Construct a new, empty subset for the given line.
+ * @param line line defining the subset
+ */
+ public EmbeddedTreeLineSubset(final Line line) {
+ this(line, false);
+ }
+
+ /** Construct a new subset for the given line. If {@code full}
+ * is true, then the subset will cover the entire line; otherwise,
+ * it will be empty.
+ * @param line line defining the subset
+ * @param full if true, the subset will cover the entire space;
+ * otherwise it will be empty
+ */
+ public EmbeddedTreeLineSubset(final Line line, boolean full) {
+ this(line, new RegionBSPTree1D(full));
+ }
+
+ /** Construct a new instance from its defining line and subspace region. The give
+ * BSP tree is used directly by this instance; it is not copied.
+ * @param line line defining the subset
+ * @param region subspace region for the instance
+ */
+ public EmbeddedTreeLineSubset(final Line line, final RegionBSPTree1D region) {
+ super(line);
+
+ this.region = region;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public EmbeddedTreeLineSubset transform(final Transform<Vector2D> transform) {
+ final SubspaceTransform st = getLine().subspaceTransform(transform);
+
+ final RegionBSPTree1D tRegion = RegionBSPTree1D.empty();
+ tRegion.copy(region);
+ tRegion.transform(st.getTransform());
+
+ return new EmbeddedTreeLineSubset(st.getLine(), tRegion);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public List<LineConvexSubset> toConvex() {
+ final List<Interval> intervals = region.toIntervals();
+
+ final Line line = getLine();
+ final List<LineConvexSubset> convexSubsets = new ArrayList<>(intervals.size());
+
+ for (final Interval interval : intervals) {
+ convexSubsets.add(Lines.subsetFromInterval(line, interval));
+ }
+
+ return convexSubsets;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RegionBSPTree1D getSubspaceRegion() {
+ return region;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>In all cases, the current instance is not modified. However, In order to avoid
+ * unnecessary copying, this method will use the current instance as the split value when
+ * the instance lies entirely on the plus or minus side of the splitter. For example, if
+ * this instance lies entirely on the minus side of the splitter, the subplane
+ * returned by {@link Split#getMinus()} will be this instance. Similarly, {@link Split#getPlus()}
+ * will return the current instance if it lies entirely on the plus side. Callers need to make
+ * special note of this, since this class is mutable.</p>
+ */
+ @Override
+ public Split<EmbeddedTreeLineSubset> split(final Hyperplane<Vector2D> splitter) {
+ final Line thisLine = getLine();
+ final Line splitterLine = (Line) splitter;
+ final DoublePrecisionContext precision = getPrecision();
+
+ final Vector2D intersection = splitterLine.intersection(thisLine);
+ if (intersection == null) {
+ return getNonIntersectingSplitResult(splitterLine, this);
+ }
+
+ final double abscissa = thisLine.abscissa(intersection);
+ final OrientedPoint subspaceSplitter = OrientedPoints.fromLocationAndDirection(
+ abscissa,
+ splitterPlusIsPositiveFacing(splitterLine),
+ precision);
+
+ final Split<RegionBSPTree1D> subspaceSplit = region.split(subspaceSplitter);
+ final SplitLocation subspaceSplitLoc = subspaceSplit.getLocation();
+
+ if (SplitLocation.MINUS == subspaceSplitLoc) {
+ return new Split<>(this, null);
+ } else if (SplitLocation.PLUS == subspaceSplitLoc) {
+ return new Split<>(null, this);
+ }
+
+ final EmbeddedTreeLineSubset minus = (subspaceSplit.getMinus() != null) ?
+ new EmbeddedTreeLineSubset(thisLine, subspaceSplit.getMinus()) :
+ null;
+ final EmbeddedTreeLineSubset plus = (subspaceSplit.getPlus() != null) ?
+ new EmbeddedTreeLineSubset(thisLine, subspaceSplit.getPlus()) :
+ null;
+
+ return new Split<>(minus, plus);
+ }
+
+ /** Add a line subset to this instance.
+ * @param subset the line subset to add
+ * @throws IllegalArgumentException if the given line subset is not from
+ * a line equivalent to this instance
+ */
+ public void add(final LineConvexSubset subset) {
+ validateLine(subset.getLine());
+
+ region.add(subset.getInterval());
+ }
+
+ /** Add the region represented by the given line subset to this instance.
+ * The argument is not modified.
+ * @param subset line subset to add
+ * @throws IllegalArgumentException if the given line subset is not from
+ * a line equivalent to this instance
+ */
+ public void add(final EmbeddedTreeLineSubset subset) {
+ validateLine(subset.getLine());
+
+ region.union(subset.getSubspaceRegion());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final Line line = getLine();
+
+ final StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSimpleName())
+ .append('[')
+ .append("lineOrigin= ")
+ .append(line.getOrigin())
+ .append(", lineDirection= ")
+ .append(line.getDirection())
+ .append(", region= ")
+ .append(region)
+ .append(']');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ RegionLocation classifyAbscissa(final double abscissa) {
+ return region.classify(abscissa);
+ }
+
+ /** Validate that the given line is equivalent to the line
+ * defining this instance.
+ * @param inputLine the line to validate
+ * @throws IllegalArgumentException if the given line is not equivalent
+ * to the line for this instance
+ */
+ private void validateLine(final Line inputLine) {
+ final Line line = getLine();
+
+ if (!line.eq(inputLine, line.getPrecision())) {
+ throw new IllegalArgumentException("Argument is not on the same " +
+ "line. Expected " + line + " but was " +
+ inputLine);
+ }
+ }
+
+ /** {@link HyperplaneSubset.Builder} implementation for line subsets.
+ */
+ public static final class Builder implements HyperplaneSubset.Builder<Vector2D> {
+
+ /** Line subset instance created by this builder. */
+ private final EmbeddedTreeLineSubset lineSubset;
+
+ /** Construct a new instance for building a line subset for the given line.
+ * @param line the underlying line for the subset
+ */
+ public Builder(final Line line) {
+ this.lineSubset = new EmbeddedTreeLineSubset(line);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void add(final HyperplaneSubset<Vector2D> sub) {
+ addInternal(sub);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void add(final HyperplaneConvexSubset<Vector2D> sub) {
+ addInternal(sub);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public EmbeddedTreeLineSubset build() {
+ return lineSubset;
+ }
+
+ /** Internal method for adding hyperplane subsets to this builder.
+ * @param sub the hyperplane subset to add; either convex or non-convex
+ */
+ private void addInternal(final HyperplaneSubset<Vector2D> sub) {
+ if (sub instanceof LineConvexSubset) {
+ lineSubset.add((LineConvexSubset) sub);
+ } else if (sub instanceof EmbeddedTreeLineSubset) {
+ lineSubset.add((EmbeddedTreeLineSubset) sub);
+ } else {
+ throw new IllegalArgumentException("Unsupported hyperplane subset type: " + sub.getClass().getName());
+ }
+ }
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
index 9ca8807..b7a0d93 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Line.java
@@ -16,6 +16,7 @@
*/
package org.apache.commons.geometry.euclidean.twod;
+import java.text.MessageFormat;
import java.util.Objects;
import org.apache.commons.geometry.core.Transform;
@@ -24,7 +25,6 @@ import org.apache.commons.geometry.core.partitioning.EmbeddingHyperplane;
import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
import org.apache.commons.geometry.euclidean.oned.AffineTransformMatrix1D;
-import org.apache.commons.geometry.euclidean.oned.Interval;
import org.apache.commons.geometry.euclidean.oned.Vector1D;
import org.apache.commons.numbers.angle.PlaneAngleRadians;
import org.apache.commons.numbers.arrays.LinearCombination;
@@ -54,9 +54,14 @@ import org.apache.commons.numbers.arrays.LinearCombination;
* the set of points at zero offset, the left half plane is the set of
* points with negative offsets and the right half plane is the set of
* points with positive offsets.</p>
+ * @see Lines
*/
public final class Line extends AbstractHyperplane<Vector2D>
implements EmbeddingHyperplane<Vector2D, Vector1D> {
+
+ /** Format string for creating line string representations. */
+ static final String TO_STRING_FORMAT = "{0}[origin= {1}, direction= {2}]";
+
/** The direction of the line as a normalized vector. */
private final Vector2D direction;
@@ -68,7 +73,7 @@ public final class Line extends AbstractHyperplane<Vector2D>
* @param originOffset The signed distance between the line and the origin.
* @param precision Precision context used to compare floating point numbers.
*/
- private Line(final Vector2D direction, final double originOffset, final DoublePrecisionContext precision) {
+ Line(final Vector2D direction, final double originOffset, final DoublePrecisionContext precision) {
super(precision);
this.direction = direction;
@@ -132,7 +137,7 @@ public final class Line extends AbstractHyperplane<Vector2D>
final Vector2D tOrigin = transform.apply(origin);
final Vector2D tOriginPlusDir = transform.apply(origin.add(getDirection()));
- return fromPoints(tOrigin, tOriginPlusDir, getPrecision());
+ return Lines.fromPoints(tOrigin, tOriginPlusDir, getPrecision());
}
/** Get an object containing the current line transformed by the argument along with a
@@ -163,7 +168,7 @@ public final class Line extends AbstractHyperplane<Vector2D>
final Vector2D p1 = transform.apply(origin);
final Vector2D p2 = transform.apply(origin.add(direction));
- final Line tLine = Line.fromPoints(p1, p2, getPrecision());
+ final Line tLine = Lines.fromPoints(p1, p2, getPrecision());
final Vector1D tSubspaceOrigin = tLine.toSubspace(p1);
final Vector1D tSubspaceDirection = tSubspaceOrigin.vectorTo(tLine.toSubspace(p2));
@@ -178,62 +183,81 @@ public final class Line extends AbstractHyperplane<Vector2D>
/** {@inheritDoc} */
@Override
- public Segment span() {
- return segment(Interval.full());
- }
-
- /** Create a new line segment from the given interval.
- * @param interval interval representing the 1D region for the line segment
- * @return a new line segment on this line
- */
- public Segment segment(final Interval interval) {
- return Segment.fromInterval(this, interval);
+ public LineConvexSubset span() {
+ return Lines.span(this);
}
- /** Create a new line segment from the given interval.
+ /** Create a new line segment from the given 1D interval. The returned line
+ * segment consists of all points between the two locations, regardless of the order the
+ * arguments are given.
* @param a first 1D location for the interval
* @param b second 1D location for the interval
* @return a new line segment on this line
+ * @throws IllegalArgumentException if either of the locations is NaN or infinite
+ * @see Lines#segmentFromLocations(Line, double, double)
*/
public Segment segment(final double a, final double b) {
- return Segment.fromInterval(this, a, b);
+ return Lines.segmentFromLocations(this, a, b);
}
- /** Create a new line segment between the projections of the two
- * given points onto this line.
+ /** Create a new line segment from two points. The returned segment represents all points on this line
+ * between the projected locations of {@code a} and {@code b}. The points may be given in any order.
* @param a first point
* @param b second point
* @return a new line segment on this line
+ * @throws IllegalArgumentException if either point contains NaN or infinite coordinate values
+ * @see Lines#segmentFromPoints(Line, Vector2D, Vector2D)
*/
public Segment segment(final Vector2D a, final Vector2D b) {
- return Segment.fromInterval(this, toSubspace(a), toSubspace(b));
+ return Lines.segmentFromPoints(this, a, b);
}
- /** Create a new line segment that starts at infinity and continues along
- * the line up to the projection of the given point.
- * @param pt point defining the end point of the line segment; the end point
+ /** Create a new convex line subset that starts at infinity and continues along
+ * the line up to the projection of the given end point.
+ * @param endPoint point defining the end point of the line subset; the end point
* is equal to the projection of this point onto the line
- * @return a new, half-open line segment
+ * @return a new, half-open line subset that ends at the given point
+ * @throws IllegalArgumentException if any coordinate in {@code endPoint} is NaN or infinite
+ * @see Lines#reverseRayFromPoint(Line, Vector2D)
*/
- public Segment segmentTo(final Vector2D pt) {
- return segment(Double.NEGATIVE_INFINITY, toSubspace(pt).getX());
+ public ReverseRay reverseRayTo(final Vector2D endPoint) {
+ return Lines.reverseRayFromPoint(this, endPoint);
}
- /** Create a new line segment that starts at the projection of the given point
- * and continues in the direction of the line to infinity, similar to a ray.
- * @param pt point defining the start point of the line segment; the start point
+ /** Create a new convex line subset that starts at infinity and continues along
+ * the line up to the given 1D location.
+ * @param endLocation the 1D location of the end of the half-line
+ * @return a new, half-open line subset that ends at the given 1D location
+ * @throws IllegalArgumentException if {@code endLocation} is NaN or infinite
+ * @see Lines#reverseRayFromLocation(Line, double)
+ */
+ public ReverseRay reverseRayTo(final double endLocation) {
+ return Lines.reverseRayFromLocation(this, endLocation);
+ }
+
+ /** Create a new ray instance that starts at the projection of the given point
+ * and continues in the direction of the line to infinity.
+ * @param startPoint point defining the start point of the ray; the start point
* is equal to the projection of this point onto the line
- * @return a new, half-open line segment
+ * @return a ray starting at the projected point and extending along this line
+ * to infinity
+ * @throws IllegalArgumentException if any coordinate in {@code startPoint} is NaN or infinite
+ * @see Lines#rayFromPoint(Line, Vector2D)
*/
- public Segment segmentFrom(final Vector2D pt) {
- return segment(toSubspace(pt).getX(), Double.POSITIVE_INFINITY);
+ public Ray rayFrom(final Vector2D startPoint) {
+ return Lines.rayFromPoint(this, startPoint);
}
- /** Create a new, empty subline based on this line.
- * @return a new, empty subline based on this line
+ /** Create a new ray instance that starts at the given 1D location and continues in
+ * the direction of the line to infinity.
+ * @param startLocation 1D location defining the start point of the ray
+ * @return a ray starting at the given 1D location and extending along this line
+ * to infinity
+ * @throws IllegalArgumentException if {@code startLocation} is NaN or infinite
+ * @see Lines#rayFromLocation(Line, double)
*/
- public SubLine subline() {
- return new SubLine(this);
+ public Ray rayFrom(final double startLocation) {
+ return Lines.rayFromLocation(this, startLocation);
}
/** Get the abscissa of the given point on the line. The abscissa represents
@@ -478,63 +502,10 @@ public final class Line extends AbstractHyperplane<Vector2D>
/** {@inheritDoc} */
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append(getClass().getSimpleName())
- .append("[origin= ")
- .append(getOrigin())
- .append(", direction= ")
- .append(direction)
- .append(']');
-
- return sb.toString();
- }
-
- /** Create a line from two points lying on the line. The line points in the direction
- * from {@code p1} to {@code p2}.
- * @param p1 first point
- * @param p2 second point
- * @param precision precision context used to compare floating point values
- * @return new line containing {@code p1} and {@code p2} and pointing in the direction
- * from {@code p1} to {@code p2}
- * @throws IllegalArgumentException If the vector between {@code p1} and {@code p2} has zero length,
- * as evaluated by the given precision context
- */
- public static Line fromPoints(final Vector2D p1, final Vector2D p2, final DoublePrecisionContext precision) {
- return fromPointAndDirection(p1, p1.vectorTo(p2), precision);
- }
-
- /** Create a line from a point and direction.
- * @param pt point belonging to the line
- * @param dir the direction of the line
- * @param precision precision context used to compare floating point values
- * @return new line containing {@code pt} and pointing in direction {@code dir}
- * @throws IllegalArgumentException If {@code dir} has zero length, as evaluated by the
- * given precision context
- */
- public static Line fromPointAndDirection(final Vector2D pt, final Vector2D dir,
- final DoublePrecisionContext precision) {
- if (dir.isZero(precision)) {
- throw new IllegalArgumentException("Line direction cannot be zero");
- }
-
- final Vector2D normalizedDir = dir.normalize();
- final double originOffset = normalizedDir.signedArea(pt);
-
- return new Line(normalizedDir, originOffset, precision);
- }
-
- /** Create a line from a point lying on the line and an angle relative to the abscissa (x) axis. Note that the
- * line does not need to intersect the x-axis; the given angle is simply relative to it.
- * @param pt point belonging to the line
- * @param angle angle of the line with respect to abscissa (x) axis, in radians
- * @param precision precision context used to compare floating point values
- * @return new line containing {@code pt} and forming the given angle with the
- * abscissa (x) axis.
- */
- public static Line fromPointAndAngle(final Vector2D pt, final double angle,
- final DoublePrecisionContext precision) {
- final Vector2D.Unit dir = Vector2D.Unit.from(Math.cos(angle), Math.sin(angle));
- return fromPointAndDirection(pt, dir, precision);
+ return MessageFormat.format(TO_STRING_FORMAT,
+ getClass().getSimpleName(),
+ getOrigin(),
+ getDirection());
}
/** Class containing a transformed line instance along with a subspace (1D) transform. The subspace
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineConvexSubset.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineConvexSubset.java
new file mode 100644
index 0000000..11a8db1
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineConvexSubset.java
@@ -0,0 +1,141 @@
+/*
+ * 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.commons.geometry.euclidean.twod;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.core.partitioning.Hyperplane;
+import org.apache.commons.geometry.core.partitioning.HyperplaneConvexSubset;
+import org.apache.commons.geometry.core.partitioning.Split;
+import org.apache.commons.geometry.euclidean.oned.Interval;
+
+/** Class representing a convex subset of a line in 2D Euclidean space. Instances
+ * need not be finite, in which case the start or end point (or both) will be null.
+ * Line segments and rays are examples of convex line subsets.
+ * @see Lines
+ */
+public abstract class LineConvexSubset extends LineSubset implements HyperplaneConvexSubset<Vector2D> {
+
+ /** Construct a new instance for the given line.
+ * @param line line containing this line subset
+ */
+ LineConvexSubset(final Line line) {
+ super(line);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public List<LineConvexSubset> toConvex() {
+ return Collections.singletonList(this);
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ /** Get the start point for the subset.
+ * @return the start point for the subset, or null if no start point exists
+ */
+ public abstract Vector2D getStartPoint();
+
+ /** Get the 1D start location of the subset or {@link Double#NEGATIVE_INFINITY} if
+ * no start location exists.
+ * @return the 1D start location of the subset or {@link Double#NEGATIVE_INFINITY} if
+ * no start location exists.
+ */
+ public abstract double getSubspaceStart();
+
+ /** Get the end point for the subset.
+ * @return the end point for the subset, or null if no end point exists.
+ */
+ public abstract Vector2D getEndPoint();
+
+ /** Get the 1D end location of the subset or {@link Double#POSITIVE_INFINITY} if
+ * no end location exists.
+ * @return the 1D end location of the subset or {@link Double#POSITIVE_INFINITY} if
+ * no end location exists
+ */
+ public abstract double getSubspaceEnd();
+
+ /** {@inheritDoc} */
+ @Override
+ public Interval getSubspaceRegion() {
+ final double start = getSubspaceStart();
+ final double end = getSubspaceEnd();
+
+ return Interval.of(start, end, getPrecision());
+ }
+
+ /** Get the 1D interval for the region. This method is an alias for {@link #getSubspaceRegion()}.
+ * @return the 1D interval for the region.
+ */
+ public Interval getInterval() {
+ return getSubspaceRegion();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Split<LineConvexSubset> split(final Hyperplane<Vector2D> splitter) {
+ final Line thisLine = getLine();
+ final Line splitterLine = (Line) splitter;
+
+ final Vector2D intersection = splitterLine.intersection(thisLine);
+ if (intersection == null) {
+ return getNonIntersectingSplitResult(splitterLine, this);
+ }
+ return splitOnIntersection(splitterLine, intersection);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector2D closest(final Vector2D pt) {
+ final Line line = getLine();
+ final double abscissa = line.abscissa(pt);
+
+ return line.toSpace(closestAbscissa(abscissa));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public abstract LineConvexSubset transform(Transform<Vector2D> transform);
+
+ /** {@inheritDoc} */
+ @Override
+ public abstract LineConvexSubset reverse();
+
+ /** Get the closest value in the subspace region to the given abscissa.
+ * @param abscissa input abscissa
+ * @return the closest value in the subspace region to the given abscissa
+ */
+ abstract double closestAbscissa(double abscissa);
+
+ /** Split this instance using the given splitter line and intersection point.
+ * @param splitter splitter line
+ * @param intersection intersection point between the splitter line and the line
+ * for this instance
+ * @return the result of splitting this instance with the given splitter line and intersection
+ * point
+ */
+ abstract Split<LineConvexSubset> splitOnIntersection(Line splitter, Vector2D intersection);
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineSpanningSubset.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineSpanningSubset.java
new file mode 100644
index 0000000..ab16ae3
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineSpanningSubset.java
@@ -0,0 +1,156 @@
+/*
+ * 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.commons.geometry.euclidean.twod;
+
+import java.text.MessageFormat;
+
+import org.apache.commons.geometry.core.RegionLocation;
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.core.partitioning.Split;
+
+/** Class representing the span of a line in 2D Euclidean space. This is the set of all points
+ * contained by the line.
+ *
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ */
+final class LineSpanningSubset extends LineConvexSubset {
+
+ /** Construct a new instance for the given line.
+ * @param line line to construct the span for
+ */
+ LineSpanningSubset(final Line line) {
+ super(line);
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isFull() {
+ return true;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return true;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFinite() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSize() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector2D getStartPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#NEGATIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceStart() {
+ return Double.NEGATIVE_INFINITY;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector2D getEndPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceEnd() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public LineSpanningSubset transform(final Transform<Vector2D> transform) {
+ return new LineSpanningSubset(getLine().transform(transform));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public LineSpanningSubset reverse() {
+ return new LineSpanningSubset(getLine().reverse());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final Line line = getLine();
+
+ return MessageFormat.format(Line.TO_STRING_FORMAT,
+ getClass().getSimpleName(),
+ line.getOrigin(),
+ line.getDirection());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ RegionLocation classifyAbscissa(double abscissa) {
+ return RegionLocation.INSIDE;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ double closestAbscissa(double abscissa) {
+ return abscissa;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ Split<LineConvexSubset> splitOnIntersection(final Line splitter, final Vector2D intersection) {
+ final Line line = getLine();
+
+ final ReverseRay low = new ReverseRay(line, intersection);
+ final Ray high = new Ray(line, intersection);
+
+ return createSplitResult(splitter, low, high);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineSubset.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineSubset.java
new file mode 100644
index 0000000..e8c28aa
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/LineSubset.java
@@ -0,0 +1,156 @@
+/*
+ * 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.commons.geometry.euclidean.twod;
+
+import org.apache.commons.geometry.core.RegionLocation;
+import org.apache.commons.geometry.core.partitioning.AbstractRegionEmbeddingHyperplaneSubset;
+import org.apache.commons.geometry.core.partitioning.Split;
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.oned.Vector1D;
+
+/** Class representing a subset of points on a line in 2D Euclidean space. For example, line segments
+ * and rays are line subsets. Line subsets may be finite or infinite.
+ */
+public abstract class LineSubset extends AbstractRegionEmbeddingHyperplaneSubset<Vector2D, Vector1D, Line> {
+ /** The line containing this instance. */
+ private final Line line;
+
+ /** Construct a new instance based on the given line.
+ * @param line line forming the base of the instance
+ */
+ LineSubset(final Line line) {
+ this.line = line;
+ }
+
+ /** Get the line containing this subset. This method is an alias
+ * for {@link #getHyperplane()}.
+ * @return the line containing this subset
+ * @see #getHyperplane()
+ */
+ public Line getLine() {
+ return getHyperplane();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Line getHyperplane() {
+ return line;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public EmbeddedTreeLineSubset.Builder builder() {
+ return new EmbeddedTreeLineSubset.Builder(line);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public RegionLocation classify(final Vector2D pt) {
+ if (line.contains(pt)) {
+ return classifyAbscissa(line.abscissa(pt));
+ }
+
+ return RegionLocation.OUTSIDE;
+ }
+
+ /** Get the unique intersection of this subset with the given line. Null is
+ * returned if no unique intersection point exists (ie, the lines are
+ * parallel or coincident) or the line does not intersect this instance.
+ * @param inputLine line to intersect with this line subset
+ * @return the unique intersection point between the line and this line subset
+ * or null if no such point exists.
+ * @see Line#intersection(Line)
+ */
+ public Vector2D intersection(final Line inputLine) {
+ final Vector2D pt = line.intersection(inputLine);
+ return (pt != null && contains(pt)) ? pt : null;
+ }
+
+ /** Get the unique intersection of this instance with the given line subset. Null
+ * is returned if the lines containing the line subsets do not have a unique intersection
+ * point (ie, they are parallel or coincident) or the intersection point is unique
+ * but is not contained in both line subsets.
+ * @param subset line subset to intersect with
+ * @return the unique intersection point between this line subset and the argument or
+ * null if no such point exists.
+ * @see Line#intersection(Line)
+ */
+ public Vector2D intersection(final LineSubset subset) {
+ final Vector2D pt = intersection(subset.getLine());
+ return (pt != null && subset.contains(pt)) ? pt : null;
+ }
+
+ /** Return the object used to perform floating point comparisons, which is the
+ * same object used by the underlying {@link Line}).
+ * @return precision object used to perform floating point comparisons.
+ */
+ public DoublePrecisionContext getPrecision() {
+ return line.getPrecision();
+ }
+
+ /** Classify the given line abscissa value with respect to the subspace region.
+ * @param abscissa the abscissa value to classify
+ * @return the region location of the line abscissa value
+ */
+ abstract RegionLocation classifyAbscissa(double abscissa);
+
+ /** Get a split result for cases where no intersection exists between the splitting line and the
+ * line underlying the given line subset. This occurs when the two lines are parallel or coincident.
+ * @param <T> Line subset type
+ * @param splitter splitting line
+ * @param subset line subset instance being split
+ * @return return result of the non-intersecting split operation
+ */
+ <T extends LineSubset> Split<T> getNonIntersectingSplitResult(final Line splitter, final T subset) {
+ // check which side of the splitter we lie on
+ final double offset = splitter.offset(subset.getLine());
+ final int comp = getPrecision().compare(offset, 0.0);
+
+ if (comp < 0) {
+ return new Split<>(subset, null);
+ } else if (comp > 0) {
+ return new Split<>(null, subset);
+ } else {
+ return new Split<>(null, null);
+ }
+ }
+
+ /** Return true if the plus side of the given splitter line is facing in the positive direction
+ * of this line.
+ * @param splitterLine line splitting this instance
+ * @return true if the plus side of the given line is facing in the positive direction of this
+ * line
+ */
+ boolean splitterPlusIsPositiveFacing(final Line splitterLine) {
+ return line.getOffsetDirection().dot(splitterLine.getDirection()) <= 0;
+ }
+
+ /** Create a split result for the given splitter line, given the low and high split portion of this
+ * instance. The arguments are assigned to the split result's minus and plus properties based on the
+ * relative orientation of the splitter line.
+ * @param <T> Line subset type
+ * @param splitter splitter line
+ * @param low portion of the split result closest to negative infinity on this line
+ * @param high portion of th split result closest to positive infinity on this line
+ * @return a split result for the given splitter line.
+ */
+ <T extends LineSubset> Split<T> createSplitResult(final Line splitter, final T low, final T high) {
+ return splitterPlusIsPositiveFacing(splitter) ?
+ new Split<>(low, high) :
+ new Split<>(high, low);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Linecastable2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Linecastable2D.java
index a9ee49e..8575477 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Linecastable2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Linecastable2D.java
@@ -21,11 +21,11 @@ import java.util.List;
/** Interface for objects that support linecast operations in Euclidean 2D space.
*
* <p>
- * Linecasting is a process that takes a line or line segment and intersects it with
+ * Linecasting is a process that takes a line or convex line subset and intersects it with
* the boundaries of a region. This is similar to
* <a href="https://en.wikipedia.org/wiki/Ray_casting">raycasting</a> used
* for collision detection with the exception that the intersecting element can be a
- * line or line segment and not just a ray.
+ * line or convex line subset and not just a ray.
* </p>
*/
public interface Linecastable2D {
@@ -41,14 +41,14 @@ public interface Linecastable2D {
return linecast(line.span());
}
- /** Intersect the given line segment against the boundaries in this instance, returning
+ /** Intersect the given line subset against the boundaries in this instance, returning
* a list of all intersections in order of increasing position along the line. An empty
* list is returned if no intersections are discovered.
- * @param segment segment to intersect
+ * @param subset line subset to intersect
* @return a list of computed intersections in order of increasing position
* along the line
*/
- List<LinecastPoint2D> linecast(Segment segment);
+ List<LinecastPoint2D> linecast(LineConvexSubset subset);
/** Intersect the given line against the boundaries in this instance, returning
* the first intersection found when traveling in the direction of the line from
@@ -61,12 +61,12 @@ public interface Linecastable2D {
return linecastFirst(line.span());
}
- /** Intersect the given line segment against the boundaries in this instance, returning
- * the first intersection found when traveling in the direction of the line segment
- * from its start point.
- * @param segment segment to intersect
+ /** Intersect the given line subset against the boundaries in this instance, returning
+ * the first intersection found when traveling in the direction of the line subset
+ * from its start location.
+ * @param subset line subset to intersect
* @return the first intersection found or null if no intersection
* is found
*/
- LinecastPoint2D linecastFirst(Segment segment);
+ LinecastPoint2D linecastFirst(LineConvexSubset subset);
}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Lines.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Lines.java
new file mode 100644
index 0000000..5915fe0
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Lines.java
@@ -0,0 +1,277 @@
+/*
+ * 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.commons.geometry.euclidean.twod;
+
+import java.text.MessageFormat;
+
+import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
+import org.apache.commons.geometry.euclidean.oned.Interval;
+
+/** Class containing factory methods for constructing {@link Line} and {@link LineSubset} instances.
+ */
+public final class Lines {
+
+ /** Utility class; no instantiation. */
+ private Lines() {
+ }
+
+ /** Create a line from two points lying on the line. The line points in the direction
+ * from {@code p1} to {@code p2}.
+ * @param p1 first point
+ * @param p2 second point
+ * @param precision precision context used to compare floating point values
+ * @return new line containing {@code p1} and {@code p2} and pointing in the direction
+ * from {@code p1} to {@code p2}
+ * @throws IllegalArgumentException If the vector between {@code p1} and {@code p2} has zero length,
+ * as evaluated by the given precision context
+ */
+ public static Line fromPoints(final Vector2D p1, final Vector2D p2, final DoublePrecisionContext precision) {
+ return fromPointAndDirection(p1, p1.vectorTo(p2), precision);
+ }
+
+ /** Create a line from a point and direction.
+ * @param pt point belonging to the line
+ * @param dir the direction of the line
+ * @param precision precision context used to compare floating point values
+ * @return new line containing {@code pt} and pointing in direction {@code dir}
+ * @throws IllegalArgumentException If {@code dir} has zero length, as evaluated by the
+ * given precision context
+ */
+ public static Line fromPointAndDirection(final Vector2D pt, final Vector2D dir,
+ final DoublePrecisionContext precision) {
+ if (dir.isZero(precision)) {
+ throw new IllegalArgumentException("Line direction cannot be zero");
+ }
+
+ final Vector2D normalizedDir = dir.normalize();
+ final double originOffset = normalizedDir.signedArea(pt);
+
+ return new Line(normalizedDir, originOffset, precision);
+ }
+
+ /** Create a line from a point lying on the line and an angle relative to the abscissa (x) axis. Note that the
+ * line does not need to intersect the x-axis; the given angle is simply relative to it.
+ * @param pt point belonging to the line
+ * @param angle angle of the line with respect to abscissa (x) axis, in radians
+ * @param precision precision context used to compare floating point values
+ * @return new line containing {@code pt} and forming the given angle with the
+ * abscissa (x) axis.
+ */
+ public static Line fromPointAndAngle(final Vector2D pt, final double angle,
+ final DoublePrecisionContext precision) {
+ final Vector2D.Unit dir = Vector2D.Unit.from(Math.cos(angle), Math.sin(angle));
+ return fromPointAndDirection(pt, dir, precision);
+ }
+
+ /** Construct a ray from a start point and a direction.
+ * @param startPoint ray start point
+ * @param direction ray direction
+ * @param precision precision context used for floating point comparisons
+ * @return a new ray instance with the given start point and direction
+ * @throws IllegalArgumentException If {@code direction} has zero length, as evaluated by the
+ * given precision context
+ * @see #fromPointAndDirection(Vector2D, Vector2D, DoublePrecisionContext)
+ */
+ public static Ray rayFromPointAndDirection(final Vector2D startPoint, final Vector2D direction,
+ final DoublePrecisionContext precision) {
+ final Line line = Lines.fromPointAndDirection(startPoint, direction, precision);
+
+ return new Ray(line, startPoint);
+ }
+
+ /** Construct a ray starting at the given point and continuing to infinity in the direction
+ * of {@code line}. The given point is projected onto the line.
+ * @param line line for the ray
+ * @param startPoint start point for the ray
+ * @return a new ray instance starting at the given point and continuing in the direction of
+ * {@code line}
+ * @throws IllegalArgumentException if any coordinate in {@code startPoint} is NaN or infinite
+ */
+ public static Ray rayFromPoint(final Line line, final Vector2D startPoint) {
+ return rayFromLocation(line, line.abscissa(startPoint));
+ }
+
+ /** Construct a ray starting at the given 1D location on {@code line} and continuing in the
+ * direction of the line to infinity.
+ * @param line line for the ray
+ * @param startLocation 1D location of the ray start point
+ * @return a new ray instance starting at the given 1D location and continuing to infinity
+ * along {@code line}
+ * @throws IllegalArgumentException if {@code startLocation} is NaN or infinite
+ */
+ public static Ray rayFromLocation(final Line line, final double startLocation) {
+ if (!Double.isFinite(startLocation)) {
+ throw new IllegalArgumentException("Invalid ray start location: " + Double.toString(startLocation));
+ }
+
+ return new Ray(line, startLocation);
+ }
+
+ /** Construct a reverse ray from an end point and a line direction.
+ * @param endPoint instance end point
+ * @param lineDirection line direction
+ * @param precision precision context used for floating point comparisons
+ * @return a new instance with the given end point and line direction
+ * @throws IllegalArgumentException If {@code lineDirection} has zero length, as evaluated by the
+ * given precision context
+ * @see #fromPointAndDirection(Vector2D, Vector2D, DoublePrecisionContext)
+ */
+ public static ReverseRay reverseRayFromPointAndDirection(final Vector2D endPoint, final Vector2D lineDirection,
+ final DoublePrecisionContext precision) {
+ final Line line = Lines.fromPointAndDirection(endPoint, lineDirection, precision);
+
+ return new ReverseRay(line, endPoint);
+ }
+
+ /** Construct a reverse ray starting at infinity and continuing in the direction of {@code line}
+ * to the given end point. The point is projected onto the line.
+ * @param line line for the instance
+ * @param endPoint end point for the instance
+ * @return a new instance starting at infinity and continuing along the line to {@code endPoint}
+ * @throws IllegalArgumentException if any coordinate in {@code endPoint} is NaN or infinite
+ */
+ public static ReverseRay reverseRayFromPoint(final Line line, final Vector2D endPoint) {
+ return reverseRayFromLocation(line, line.abscissa(endPoint));
+ }
+
+ /** Construct a reverse ray starting at infinity and continuing in the direction of {@code line}
+ * to the given 1D end location.
+ * @param line line for the instance
+ * @param endLocation 1D location of the instance end point
+ * @return a new instance starting infinity and continuing in the direction of {@code line}
+ * to the given 1D end location
+ * @throws IllegalArgumentException if {@code endLocation} is NaN or infinite
+ */
+ public static ReverseRay reverseRayFromLocation(final Line line, final double endLocation) {
+ if (!Double.isFinite(endLocation)) {
+ throw new IllegalArgumentException("Invalid reverse ray end location: " + Double.toString(endLocation));
+ }
+
+ return new ReverseRay(line, endLocation);
+ }
+
+ /** Construct a new line segment from two points. A new line is created for the segment and points in the
+ * direction from {@code startPoint} to {@code endPoint}.
+ * @param startPoint segment start point
+ * @param endPoint segment end point
+ * @param precision precision context to use for floating point comparisons
+ * @return a new line segment instance with the given start and end points
+ * @throws IllegalArgumentException If the vector between {@code startPoint} and {@code endPoint} has zero length,
+ * as evaluated by the given precision context
+ */
+ public static Segment segmentFromPoints(final Vector2D startPoint, final Vector2D endPoint,
+ final DoublePrecisionContext precision) {
+ final Line line = Lines.fromPoints(startPoint, endPoint, precision);
+
+ // we know that the points lie on the line and are in increasing abscissa order
+ // since they were used to create the line
+ return new Segment(line, startPoint, endPoint);
+ }
+
+ /** Construct a new line segment from a line and a pair of points. The returned segment represents
+ * all points on the line between the projected locations of {@code a} and {@code b}. The points may
+ * be given in any order.
+ * @param line line forming the base of the segment
+ * @param a first point
+ * @param b second point
+ * @return a new line segment representing the points between the projected locations of {@code a}
+ * and {@code b} on the given line
+ * @throws IllegalArgumentException if either point contains NaN or infinite coordinate values
+ */
+ public static Segment segmentFromPoints(final Line line, final Vector2D a, final Vector2D b) {
+ return segmentFromLocations(line, line.abscissa(a), line.abscissa(b));
+ }
+
+ /** Construct a new line segment from a pair of 1D locations on a line. The returned line
+ * segment consists of all points between the two locations, regardless of the order the
+ * arguments are given.
+ * @param line line forming the base of the segment
+ * @param a first 1D location on the line
+ * @param b second 1D location on the line
+ * @return a new line segment representing the points between {@code a} and {@code b} on
+ * the given line
+ * @throws IllegalArgumentException if either of the locations is NaN or infinite
+ */
+ public static Segment segmentFromLocations(final Line line, final double a, final double b) {
+
+ if (Double.isFinite(a) && Double.isFinite(b)) {
+ final double min = Math.min(a, b);
+ final double max = Math.max(a, b);
+
+ return new Segment(line, min, max);
+ }
+
+ throw new IllegalArgumentException(
+ MessageFormat.format("Invalid line segment locations: {0}, {1}",
+ Double.toString(a), Double.toString(b)));
+ }
+
+ /** Create a {@link LineConvexSubset} spanning the entire line. In other words, the returned
+ * subset is infinite and contains all points on the given line.
+ * @param line the line to span
+ * @return a convex subset spanning the entire line
+ */
+ public static LineConvexSubset span(final Line line) {
+ return new LineSpanningSubset(line);
+ }
+
+ /** Create a line subset from a line and a 1D interval on the line. The returned subset
+ * uses the precision context from the line and not any precision contexts referenced by the interval.
+ * @param line the line containing the subset
+ * @param interval 1D interval on the line
+ * @return a convex subset defined by the given line and interval
+ */
+ public static LineConvexSubset subsetFromInterval(final Line line, final Interval interval) {
+ return subsetFromInterval(line, interval.getMin(), interval.getMax());
+ }
+
+ /** Create a line subset from a line and a 1D interval on the line. The double values may be given in any
+ * order and support the use of infinite values. For example, the call
+ * {@code Lines.subsetFromInterval(line, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)} will return
+ * an instance representing the full span of the line.
+ * @param line the line containing the subset
+ * @param a first 1D location on the line
+ * @param b second 1D location on the line
+ * @return a line subset defined by the given line and interval
+ * @throws IllegalArgumentException if either double value is NaN or both are infinite with the same sign
+ * (eg, both positive infinity or both negative infinity)
+ */
+ public static LineConvexSubset subsetFromInterval(final Line line, final double a, final double b) {
+ final double min = Math.min(a, b);
+ final double max = Math.max(a, b);
+
+ final boolean hasMin = Double.isFinite(min);
+ final boolean hasMax = Double.isFinite(max);
+
+ if (hasMin) {
+ if (hasMax) {
+ // has both
+ return new Segment(line, min, max);
+ }
+ // min only
+ return new Ray(line, min);
+ } else if (hasMax) {
+ // max only
+ return new ReverseRay(line, max);
+ } else if (Double.isInfinite(min) && Double.isInfinite(max) && Double.compare(min, max) < 0) {
+ return new LineSpanningSubset(line);
+ }
+
+ throw new IllegalArgumentException(MessageFormat.format(
+ "Invalid line subset interval: {0}, {1}", Double.toString(a), Double.toString(b)));
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Ray.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Ray.java
new file mode 100644
index 0000000..c817727
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Ray.java
@@ -0,0 +1,194 @@
+/*
+ * 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.commons.geometry.euclidean.twod;
+
+import org.apache.commons.geometry.core.RegionLocation;
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.core.partitioning.Split;
+
+/** Class representing a ray in 2D Euclidean space. A ray is a portion of a line consisting of
+ * a single start point and extending to infinity along the direction of the line.
+ *
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see ReverseRay
+ * @see Lines
+ */
+public final class Ray extends LineConvexSubset {
+
+ /** The start abscissa value for the ray. */
+ private final double start;
+
+ /** Construct a ray from a line and a start point. The start point is projected
+ * onto the line. No validation is performed.
+ * @param line line for the ray
+ * @param startPoint start point for the ray
+ */
+ Ray(final Line line, final Vector2D startPoint) {
+ this(line, line.abscissa(startPoint));
+ }
+
+ /** Construct a ray from a line and a 1D start location. No validation is performed.
+ * @param line line for the ray
+ * @param start 1D start location
+ */
+ Ray(final Line line, final double start) {
+ super(line);
+
+ this.start = start;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFull() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return true;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFinite() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSize() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ @Override
+ public Vector2D getStartPoint() {
+ return getLine().toSpace(start);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSubspaceStart() {
+ return start;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector2D getEndPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceEnd() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** Get the direction of the ray. This is a convenience method for {@code ray.getLine().getDirection()}.
+ * @return the direction of the ray
+ */
+ public Vector2D getDirection() {
+ return getLine().getDirection();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Ray transform(final Transform<Vector2D> transform) {
+ final Line tLine = getLine().transform(transform);
+ final Vector2D tStart = transform.apply(getStartPoint());
+
+ return new Ray(tLine, tStart);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ReverseRay reverse() {
+ return new ReverseRay(getLine().reverse(), -start);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName())
+ .append("[startPoint= ")
+ .append(getStartPoint())
+ .append(", direction= ")
+ .append(getLine().getDirection())
+ .append(']');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ RegionLocation classifyAbscissa(double abscissa) {
+ int cmp = getPrecision().compare(abscissa, start);
+ if (cmp > 0) {
+ return RegionLocation.INSIDE;
+ } else if (cmp == 0) {
+ return RegionLocation.BOUNDARY;
+ }
+
+ return RegionLocation.OUTSIDE;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ double closestAbscissa(double abscissa) {
+ return Math.max(start, abscissa);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ Split<LineConvexSubset> splitOnIntersection(final Line splitter, final Vector2D intersection) {
+
+ final Line line = getLine();
+ final double splitAbscissa = line.abscissa(intersection);
+
+ LineConvexSubset low = null;
+ LineConvexSubset high = null;
+
+ int cmp = getPrecision().compare(splitAbscissa, start);
+ if (cmp > 0) {
+ low = new Segment(line, start, splitAbscissa);
+ high = new Ray(line, splitAbscissa);
+ } else {
+ high = this;
+ }
+
+ return createSplitResult(splitter, low, high);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2D.java
index 3e3c12a..004b369 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/RegionBSPTree2D.java
@@ -29,15 +29,17 @@ import org.apache.commons.geometry.core.partitioning.bsp.AbstractBSPTree;
import org.apache.commons.geometry.core.partitioning.bsp.AbstractRegionBSPTree;
import org.apache.commons.geometry.core.partitioning.bsp.BSPTreeVisitor;
import org.apache.commons.geometry.core.partitioning.bsp.RegionCutBoundary;
+import org.apache.commons.geometry.euclidean.twod.path.InteriorAngleLinePathConnector;
+import org.apache.commons.geometry.euclidean.twod.path.LinePath;
/** Binary space partitioning (BSP) tree representing a region in two dimensional
* Euclidean space.
*/
public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, RegionBSPTree2D.RegionNode2D>
- implements BoundarySource2D, Linecastable2D {
+ implements BoundarySource2D {
- /** List of line segment paths comprising the region boundary. */
- private List<Polyline> boundaryPaths;
+ /** List of line subset paths comprising the region boundary. */
+ private List<LinePath> boundaryPaths;
/** Create a new, empty region.
*/
@@ -67,28 +69,28 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
/** {@inheritDoc} */
@Override
- public Iterable<Segment> boundaries() {
- return createBoundaryIterable(b -> (Segment) b);
+ public Iterable<LineConvexSubset> boundaries() {
+ return createBoundaryIterable(b -> (LineConvexSubset) b);
}
/** {@inheritDoc} */
@Override
- public Stream<Segment> boundaryStream() {
+ public Stream<LineConvexSubset> boundaryStream() {
return StreamSupport.stream(boundaries().spliterator(), false);
}
/** {@inheritDoc} */
@Override
- public List<Segment> getBoundaries() {
- return createBoundaryList(b -> (Segment) b);
+ public List<LineConvexSubset> getBoundaries() {
+ return createBoundaryList(b -> (LineConvexSubset) b);
}
- /** Get the boundary of the region as a list of connected line segment paths. The
- * line segments are oriented such that their minus (left) side lies on the
+ /** Get the boundary of the region as a list of connected line subset paths.
+ * The line subset are oriented such that their minus (left) side lies on the
* interior of the region.
- * @return line segment paths representing the region boundary
+ * @return line subset paths representing the region boundary
*/
- public List<Polyline> getBoundaryPaths() {
+ public List<LinePath> getBoundaryPaths() {
if (boundaryPaths == null) {
boundaryPaths = Collections.unmodifiableList(computeBoundaryPaths());
}
@@ -165,8 +167,8 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
/** {@inheritDoc} */
@Override
- public List<LinecastPoint2D> linecast(final Segment segment) {
- final LinecastVisitor visitor = new LinecastVisitor(segment, false);
+ public List<LinecastPoint2D> linecast(final LineConvexSubset subset) {
+ final LinecastVisitor visitor = new LinecastVisitor(subset, false);
accept(visitor);
return visitor.getResults();
@@ -174,22 +176,22 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
/** {@inheritDoc} */
@Override
- public LinecastPoint2D linecastFirst(final Segment segment) {
- final LinecastVisitor visitor = new LinecastVisitor(segment, true);
+ public LinecastPoint2D linecastFirst(final LineConvexSubset subset) {
+ final LinecastVisitor visitor = new LinecastVisitor(subset, true);
accept(visitor);
return visitor.getFirstResult();
}
- /** Compute the line segment paths comprising the region boundary.
- * @return the line segment paths comprising the region boundary
+ /** Compute the line subset paths comprising the region boundary.
+ * @return the line subset paths comprising the region boundary
*/
- private List<Polyline> computeBoundaryPaths() {
- final InteriorAngleSegmentConnector connector = new InteriorAngleSegmentConnector.Minimize();
+ private List<LinePath> computeBoundaryPaths() {
+ final InteriorAngleLinePathConnector connector = new InteriorAngleLinePathConnector.Minimize();
connector.connect(boundaries());
return connector.connectAll().stream()
- .map(Polyline::simplify).collect(Collectors.toList());
+ .map(LinePath::simplify).collect(Collectors.toList());
}
/** {@inheritDoc} */
@@ -202,7 +204,7 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
return new RegionSizeProperties<>(0, null);
}
- // compute the size based on the boundary segments
+ // compute the size based on the boundary line subsets
double quadrilateralAreaSum = 0.0;
double scaledSumX = 0.0;
@@ -212,9 +214,9 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
Vector2D endPoint;
double signedArea;
- for (final Segment segment : boundaries()) {
+ for (final LineConvexSubset boundary : boundaries()) {
- if (segment.isInfinite()) {
+ if (boundary.isInfinite()) {
// at least on boundary is infinite, meaning that
// the size is also infinite
quadrilateralAreaSum = Double.POSITIVE_INFINITY;
@@ -222,8 +224,8 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
break;
}
- startPoint = segment.getStartPoint();
- endPoint = segment.getEndPoint();
+ startPoint = boundary.getStartPoint();
+ endPoint = boundary.getEndPoint();
// compute the area
signedArea = startPoint.signedArea(endPoint);
@@ -286,7 +288,7 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
* @return a new tree instance constructed from the given boundaries
* @see #from(Iterable, boolean)
*/
- public static RegionBSPTree2D from(final Iterable<Segment> boundaries) {
+ public static RegionBSPTree2D from(final Iterable<LineConvexSubset> boundaries) {
return from(boundaries, false);
}
@@ -297,7 +299,7 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
* @param full if true, the initial tree will contain the entire space
* @return a new tree instance constructed from the given boundaries
*/
- public static RegionBSPTree2D from(final Iterable<Segment> boundaries, final boolean full) {
+ public static RegionBSPTree2D from(final Iterable<LineConvexSubset> boundaries, final boolean full) {
final RegionBSPTree2D tree = new RegionBSPTree2D(full);
tree.insert(boundaries);
@@ -366,8 +368,8 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
*/
private static final class LinecastVisitor implements BSPTreeVisitor<Vector2D, RegionNode2D> {
- /** The line segment to intersect with the boundaries of the BSP tree. */
- private final Segment linecastSegment;
+ /** The line subset to intersect with the boundaries of the BSP tree. */
+ private final LineConvexSubset linecastSubset;
/** If true, the visitor will stop visiting the tree once the first linecast
* point is determined.
@@ -380,13 +382,13 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
/** List of results from the linecast operation. */
private final List<LinecastPoint2D> results = new ArrayList<>();
- /** Create a new instance with the given intersecting line segment.
- * @param linecastSegment segment to intersect with the BSP tree region boundary
+ /** Create a new instance with the given intersecting line subset.
+ * @param linecastSubset line subset to intersect with the BSP tree region boundary
* @param firstOnly if true, the visitor will stop visiting the tree once the first
* linecast point is determined
*/
- LinecastVisitor(final Segment linecastSegment, final boolean firstOnly) {
- this.linecastSegment = linecastSegment;
+ LinecastVisitor(final LineConvexSubset linecastSubset, final boolean firstOnly) {
+ this.linecastSubset = linecastSubset;
this.firstOnly = firstOnly;
}
@@ -415,7 +417,7 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
@Override
public Order visitOrder(final RegionNode2D internalNode) {
final Line cut = (Line) internalNode.getCutHyperplane();
- final Line line = linecastSegment.getLine();
+ final Line line = linecastSubset.getLine();
final boolean plusIsNear = line.getDirection().dot(cut.getOffsetDirection()) < 0;
@@ -428,8 +430,8 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
@Override
public Result visit(final RegionNode2D node) {
if (node.isInternal()) {
- // check if the line segment intersects the cut subhyperplane
- final Line line = linecastSegment.getLine();
+ // check if the line subset intersects the node cut
+ final Line line = linecastSubset.getLine();
final Vector2D pt = ((Line) node.getCutHyperplane()).intersection(line);
if (pt != null) {
@@ -438,7 +440,7 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
// we have results and we are now sure that no other intersection points will be
// found that are closer or at the same position on the intersecting line.
return Result.TERMINATE;
- } else if (linecastSegment.contains(pt)) {
+ } else if (linecastSubset.contains(pt)) {
// we've potentially found a new linecast point; add it to the list of potential
// results
final LinecastPoint2D potentialResult = computeLinecastPoint(pt, node);
@@ -458,8 +460,7 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
/** Compute the linecast point for the given intersection point and tree node, returning null
* if the point does not actually lie on the region boundary.
* @param pt intersection point
- * @param node node containing the cut subhyperplane that the linecast line
- * intersected with
+ * @param node node containing the cut that the linecast line intersected with
* @return a new linecast point instance or null if the intersection point does not lie
* on the region boundary
*/
@@ -485,7 +486,7 @@ public final class RegionBSPTree2D extends AbstractRegionBSPTree<Vector2D, Regio
normal = normal.negate();
}
- return new LinecastPoint2D(pt, normal, linecastSegment.getLine());
+ return new LinecastPoint2D(pt, normal, linecastSubset.getLine());
}
return null;
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/ReverseRay.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/ReverseRay.java
new file mode 100644
index 0000000..766b912
--- /dev/null
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/ReverseRay.java
@@ -0,0 +1,189 @@
+/*
+ * 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.commons.geometry.euclidean.twod;
+
+import org.apache.commons.geometry.core.RegionLocation;
+import org.apache.commons.geometry.core.Transform;
+import org.apache.commons.geometry.core.partitioning.Split;
+
+/** Class representing a portion of a line in 2D Euclidean space that starts at infinity and
+ * continues in the direction of the line up to a single end point. This is equivalent to taking a
+ * {@link Ray} and reversing the line direction.
+ *
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see Ray
+ * @see Lines
+ */
+public final class ReverseRay extends LineConvexSubset {
+
+ /** The abscissa of the endpoint. */
+ private final double end;
+
+ /** Construct a new instance from the given line and end point. The end point is projected onto
+ * the line. No validation is performed.
+ * @param line line for the instance
+ * @param endPoint end point for the instance
+ */
+ ReverseRay(final Line line, final Vector2D endPoint) {
+ this(line, line.abscissa(endPoint));
+ }
+
+ /** Construct a new instance from the given line and 1D end location. No validation is performed.
+ * @param line line for the instance
+ * @param end end location for the instance
+ */
+ ReverseRay(final Line line, final double end) {
+ super(line);
+
+ this.end = end;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFull() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return true;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFinite() {
+ return false;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSize() {
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code null}.</p>
+ */
+ @Override
+ public Vector2D getStartPoint() {
+ return null;
+ }
+
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@link Double#NEGATIVE_INFINITY}.</p>
+ */
+ @Override
+ public double getSubspaceStart() {
+ return Double.NEGATIVE_INFINITY;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Vector2D getEndPoint() {
+ return getLine().toSpace(end);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double getSubspaceEnd() {
+ return end;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ReverseRay transform(final Transform<Vector2D> transform) {
+ final Line tLine = getLine().transform(transform);
+ final Vector2D tEnd = transform.apply(getEndPoint());
+
+ return new ReverseRay(tLine, tEnd);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Ray reverse() {
+ return new Ray(getLine().reverse(), -end);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName())
+ .append("[direction= ")
+ .append(getLine().getDirection())
+ .append(", endPoint= ")
+ .append(getEndPoint())
+ .append(']');
+
+ return sb.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ RegionLocation classifyAbscissa(double abscissa) {
+ int cmp = getPrecision().compare(abscissa, end);
+ if (cmp < 0) {
+ return RegionLocation.INSIDE;
+ } else if (cmp == 0) {
+ return RegionLocation.BOUNDARY;
+ }
+
+ return RegionLocation.OUTSIDE;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ double closestAbscissa(double abscissa) {
+ return Math.min(end, abscissa);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected Split<LineConvexSubset> splitOnIntersection(final Line splitter, final Vector2D intersection) {
+
+ final Line line = getLine();
+ final double splitAbscissa = line.abscissa(intersection);
+
+ LineConvexSubset low = null;
+ LineConvexSubset high = null;
+
+ int cmp = getPrecision().compare(splitAbscissa, end);
+ if (cmp < 0) {
+ low = new ReverseRay(line, splitAbscissa);
+ high = new Segment(line, splitAbscissa, end);
+ } else {
+ low = this;
+ }
+
+ return createSplitResult(splitter, low, high);
+ }
+}
diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
index 2084714..0464ccd 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/Segment.java
@@ -16,290 +16,185 @@
*/
package org.apache.commons.geometry.euclidean.twod;
-import java.util.Arrays;
-import java.util.List;
-
+import org.apache.commons.geometry.core.RegionLocation;
import org.apache.commons.geometry.core.Transform;
-import org.apache.commons.geometry.core.partitioning.ConvexSubHyperplane;
-import org.apache.commons.geometry.core.partitioning.Hyperplane;
import org.apache.commons.geometry.core.partitioning.Split;
import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
-import org.apache.commons.geometry.euclidean.oned.AffineTransformMatrix1D;
-import org.apache.commons.geometry.euclidean.oned.Interval;
-import org.apache.commons.geometry.euclidean.oned.Vector1D;
-import org.apache.commons.geometry.euclidean.twod.Line.SubspaceTransform;
-/** <p>Class representing a line segment in 2D Euclidean space. Segments
- * need not be finite, in which case the start or end point (or both)
- * will be null.</p>
+/** Class representing a line segment in 2D Euclidean space. A line segment is a portion of
+ * a line with finite start and end points.
*
* <p>Instances of this class are guaranteed to be immutable.</p>
+ * @see Lines
+ * @see <a href="https://en.wikipedia.org/wiki/Line_segment">Line Segment</a>
*/
-public final class Segment extends AbstractSubLine
- implements ConvexSubHyperplane<Vector2D> {
- /** String used to indicate the start point of the segment in the toString() representation. */
- private static final String START_STR = "start= ";
-
- /** String used to indicate the direction the segment in the toString() representation. */
- private static final String DIR_STR = "direction= ";
+public final class Segment extends LineConvexSubset {
- /** String used to indicate the end point of the segment in the toString() representation. */
- private static final String END_STR = "end= ";
+ /** Start abscissa for the segment. */
+ private final double start;
- /** String used as a separator value in the toString() representation. */
- private static final String SEP_STR = ", ";
-
- /** The interval representing the region of the line contained in
- * the line segment.
- */
- private final Interval interval;
+ /** End abscissa for the segment. */
+ private final double end;
- /** Construct a line segment from an underlying line and a 1D interval
- * on it.
- * @param line the underlying line
- * @param interval 1D interval on the line defining the line segment
+ /** Construct a new instance from a line and two points on the line. The points are projected onto
+ * the line and must be in order of increasing abscissa. No validation is performed.
+ * @param line line for the segment
+ * @param startPoint segment start point
+ * @param endPoint segment end point
*/
- private Segment(final Line line, final Interval interval) {
- super(line);
-
- this.interval = interval;
+ Segment(final Line line, final Vector2D startPoint, final Vector2D endPoint) {
+ this(line, line.abscissa(startPoint), line.abscissa(endPoint));
}
- /** Get the start value in the 1D subspace of the line.
- * @return the start value in the 1D subspace of the line.
+ /** Construct a new instance from a line and two abscissa locations on the line.
+ * The abscissa locations must be in increasing order. No validation is performed.
+ * @param line line for the segment
+ * @param start abscissa start location
+ * @param end abscissa end location
*/
- public double getSubspaceStart() {
- return interval.getMin();
- }
+ Segment(final Line line, final double start, final double end) {
+ super(line);
- /** Get the end value in the 1D subspace of the line.
- * @return the end value in the 1D subspace of the line
- */
- public double getSubspaceEnd() {
- return interval.getMax();
+ this.start = start;
+ this.end = end;
}
- /** Get the start point of the line segment or null if no start point
- * exists (ie, the segment is infinite).
- * @return the start point of the line segment or null if no start point
- * exists
- */
- public Vector2D getStartPoint() {
- return interval.hasMinBoundary() ? getLine().toSpace(interval.getMin()) : null;
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isFull() {
+ return false;
}
- /** Get the end point of the line segment or null if no end point
- * exists (ie, the segment is infinite).
- * @return the end point of the line segment or null if no end point
- * exists
- */
- public Vector2D getEndPoint() {
- return interval.hasMaxBoundary() ? getLine().toSpace(interval.getMax()) : null;
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code false}.</p>
+ */
+ @Override
+ public boolean isInfinite() {
+ return false;
}
- /** Return the 1D interval for the line segment.
- * @return the 1D interval for the line segment
- * @see #getSubspaceRegion()
+ /** {@inheritDoc}
+ *
+ * <p>This method always returns {@code true}.</p>
*/
- public Interval getInterval() {
- return interval;
+ @Override
+ public boolean isFinite() {
+ return true;
}
/** {@inheritDoc} */
@Override
- public boolean isInfinite() {
- return interval.isInfinite();
+ public double getSize() {
+ return end - start;
}
/** {@inheritDoc} */
@Override
- public boolean isFinite() {
- return interval.isFinite();
+ public Vector2D getStartPoint() {
+ return getLine().toSpace(start);
}
/** {@inheritDoc} */
@Override
- public Interval getSubspaceRegion() {
- return getInterval();
+ public double getSubspaceStart() {
+ return start;
}
/** {@inheritDoc} */
@Override
- public List<Segment> toConvex() {
- return Arrays.asList(this);
+ public Vector2D getEndPoint() {
+ return getLine().toSpace(end);
}
/** {@inheritDoc} */
@Override
- public Split<Segment> split(final Hyperplane<Vector2D> splitter) {
- return splitInternal(splitter, this, (line, region) -> new Segment(line, (Interval) region));
+ public double getSubspaceEnd() {
+ return end;
}
/** {@inheritDoc} */
@Override
- public Segment transform(Transform<Vector2D> transform) {
- final Line line = getLine();
- final SubspaceTransform st = line.subspaceTransform(transform);
-
- return fromInterval(st.getLine(), interval.transform(st.getTransform()));
- }
+ public Segment transform(final Transform<Vector2D> transform) {
+ final Vector2D t1 = transform.apply(getStartPoint());
+ final Vector2D t2 = transform.apply(getEndPoint());
- /** Get the unique intersection of this segment with the given line. Null is
- * returned if no unique intersection point exists (ie, the lines are
- * parallel or coincident) or the line does not intersect the segment.
- * @param line line to intersect with this segment
- * @return the unique intersection point between the line and this segment
- * or null if no such point exists.
- * @see Line#intersection(Line)
- */
- public Vector2D intersection(final Line line) {
- final Vector2D pt = getLine().intersection(line);
- return (pt != null && contains(pt)) ? pt : null;
- }
+ final Line tLine = getLine().transform(transform);
- /** Get the unique intersection of this instance with the given segment. Null
- * is returned if the lines containing the segments do not have a unique intersection
- * point (ie, they are parallel or coincident) or the intersection point is unique
- * but in not contained in both segments.
- * @param segment segment to intersect with
- * @return the unique intersection point between this segment and the argument or
- * null if no such point exists.
- * @see Line#intersection(Line)
- */
- public Vector2D intersection(final Segment segment) {
- final Vector2D pt = intersection(segment.getLine());
- return (pt != null && segment.contains(pt)) ? pt : null;
+ return new Segment(tLine, t1, t2);
}
/** {@inheritDoc} */
@Override
public Segment reverse() {
- final Interval reversedInterval = interval.transform(AffineTransformMatrix1D.createScale(-1));
- return fromInterval(getLine().reverse(), reversedInterval);
+ return new Segment(getLine().reverse(), -end, -start);
}
- /** Return a string representation of the segment.
- *
- * <p>In order to keep the representation short but informative, the exact format used
- * depends on the properties of the instance, as demonstrated in the examples
- * below.
- * <ul>
- * <li>Infinite segment -
- * {@code "Segment[lineOrigin= (0.0, 0.0), lineDirection= (1.0, 0.0)]"}</li>
- * <li>Start point but no end point -
- * {@code "Segment[start= (0.0, 0.0), direction= (1.0, 0.0)]"}</li>
- * <li>End point but no start point -
- * {@code "Segment[direction= (1.0, 0.0), end= (0.0, 0.0)]"}</li>
- * <li>Start point and end point -
- * {@code "Segment[start= (0.0, 0.0), end= (1.0, 0.0)]"}</li>
- * </ul>
- */
+ /** {@inheritDoc} */
@Override
public String toString() {
- final Vector2D startPoint = getStartPoint();
- final Vector2D endPoint = getEndPoint();
-
final StringBuilder sb = new StringBuilder();
- sb.append(this.getClass().getSimpleName())
- .append('[');
-
- if (startPoint != null && endPoint != null) {
- sb.append(START_STR)
- .append(startPoint)
- .append(SEP_STR)
- .append(END_STR)
- .append(endPoint);
- } else if (startPoint != null) {
- sb.append(START_STR)
- .append(startPoint)
- .append(SEP_STR)
- .append(DIR_STR)
- .append(getLine().getDirection());
- } else if (endPoint != null) {
- sb.append(DIR_STR)
- .append(getLine().getDirection())
- .append(SEP_STR)
- .append(END_STR)
- .append(endPoint);
- } else {
- final Line line = getLine();
-
- sb.append("lineOrigin= ")
- .append(line.getOrigin())
- .append(", lineDirection= ")
- .append(line.getDirection());
- }
-
- sb.append(']');
+ sb.append(getClass().getSimpleName())
+ .append("[startPoint= ")
+ .append(getStartPoint())
+ .append(", endPoint= ")
+ .append(getEndPoint())
+ .append(']');
return sb.toString();
}
- /** Create a line segment between two points. The underlying line points in the direction from {@code start}
- * to {@code end}.
- * @param start start point for the line segment
- * @param end end point for the line segment
- * @param precision precision context used to determine floating point equality
- * @return a new line segment between {@code start} and {@code end}.
- */
- public static Segment fromPoints(final Vector2D start, final Vector2D end, final DoublePrecisionContext precision) {
- final Line line = Line.fromPoints(start, end, precision);
- return fromPointsOnLine(line, start, end);
- }
-
- /** Construct a line segment from a starting point and a direction that the line should extend to
- * infinity from. This is equivalent to constructing a ray.
- * @param start start point for the segment
- * @param direction direction that the line should extend from the segment
- * @param precision precision context used to determine floating point equality
- * @return a new line segment starting from the given point and extending to infinity in the
- * specified direction
- */
- public static Segment fromPointAndDirection(final Vector2D start, final Vector2D direction,
- final DoublePrecisionContext precision) {
- final Line line = Line.fromPointAndDirection(start, direction, precision);
- return fromInterval(line, Interval.min(line.toSubspace(start).getX(), precision));
- }
-
- /** Create a line segment from an underlying line and a 1D interval on the line.
- * @param line the line that the line segment will belong to
- * @param interval 1D interval on the line
- * @return a line segment defined by the given line and interval
- */
- public static Segment fromInterval(final Line line, final Interval interval) {
- return new Segment(line, interval);
- }
+ /** {@inheritDoc} */
+ @Override
+ RegionLocation classifyAbscissa(final double abscissa) {
+ final DoublePrecisionContext precision = getPrecision();
+ int startCmp = precision.compare(abscissa, start);
+ if (startCmp > 0) {
+ int endCmp = precision.compare(abscissa, end);
+ if (endCmp < 0) {
+ return RegionLocation.INSIDE;
+ } else if (endCmp == 0) {
+ return RegionLocation.BOUNDARY;
+ }
+ } else if (startCmp == 0) {
+ return RegionLocation.BOUNDARY;
+ }
- /** Create a line segment from an underlying line and a 1D interval on the line.
- * @param line the line that the line segment will belong to
- * @param a first 1D location on the line
- * @param b second 1D location on the line
- * @return a line segment defined by the given line and interval
- */
- public static Segment fromInterval(final Line line, final double a, final double b) {
- return fromInterval(line, Interval.of(a, b, line.getPrecision()));
... 22625 lines suppressed ...