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    *      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.geometry.euclidean.twod;
    18
    19  import java.util.List;
    20
    21  import org.apache.commons.geometry.core.RegionEmbedding;
    22  import org.apache.commons.geometry.core.RegionLocation;
    23  import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
    24  import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
    25  import org.apache.commons.geometry.core.partitioning.Split;
    26  import org.apache.commons.geometry.euclidean.oned.Vector1D;
    27  import org.apache.commons.numbers.core.Precision;
    28
    29  /** Class representing a subset of points on a line in 2D Euclidean space. For example, line segments
    30   * and rays are line subsets. Line subsets may be finite or infinite.
    31   */
    32  public abstract class LineSubset implements HyperplaneSubset<Vector2D>, RegionEmbedding<Vector2D, Vector1D> {
    33      /** The line containing this instance. */
    34      private final Line line;
    35
    36      /** Construct a new instance based on the given line.
    37       * @param line line forming the base of the instance
    38       */
    39      LineSubset(final Line line) {
    40          this.line = line;
    41      }
    42
    43      /** Get the line containing this subset. This method is an alias
    44       * for {@link #getHyperplane()}.
    45       * @return the line containing this subset
    46       * @see #getHyperplane()
    47       */
    48      public Line getLine() {
    49          return getHyperplane();
    50      }
    51
    52      /** {@inheritDoc} */
    53      @Override
    54      public Line getHyperplane() {
    55          return line;
    56      }
    57
    58      /** {@inheritDoc} */
    59      @Override
    60      public Vector1D toSubspace(final Vector2D pt) {
    61          return line.toSubspace(pt);
    62      }
    63
    64      /** Get a {@link Bounds2D} object defining an axis-aligned bounding box containing all
    65       * vertices for this subset. Null is returned if the subset is infinite or does not
    66       * contain any vertices.
    67       * @return the bounding box for this instance or null if no valid bounds could be determined
    68       */
    69      public abstract Bounds2D getBounds();
    70
    71      /** {@inheritDoc} */
    72      @Override
    73      public abstract HyperplaneBoundedRegion<Vector1D> getSubspaceRegion();
    74
    75      /** {@inheritDoc} */
    76      @Override
    77      public Vector2D toSpace(final Vector1D pt) {
    78          return line.toSpace(pt);
    79      }
    80
    81      /** {@inheritDoc} */
    82      @Override
    83      public abstract List<LineConvexSubset> toConvex();
    84
    85      /** {@inheritDoc} */
    86      @Override
    87      public RegionLocation classify(final Vector2D pt) {
    88          if (line.contains(pt)) {
    89              return classifyAbscissa(line.abscissa(pt));
    90          }
    91
    92          return RegionLocation.OUTSIDE;
    93      }
    94
    95      /** Get the unique intersection of this subset with the given line. Null is
    96       * returned if no unique intersection point exists (ie, the lines are
    97       * parallel or coincident) or the line does not intersect this instance.
    98       * @param inputLine line to intersect with this line subset
    99       * @return the unique intersection point between the line and this line subset
    100      *      or null if no such point exists.
    101      * @see Line#intersection(Line)
    102      */
    103     public Vector2D intersection(final Line inputLine) {
    104         final Vector2D pt = line.intersection(inputLine);
    105         return (pt != null && contains(pt)) ? pt : null;
    106     }
    107
    108     /** Get the unique intersection of this instance with the given line subset. Null
    109      * is returned if the lines containing the line subsets do not have a unique intersection
    110      * point (ie, they are parallel or coincident) or the intersection point is unique
    111      * but is not contained in both line subsets.
    112      * @param subset line subset to intersect with
    113      * @return the unique intersection point between this line subset and the argument or
    114      *      null if no such point exists.
    115      * @see Line#intersection(Line)
    116      */
    117     public Vector2D intersection(final LineSubset subset) {
    118         final Vector2D pt = intersection(subset.getLine());
    119         return (pt != null && subset.contains(pt)) ? pt : null;
    120     }
    121
    122     /** Return the object used to perform floating point comparisons, which is the
    123      * same object used by the underlying {@link Line}).
    124      * @return precision object used to perform floating point comparisons.
    125      */
    126     public Precision.DoubleEquivalence getPrecision() {
    127         return line.getPrecision();
    128     }
    129
    130     /** Classify the given line abscissa value with respect to the subspace region.
    131      * @param abscissa the abscissa value to classify
    132      * @return the region location of the line abscissa value
    133      */
    134     abstract RegionLocation classifyAbscissa(double abscissa);
    135
    136     /** Get a split result for cases where no intersection exists between the splitting line and the
    137      * line underlying the given line subset. This occurs when the two lines are parallel or coincident.
    138      * @param <T> Line subset type
    139      * @param splitter splitting line
    140      * @param subset line subset instance being split
    141      * @return return result of the non-intersecting split operation
    142      */
    143     <T extends LineSubset> Split<T> getNonIntersectingSplitResult(final Line splitter, final T subset) {
    144         // check which side of the splitter we lie on
    145         final double offset = splitter.offset(subset.getLine());
    146         final int comp = getPrecision().compare(offset, 0.0);
    147
    148         if (comp < 0) {
    149             return new Split<>(subset, null);
    150         } else if (comp > 0) {
    151             return new Split<>(null, subset);
    152         } else {
    153             return new Split<>(null, null);
    154         }
    155     }
    156
    157     /** Return true if the plus side of the given splitter line is facing in the positive direction
    158      * of this line.
    159      * @param splitterLine line splitting this instance
    160      * @return true if the plus side of the given line is facing in the positive direction of this
    161      *      line
    162      */
    163     boolean splitterPlusIsPositiveFacing(final Line splitterLine) {
    164         return line.getOffsetDirection().dot(splitterLine.getDirection()) <= 0;
    165     }
    166
    167     /** Create a split result for the given splitter line, given the low and high split portion of this
    168      * instance. The arguments are assigned to the split result's minus and plus properties based on the
    169      * relative orientation of the splitter line.
    170      * @param <T> Line subset type
    171      * @param splitter splitter line
    172      * @param low portion of the split result closest to negative infinity on this line
    173      * @param high portion of th split result closest to positive infinity on this line
    174      * @return a split result for the given splitter line.
    175      */
    176     <T extends LineSubset> Split<T> createSplitResult(final Line splitter, final T low, final T high) {
    177         return splitterPlusIsPositiveFacing(splitter) ?
    178                 new Split<>(low, high) :
    179                 new Split<>(high, low);
    180     }
    181 }