LineSubset.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.geometry.euclidean.twod;

  18. import java.util.List;

  19. import org.apache.commons.geometry.core.RegionEmbedding;
  20. import org.apache.commons.geometry.core.RegionLocation;
  21. import org.apache.commons.geometry.core.partitioning.HyperplaneBoundedRegion;
  22. import org.apache.commons.geometry.core.partitioning.HyperplaneSubset;
  23. import org.apache.commons.geometry.core.partitioning.Split;
  24. import org.apache.commons.geometry.euclidean.oned.Vector1D;
  25. import org.apache.commons.numbers.core.Precision;

  26. /** Class representing a subset of points on a line in 2D Euclidean space. For example, line segments
  27.  * and rays are line subsets. Line subsets may be finite or infinite.
  28.  */
  29. public abstract class LineSubset implements HyperplaneSubset<Vector2D>, RegionEmbedding<Vector2D, Vector1D> {
  30.     /** The line containing this instance. */
  31.     private final Line line;

  32.     /** Construct a new instance based on the given line.
  33.      * @param line line forming the base of the instance
  34.      */
  35.     LineSubset(final Line line) {
  36.         this.line = line;
  37.     }

  38.     /** Get the line containing this subset. This method is an alias
  39.      * for {@link #getHyperplane()}.
  40.      * @return the line containing this subset
  41.      * @see #getHyperplane()
  42.      */
  43.     public Line getLine() {
  44.         return getHyperplane();
  45.     }

  46.     /** {@inheritDoc} */
  47.     @Override
  48.     public Line getHyperplane() {
  49.         return line;
  50.     }

  51.     /** {@inheritDoc} */
  52.     @Override
  53.     public Vector1D toSubspace(final Vector2D pt) {
  54.         return line.toSubspace(pt);
  55.     }

  56.     /** Get a {@link Bounds2D} object defining an axis-aligned bounding box containing all
  57.      * vertices for this subset. Null is returned if the subset is infinite or does not
  58.      * contain any vertices.
  59.      * @return the bounding box for this instance or null if no valid bounds could be determined
  60.      */
  61.     public abstract Bounds2D getBounds();

  62.     /** {@inheritDoc} */
  63.     @Override
  64.     public abstract HyperplaneBoundedRegion<Vector1D> getSubspaceRegion();

  65.     /** {@inheritDoc} */
  66.     @Override
  67.     public Vector2D toSpace(final Vector1D pt) {
  68.         return line.toSpace(pt);
  69.     }

  70.     /** {@inheritDoc} */
  71.     @Override
  72.     public abstract List<LineConvexSubset> toConvex();

  73.     /** {@inheritDoc} */
  74.     @Override
  75.     public RegionLocation classify(final Vector2D pt) {
  76.         if (line.contains(pt)) {
  77.             return classifyAbscissa(line.abscissa(pt));
  78.         }

  79.         return RegionLocation.OUTSIDE;
  80.     }

  81.     /** Get the unique intersection of this subset with the given line. Null is
  82.      * returned if no unique intersection point exists (ie, the lines are
  83.      * parallel or coincident) or the line does not intersect this instance.
  84.      * @param inputLine line to intersect with this line subset
  85.      * @return the unique intersection point between the line and this line subset
  86.      *      or null if no such point exists.
  87.      * @see Line#intersection(Line)
  88.      */
  89.     public Vector2D intersection(final Line inputLine) {
  90.         final Vector2D pt = line.intersection(inputLine);
  91.         return (pt != null && contains(pt)) ? pt : null;
  92.     }

  93.     /** Get the unique intersection of this instance with the given line subset. Null
  94.      * is returned if the lines containing the line subsets do not have a unique intersection
  95.      * point (ie, they are parallel or coincident) or the intersection point is unique
  96.      * but is not contained in both line subsets.
  97.      * @param subset line subset to intersect with
  98.      * @return the unique intersection point between this line subset and the argument or
  99.      *      null if no such point exists.
  100.      * @see Line#intersection(Line)
  101.      */
  102.     public Vector2D intersection(final LineSubset subset) {
  103.         final Vector2D pt = intersection(subset.getLine());
  104.         return (pt != null && subset.contains(pt)) ? pt : null;
  105.     }

  106.     /** Return the object used to perform floating point comparisons, which is the
  107.      * same object used by the underlying {@link Line}).
  108.      * @return precision object used to perform floating point comparisons.
  109.      */
  110.     public Precision.DoubleEquivalence getPrecision() {
  111.         return line.getPrecision();
  112.     }

  113.     /** Classify the given line abscissa value with respect to the subspace region.
  114.      * @param abscissa the abscissa value to classify
  115.      * @return the region location of the line abscissa value
  116.      */
  117.     abstract RegionLocation classifyAbscissa(double abscissa);

  118.     /** Get a split result for cases where no intersection exists between the splitting line and the
  119.      * line underlying the given line subset. This occurs when the two lines are parallel or coincident.
  120.      * @param <T> Line subset type
  121.      * @param splitter splitting line
  122.      * @param subset line subset instance being split
  123.      * @return return result of the non-intersecting split operation
  124.      */
  125.     <T extends LineSubset> Split<T> getNonIntersectingSplitResult(final Line splitter, final T subset) {
  126.         // check which side of the splitter we lie on
  127.         final double offset = splitter.offset(subset.getLine());
  128.         final int comp = getPrecision().compare(offset, 0.0);

  129.         if (comp < 0) {
  130.             return new Split<>(subset, null);
  131.         } else if (comp > 0) {
  132.             return new Split<>(null, subset);
  133.         } else {
  134.             return new Split<>(null, null);
  135.         }
  136.     }

  137.     /** Return true if the plus side of the given splitter line is facing in the positive direction
  138.      * of this line.
  139.      * @param splitterLine line splitting this instance
  140.      * @return true if the plus side of the given line is facing in the positive direction of this
  141.      *      line
  142.      */
  143.     boolean splitterPlusIsPositiveFacing(final Line splitterLine) {
  144.         return line.getOffsetDirection().dot(splitterLine.getDirection()) <= 0;
  145.     }

  146.     /** Create a split result for the given splitter line, given the low and high split portion of this
  147.      * instance. The arguments are assigned to the split result's minus and plus properties based on the
  148.      * relative orientation of the splitter line.
  149.      * @param <T> Line subset type
  150.      * @param splitter splitter line
  151.      * @param low portion of the split result closest to negative infinity on this line
  152.      * @param high portion of th split result closest to positive infinity on this line
  153.      * @return a split result for the given splitter line.
  154.      */
  155.     <T extends LineSubset> Split<T> createSplitResult(final Line splitter, final T low, final T high) {
  156.         return splitterPlusIsPositiveFacing(splitter) ?
  157.                 new Split<>(low, high) :
  158.                 new Split<>(high, low);
  159.     }
  160. }