diff --git a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SubLine.java b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SubLine.java index 64cb9b61a..41b3b9e0f 100644 --- a/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SubLine.java +++ b/src/main/java/org/apache/commons/math/geometry/euclidean/twod/SubLine.java @@ -28,6 +28,7 @@ import org.apache.commons.math.geometry.partitioning.AbstractSubHyperplane; import org.apache.commons.math.geometry.partitioning.BSPTree; import org.apache.commons.math.geometry.partitioning.Hyperplane; import org.apache.commons.math.geometry.partitioning.Region; +import org.apache.commons.math.geometry.partitioning.Region.Location; import org.apache.commons.math.geometry.partitioning.Side; import org.apache.commons.math.geometry.partitioning.SubHyperplane; import org.apache.commons.math.util.FastMath; @@ -85,6 +86,43 @@ public class SubLine extends AbstractSubHyperplane { } + /** Get the intersection of the instance and another sub-line. + *

+ * This method is related to the {@link Line#intersection(Hyperplane) + * intersection} method in the {@link Line Line} class, but in addition + * to compute the point along infinite lines, it also checks the point + * lies on both sub-line ranges. + *

+ * @param subLine other sub-line which may intersect instance + * @param includeEndPoints if true, endpoints are considered to belong to + * instance (i.e. they are closed sets) and may be returned, otherwise endpoints + * are considered to not belong to instance (i.e. they are open sets) and intersection + * occurring on endpoints lead to null being returned + * @return the intersection point if there is one, null if the sub-lines don't intersect + */ + public Vector2D intersection(final SubLine subLine, final boolean includeEndPoints) { + + // retrieve the underlying lines + Line line1 = (Line) getHyperplane(); + Line line2 = (Line) subLine.getHyperplane(); + + // compute the intersection on infinite line + Vector2D v2D = line1.intersection(line2); + + // check location of point with respect to first sub-line + Location loc1 = getRemainingRegion().checkPoint(line1.toSubSpace(v2D)); + + // check location of point with respect to second sub-line + Location loc2 = subLine.getRemainingRegion().checkPoint(line2.toSubSpace(v2D)); + + if (includeEndPoints) { + return ((loc1 != Location.OUTSIDE) && (loc2 != Location.OUTSIDE)) ? v2D : null; + } else { + return ((loc1 == Location.INSIDE) && (loc2 == Location.INSIDE)) ? v2D : null; + } + + } + /** Build an interval set from two points. * @param start start point * @param end end point diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml index 80c9c1d2f..c0346692a 100644 --- a/src/site/xdoc/changes.xml +++ b/src/site/xdoc/changes.xml @@ -52,6 +52,10 @@ The type attribute can be add,update,fix,remove. If the output is not quite correct, check for invisible trailing spaces! --> + + Added a way to compute sub-lines intersections, considering sub-lines either + as open sets or closed sets + Added a way to build a sub-line from its endpoints, and to retrieve the enpoints from a sub-line diff --git a/src/test/java/org/apache/commons/math/geometry/euclidean/twod/SubLineTest.java b/src/test/java/org/apache/commons/math/geometry/euclidean/twod/SubLineTest.java index 9c2724b13..adf55e654 100644 --- a/src/test/java/org/apache/commons/math/geometry/euclidean/twod/SubLineTest.java +++ b/src/test/java/org/apache/commons/math/geometry/euclidean/twod/SubLineTest.java @@ -97,4 +97,52 @@ public class SubLineTest { segments.get(0)[1].getY() > 0); } + @Test + public void testIntersectionInsideInside() { + SubLine sub1 = new SubLine(new Vector2D(1, 1), new Vector2D(3, 1)); + SubLine sub2 = new SubLine(new Vector2D(2, 0), new Vector2D(2, 2)); + Assert.assertEquals(0.0, new Vector2D(2, 1).distance(sub1.intersection(sub2, true)), 1.0e-12); + Assert.assertEquals(0.0, new Vector2D(2, 1).distance(sub1.intersection(sub2, false)), 1.0e-12); + } + + @Test + public void testIntersectionInsideBoundary() { + SubLine sub1 = new SubLine(new Vector2D(1, 1), new Vector2D(3, 1)); + SubLine sub2 = new SubLine(new Vector2D(2, 0), new Vector2D(2, 1)); + Assert.assertEquals(0.0, new Vector2D(2, 1).distance(sub1.intersection(sub2, true)), 1.0e-12); + Assert.assertNull(sub1.intersection(sub2, false)); + } + + @Test + public void testIntersectionInsideOutside() { + SubLine sub1 = new SubLine(new Vector2D(1, 1), new Vector2D(3, 1)); + SubLine sub2 = new SubLine(new Vector2D(2, 0), new Vector2D(2, 0.5)); + Assert.assertNull(sub1.intersection(sub2, true)); + Assert.assertNull(sub1.intersection(sub2, false)); + } + + @Test + public void testIntersectionBoundaryBoundary() { + SubLine sub1 = new SubLine(new Vector2D(1, 1), new Vector2D(2, 1)); + SubLine sub2 = new SubLine(new Vector2D(2, 0), new Vector2D(2, 1)); + Assert.assertEquals(0.0, new Vector2D(2, 1).distance(sub1.intersection(sub2, true)), 1.0e-12); + Assert.assertNull(sub1.intersection(sub2, false)); + } + + @Test + public void testIntersectionBoundaryOutside() { + SubLine sub1 = new SubLine(new Vector2D(1, 1), new Vector2D(2, 1)); + SubLine sub2 = new SubLine(new Vector2D(2, 0), new Vector2D(2, 0.5)); + Assert.assertNull(sub1.intersection(sub2, true)); + Assert.assertNull(sub1.intersection(sub2, false)); + } + + @Test + public void testIntersectionOutsideOutside() { + SubLine sub1 = new SubLine(new Vector2D(1, 1), new Vector2D(1.5, 1)); + SubLine sub2 = new SubLine(new Vector2D(2, 0), new Vector2D(2, 0.5)); + Assert.assertNull(sub1.intersection(sub2, true)); + Assert.assertNull(sub1.intersection(sub2, false)); + } + }