View Javadoc
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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.geometry.euclidean.threed;
23  
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.hipparchus.exception.MathIllegalArgumentException;
28  import org.hipparchus.geometry.euclidean.oned.Interval;
29  import org.hipparchus.geometry.euclidean.oned.IntervalsSet;
30  import org.hipparchus.geometry.euclidean.oned.Vector1D;
31  import org.hipparchus.geometry.partitioning.Region.Location;
32  
33  /** This class represents a subset of a {@link Line}.
34   */
35  public class SubLine {
36  
37      /** Underlying line. */
38      private final Line line;
39  
40      /** Remaining region of the hyperplane. */
41      private final IntervalsSet remainingRegion;
42  
43      /** Simple constructor.
44       * @param line underlying line
45       * @param remainingRegion remaining region of the line
46       */
47      public SubLine(final Line line, final IntervalsSet remainingRegion) {
48          this.line            = line;
49          this.remainingRegion = remainingRegion;
50      }
51  
52      /** Create a sub-line from two endpoints.
53       * @param start start point
54       * @param end end point
55       * @param tolerance tolerance below which points are considered identical
56       * @exception MathIllegalArgumentException if the points are equal
57       */
58      public SubLine(final Vector3D start, final Vector3D end, final double tolerance)
59          throws MathIllegalArgumentException {
60          this(new Line(start, end, tolerance), buildIntervalSet(start, end, tolerance));
61      }
62  
63      /** Create a sub-line from a segment.
64       * @param segment single segment forming the sub-line
65       * @exception MathIllegalArgumentException if the segment endpoints are equal
66       */
67      public SubLine(final Segment segment) throws MathIllegalArgumentException {
68          this(segment.getLine(),
69               buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getTolerance()));
70      }
71  
72      /** Get the endpoints of the sub-line.
73       * <p>
74       * A subline may be any arbitrary number of disjoints segments, so the endpoints
75       * are provided as a list of endpoint pairs. Each element of the list represents
76       * one segment, and each segment contains a start point at index 0 and an end point
77       * at index 1. If the sub-line is unbounded in the negative infinity direction,
78       * the start point of the first segment will have infinite coordinates. If the
79       * sub-line is unbounded in the positive infinity direction, the end point of the
80       * last segment will have infinite coordinates. So a sub-line covering the whole
81       * line will contain just one row and both elements of this row will have infinite
82       * coordinates. If the sub-line is empty, the returned list will contain 0 segments.
83       * </p>
84       * @return list of segments endpoints
85       */
86      public List<Segment> getSegments() {
87  
88          final List<Interval> list = remainingRegion.asList();
89          final List<Segment> segments = new ArrayList<>(list.size());
90  
91          for (final Interval interval : list) {
92              final Vector3D start = line.toSpace(new Vector1D(interval.getInf()));
93              final Vector3D end   = line.toSpace(new Vector1D(interval.getSup()));
94              segments.add(new Segment(start, end, line));
95          }
96  
97          return segments;
98  
99      }
100 
101     /** Get the intersection of the instance and another sub-line.
102      * <p>
103      * This method is related to the {@link Line#intersection(Line)
104      * intersection} method in the {@link Line Line} class, but in addition
105      * to compute the point along infinite lines, it also checks the point
106      * lies on both sub-line ranges.
107      * </p>
108      * @param subLine other sub-line which may intersect instance
109      * @param includeEndPoints if true, endpoints are considered to belong to
110      * instance (i.e. they are closed sets) and may be returned, otherwise endpoints
111      * are considered to not belong to instance (i.e. they are open sets) and intersection
112      * occurring on endpoints lead to null being returned
113      * @return the intersection point if there is one, null if the sub-lines don't intersect
114      */
115     public Vector3D intersection(final SubLine subLine, final boolean includeEndPoints) {
116 
117         // compute the intersection on infinite line
118         Vector3D v1D = line.intersection(subLine.line);
119         if (v1D == null) {
120             return null;
121         }
122 
123         // check location of point with respect to first sub-line
124         Location loc1 = remainingRegion.checkPoint(line.toSubSpace(v1D));
125 
126         // check location of point with respect to second sub-line
127         Location loc2 = subLine.remainingRegion.checkPoint(subLine.line.toSubSpace(v1D));
128 
129         if (includeEndPoints) {
130             return ((loc1 != Location.OUTSIDE) && (loc2 != Location.OUTSIDE)) ? v1D : null;
131         } else {
132             return ((loc1 == Location.INSIDE) && (loc2 == Location.INSIDE)) ? v1D : null;
133         }
134 
135     }
136 
137     /** Build an interval set from two points.
138      * @param start start point
139      * @param end end point
140      * @return an interval set
141      * @param tolerance tolerance below which points are considered identical
142      * @exception MathIllegalArgumentException if the points are equal
143      */
144     private static IntervalsSet buildIntervalSet(final Vector3D start, final Vector3D end, final double tolerance)
145         throws MathIllegalArgumentException {
146         final Line line = new Line(start, end, tolerance);
147         return new IntervalsSet(line.toSubSpace(start).getX(), line.toSubSpace(end).getX(), tolerance);
148     }
149 
150 }