SubLine.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.geometry.euclidean.twod;

  22. import java.util.ArrayList;
  23. import java.util.List;

  24. import org.hipparchus.geometry.euclidean.oned.Euclidean1D;
  25. import org.hipparchus.geometry.euclidean.oned.Interval;
  26. import org.hipparchus.geometry.euclidean.oned.IntervalsSet;
  27. import org.hipparchus.geometry.euclidean.oned.OrientedPoint;
  28. import org.hipparchus.geometry.euclidean.oned.SubOrientedPoint;
  29. import org.hipparchus.geometry.euclidean.oned.Vector1D;
  30. import org.hipparchus.geometry.partitioning.AbstractSubHyperplane;
  31. import org.hipparchus.geometry.partitioning.BSPTree;
  32. import org.hipparchus.geometry.partitioning.Region;
  33. import org.hipparchus.geometry.partitioning.Region.Location;
  34. import org.hipparchus.util.FastMath;

  35. /** This class represents a sub-hyperplane for {@link Line}.
  36.  */
  37. public class SubLine
  38.     extends AbstractSubHyperplane<Euclidean2D, Vector2D, Line, SubLine, Euclidean1D, Vector1D, OrientedPoint, SubOrientedPoint> {

  39.     /** Simple constructor.
  40.      * @param hyperplane underlying hyperplane
  41.      * @param remainingRegion remaining region of the hyperplane
  42.      */
  43.     public SubLine(final Line hyperplane,
  44.                    final Region<Euclidean1D, Vector1D, OrientedPoint, SubOrientedPoint> remainingRegion) {
  45.         super(hyperplane, remainingRegion);
  46.     }

  47.     /** Create a sub-line from two endpoints.
  48.      * @param start start point
  49.      * @param end end point
  50.      * @param tolerance tolerance below which points are considered identical
  51.      */
  52.     public SubLine(final Vector2D start, final Vector2D end, final double tolerance) {
  53.         super(new Line(start, end, tolerance), buildIntervalSet(start, end, tolerance));
  54.     }

  55.     /** Create a sub-line from a segment.
  56.      * @param segment single segment forming the sub-line
  57.      */
  58.     public SubLine(final Segment segment) {
  59.         super(segment.getLine(),
  60.               buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getTolerance()));
  61.     }

  62.     /** Get the endpoints of the sub-line.
  63.      * <p>
  64.      * A subline may be any arbitrary number of disjoints segments, so the endpoints
  65.      * are provided as a list of endpoint pairs. Each element of the list represents
  66.      * one segment, and each segment contains a start point at index 0 and an end point
  67.      * at index 1. If the sub-line is unbounded in the negative infinity direction,
  68.      * the start point of the first segment will have infinite coordinates. If the
  69.      * sub-line is unbounded in the positive infinity direction, the end point of the
  70.      * last segment will have infinite coordinates. So a sub-line covering the whole
  71.      * line will contain just one row and both elements of this row will have infinite
  72.      * coordinates. If the sub-line is empty, the returned list will contain 0 segments.
  73.      * </p>
  74.      * @return list of segments endpoints
  75.      */
  76.     public List<Segment> getSegments() {

  77.         final List<Interval> list = ((IntervalsSet) getRemainingRegion()).asList();
  78.         final List<Segment> segments = new ArrayList<>(list.size());

  79.         for (final Interval interval : list) {
  80.             final Vector2D start = getHyperplane().toSpace(new Vector1D(interval.getInf()));
  81.             final Vector2D end   = getHyperplane().toSpace(new Vector1D(interval.getSup()));
  82.             segments.add(new Segment(start, end, getHyperplane()));
  83.         }

  84.         return segments;

  85.     }

  86.     /** Get the intersection of the instance and another sub-line.
  87.      * <p>
  88.      * This method is related to the {@link Line#intersection(Line)
  89.      * intersection} method in the {@link Line Line} class, but in addition
  90.      * to compute the point along infinite lines, it also checks the point
  91.      * lies on both sub-line ranges.
  92.      * </p>
  93.      * @param subLine other sub-line which may intersect instance
  94.      * @param includeEndPoints if true, endpoints are considered to belong to
  95.      * instance (i.e. they are closed sets) and may be returned, otherwise endpoints
  96.      * are considered to not belong to instance (i.e. they are open sets) and intersection
  97.      * occurring on endpoints lead to null being returned
  98.      * @return the intersection point if there is one, null if the sub-lines don't intersect
  99.      */
  100.     public Vector2D intersection(final SubLine subLine, final boolean includeEndPoints) {

  101.         // retrieve the underlying lines
  102.         Line line1 = getHyperplane();
  103.         Line line2 = subLine.getHyperplane();

  104.         // compute the intersection on infinite line
  105.         Vector2D v2D = line1.intersection(line2);
  106.         if (v2D == null) {
  107.             return null;
  108.         }

  109.         // check location of point with respect to first sub-line
  110.         Location loc1 = getRemainingRegion().checkPoint(line1.toSubSpace(v2D));

  111.         // check location of point with respect to second sub-line
  112.         Location loc2 = subLine.getRemainingRegion().checkPoint(line2.toSubSpace(v2D));

  113.         if (includeEndPoints) {
  114.             return ((loc1 != Location.OUTSIDE) && (loc2 != Location.OUTSIDE)) ? v2D : null;
  115.         } else {
  116.             return ((loc1 == Location.INSIDE) && (loc2 == Location.INSIDE)) ? v2D : null;
  117.         }

  118.     }

  119.     /** Build an interval set from two points.
  120.      * @param start start point
  121.      * @param end end point
  122.      * @param tolerance tolerance below which points are considered identical
  123.      * @return an interval set
  124.      */
  125.     private static IntervalsSet buildIntervalSet(final Vector2D start, final Vector2D end, final double tolerance) {
  126.         final Line line = new Line(start, end, tolerance);
  127.         return new IntervalsSet(line.toSubSpace(start).getX(),
  128.                                 line.toSubSpace(end).getX(),
  129.                                 tolerance);
  130.     }

  131.     /** {@inheritDoc} */
  132.     @Override
  133.     protected SubLine buildNew(final Line hyperplane,
  134.                                final Region<Euclidean1D, Vector1D, OrientedPoint, SubOrientedPoint> remainingRegion) {
  135.         return new SubLine(hyperplane, remainingRegion);
  136.     }

  137.     /** {@inheritDoc} */
  138.     @Override
  139.     public Vector2D getInteriorPoint() {
  140.         final Vector1D v = getRemainingRegion().getInteriorPoint();
  141.         return isEmpty() ? null : getHyperplane().toSpace(v);
  142.     }

  143.     /** {@inheritDoc} */
  144.     @Override
  145.     public SplitSubHyperplane<Euclidean2D, Vector2D, Line, SubLine> split(final Line hyperplane) {

  146.         final Line    thisLine  = getHyperplane();
  147.         final Vector2D crossing = thisLine.intersection(hyperplane);
  148.         final double tolerance  = thisLine.getTolerance();

  149.         if (crossing == null) {
  150.             // the lines are parallel
  151.             final double global = hyperplane.getOffset(thisLine);
  152.             if (global < -tolerance) {
  153.                 return new SplitSubHyperplane<>(null, this);
  154.             } else if (global > tolerance) {
  155.                 return new SplitSubHyperplane<>(this, null);
  156.             } else {
  157.                 return new SplitSubHyperplane<>(null, null);
  158.             }
  159.         }

  160.         // the lines do intersect
  161.         final boolean direct = FastMath.sin(thisLine.getAngle() - hyperplane.getAngle()) < 0;
  162.         final Vector1D x      = thisLine.toSubSpace(crossing);
  163.         final SubOrientedPoint subPlus  = new OrientedPoint(x, !direct, tolerance).wholeHyperplane();
  164.         final SubOrientedPoint subMinus = new OrientedPoint(x,  direct, tolerance).wholeHyperplane();

  165.         final BSPTree<Euclidean1D, Vector1D, OrientedPoint, SubOrientedPoint> splitTree =
  166.                 getRemainingRegion().getTree(false).split(subMinus);
  167.         final BSPTree<Euclidean1D, Vector1D, OrientedPoint, SubOrientedPoint> plusTree  =
  168.                 getRemainingRegion().isEmpty(splitTree.getPlus()) ?
  169.                                              new BSPTree<>(Boolean.FALSE) :
  170.                                              new BSPTree<>(subPlus, new BSPTree<>(Boolean.FALSE), splitTree.getPlus(), null);
  171.         final BSPTree<Euclidean1D, Vector1D, OrientedPoint, SubOrientedPoint> minusTree =
  172.                 getRemainingRegion().isEmpty(splitTree.getMinus()) ?
  173.                                              new BSPTree<>(Boolean.FALSE) :
  174.                                              new BSPTree<>(subMinus, new BSPTree<>(Boolean.FALSE), splitTree.getMinus(), null);
  175.         return new SplitSubHyperplane<>(new SubLine(thisLine.copySelf(), new IntervalsSet(plusTree, tolerance)),
  176.                                         new SubLine(thisLine.copySelf(), new IntervalsSet(minusTree, tolerance)));

  177.     }

  178. }