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.  *      http://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. package org.apache.commons.math3.geometry.euclidean.threed;

  18. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.apache.commons.math3.exception.MathIllegalArgumentException;
  21. import org.apache.commons.math3.geometry.Point;
  22. import org.apache.commons.math3.geometry.euclidean.oned.Euclidean1D;
  23. import org.apache.commons.math3.geometry.euclidean.oned.Interval;
  24. import org.apache.commons.math3.geometry.euclidean.oned.IntervalsSet;
  25. import org.apache.commons.math3.geometry.euclidean.oned.Vector1D;
  26. import org.apache.commons.math3.geometry.partitioning.Region.Location;

  27. /** This class represents a subset of a {@link Line}.
  28.  * @since 3.0
  29.  */
  30. public class SubLine {

  31.     /** Default value for tolerance. */
  32.     private static final double DEFAULT_TOLERANCE = 1.0e-10;

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

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

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

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

  56.     /** Create a sub-line from two endpoints.
  57.      * @param start start point
  58.      * @param end end point
  59.      * @exception MathIllegalArgumentException if the points are equal
  60.      * @deprecated as of 3.3, replaced with {@link #SubLine(Vector3D, Vector3D, double)}
  61.      */
  62.     public SubLine(final Vector3D start, final Vector3D end)
  63.         throws MathIllegalArgumentException {
  64.         this(start, end, DEFAULT_TOLERANCE);
  65.     }

  66.     /** Create a sub-line from a segment.
  67.      * @param segment single segment forming the sub-line
  68.      * @exception MathIllegalArgumentException if the segment endpoints are equal
  69.      */
  70.     public SubLine(final Segment segment) throws MathIllegalArgumentException {
  71.         this(segment.getLine(),
  72.              buildIntervalSet(segment.getStart(), segment.getEnd(), segment.getLine().getTolerance()));
  73.     }

  74.     /** Get the endpoints of the sub-line.
  75.      * <p>
  76.      * A subline may be any arbitrary number of disjoints segments, so the endpoints
  77.      * are provided as a list of endpoint pairs. Each element of the list represents
  78.      * one segment, and each segment contains a start point at index 0 and an end point
  79.      * at index 1. If the sub-line is unbounded in the negative infinity direction,
  80.      * the start point of the first segment will have infinite coordinates. If the
  81.      * sub-line is unbounded in the positive infinity direction, the end point of the
  82.      * last segment will have infinite coordinates. So a sub-line covering the whole
  83.      * line will contain just one row and both elements of this row will have infinite
  84.      * coordinates. If the sub-line is empty, the returned list will contain 0 segments.
  85.      * </p>
  86.      * @return list of segments endpoints
  87.      */
  88.     public List<Segment> getSegments() {

  89.         final List<Interval> list = remainingRegion.asList();
  90.         final List<Segment> segments = new ArrayList<Segment>(list.size());

  91.         for (final Interval interval : list) {
  92.             final Vector3D start = line.toSpace((Point<Euclidean1D>) new Vector1D(interval.getInf()));
  93.             final Vector3D end   = line.toSpace((Point<Euclidean1D>) new Vector1D(interval.getSup()));
  94.             segments.add(new Segment(start, end, line));
  95.         }

  96.         return segments;

  97.     }

  98.     /** Get the intersection of the instance and another sub-line.
  99.      * <p>
  100.      * This method is related to the {@link Line#intersection(Line)
  101.      * intersection} method in the {@link Line Line} class, but in addition
  102.      * to compute the point along infinite lines, it also checks the point
  103.      * lies on both sub-line ranges.
  104.      * </p>
  105.      * @param subLine other sub-line which may intersect instance
  106.      * @param includeEndPoints if true, endpoints are considered to belong to
  107.      * instance (i.e. they are closed sets) and may be returned, otherwise endpoints
  108.      * are considered to not belong to instance (i.e. they are open sets) and intersection
  109.      * occurring on endpoints lead to null being returned
  110.      * @return the intersection point if there is one, null if the sub-lines don't intersect
  111.      */
  112.     public Vector3D intersection(final SubLine subLine, final boolean includeEndPoints) {

  113.         // compute the intersection on infinite line
  114.         Vector3D v1D = line.intersection(subLine.line);
  115.         if (v1D == null) {
  116.             return null;
  117.         }

  118.         // check location of point with respect to first sub-line
  119.         Location loc1 = remainingRegion.checkPoint((Point<Euclidean1D>) line.toSubSpace((Point<Euclidean3D>) v1D));

  120.         // check location of point with respect to second sub-line
  121.         Location loc2 = subLine.remainingRegion.checkPoint((Point<Euclidean1D>) subLine.line.toSubSpace((Point<Euclidean3D>) v1D));

  122.         if (includeEndPoints) {
  123.             return ((loc1 != Location.OUTSIDE) && (loc2 != Location.OUTSIDE)) ? v1D : null;
  124.         } else {
  125.             return ((loc1 == Location.INSIDE) && (loc2 == Location.INSIDE)) ? v1D : null;
  126.         }

  127.     }

  128.     /** Build an interval set from two points.
  129.      * @param start start point
  130.      * @param end end point
  131.      * @return an interval set
  132.      * @param tolerance tolerance below which points are considered identical
  133.      * @exception MathIllegalArgumentException if the points are equal
  134.      */
  135.     private static IntervalsSet buildIntervalSet(final Vector3D start, final Vector3D end, final double tolerance)
  136.         throws MathIllegalArgumentException {
  137.         final Line line = new Line(start, end, tolerance);
  138.         return new IntervalsSet(line.toSubSpace((Point<Euclidean3D>) start).getX(),
  139.                                 line.toSubSpace((Point<Euclidean3D>) end).getX(),
  140.                                 tolerance);
  141.     }

  142. }