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.threed;

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

  24. import org.hipparchus.exception.MathIllegalArgumentException;
  25. import org.hipparchus.geometry.euclidean.oned.Interval;
  26. import org.hipparchus.geometry.euclidean.oned.IntervalsSet;
  27. import org.hipparchus.geometry.euclidean.oned.Vector1D;
  28. import org.hipparchus.geometry.partitioning.Region.Location;

  29. /** This class represents a subset of a {@link Line}.
  30.  */
  31. public class SubLine {

  32.     /** Underlying line. */
  33.     private final Line line;

  34.     /** Remaining region of the hyperplane. */
  35.     private final IntervalsSet remainingRegion;

  36.     /** Simple constructor.
  37.      * @param line underlying line
  38.      * @param remainingRegion remaining region of the line
  39.      */
  40.     public SubLine(final Line line, final IntervalsSet remainingRegion) {
  41.         this.line            = line;
  42.         this.remainingRegion = remainingRegion;
  43.     }

  44.     /** Create a sub-line from two endpoints.
  45.      * @param start start point
  46.      * @param end end point
  47.      * @param tolerance tolerance below which points are considered identical
  48.      * @exception MathIllegalArgumentException if the points are equal
  49.      */
  50.     public SubLine(final Vector3D start, final Vector3D end, final double tolerance)
  51.         throws MathIllegalArgumentException {
  52.         this(new Line(start, end, tolerance), buildIntervalSet(start, end, tolerance));
  53.     }

  54.     /** Create a sub-line from a segment.
  55.      * @param segment single segment forming the sub-line
  56.      * @exception MathIllegalArgumentException if the segment endpoints are equal
  57.      */
  58.     public SubLine(final Segment segment) throws MathIllegalArgumentException {
  59.         this(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 = remainingRegion.asList();
  78.         final List<Segment> segments = new ArrayList<>(list.size());

  79.         for (final Interval interval : list) {
  80.             final Vector3D start = line.toSpace(new Vector1D(interval.getInf()));
  81.             final Vector3D end   = line.toSpace(new Vector1D(interval.getSup()));
  82.             segments.add(new Segment(start, end, line));
  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 Vector3D intersection(final SubLine subLine, final boolean includeEndPoints) {

  101.         // compute the intersection on infinite line
  102.         Vector3D v1D = line.intersection(subLine.line);
  103.         if (v1D == null) {
  104.             return null;
  105.         }

  106.         // check location of point with respect to first sub-line
  107.         Location loc1 = remainingRegion.checkPoint(line.toSubSpace(v1D));

  108.         // check location of point with respect to second sub-line
  109.         Location loc2 = subLine.remainingRegion.checkPoint(subLine.line.toSubSpace(v1D));

  110.         if (includeEndPoints) {
  111.             return ((loc1 != Location.OUTSIDE) && (loc2 != Location.OUTSIDE)) ? v1D : null;
  112.         } else {
  113.             return ((loc1 == Location.INSIDE) && (loc2 == Location.INSIDE)) ? v1D : null;
  114.         }

  115.     }

  116.     /** Build an interval set from two points.
  117.      * @param start start point
  118.      * @param end end point
  119.      * @return an interval set
  120.      * @param tolerance tolerance below which points are considered identical
  121.      * @exception MathIllegalArgumentException if the points are equal
  122.      */
  123.     private static IntervalsSet buildIntervalSet(final Vector3D start, final Vector3D end, final double tolerance)
  124.         throws MathIllegalArgumentException {
  125.         final Line line = new Line(start, end, tolerance);
  126.         return new IntervalsSet(line.toSubSpace(start).getX(), line.toSubSpace(end).getX(), tolerance);
  127.     }

  128. }