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 org.apache.commons.geometry.core.RegionLocation;
    20  import org.apache.commons.geometry.core.Transform;
    21  import org.apache.commons.geometry.core.partitioning.Split;
    22  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
    23
    24  /** Class representing a portion of a line in 2D Euclidean space that starts at infinity and
    25   * continues in the direction of the line up to a single end point. This is equivalent to taking a
    26   * {@link Ray} and reversing the line direction.
    27   *
    28   * <p>Instances of this class are guaranteed to be immutable.</p>
    29   * @see Ray
    30   * @see Lines
    31   */
    32  public final class ReverseRay extends LineConvexSubset {
    33
    34      /** The end point of the reverse ray. */
    35      private final Vector2D endPoint;
    36
    37      /** Construct a new instance from the given line and end point. Callers are responsible for ensuring that
    38       * the given end point lies on the line. No validation is performed.
    39       * @param line line for the instance
    40       * @param endPoint end point for the instance
    41       */
    42      ReverseRay(final Line line, final Vector2D endPoint) {
    43          super(line);
    44
    45          this.endPoint = endPoint;
    46      }
    47
    48      /** {@inheritDoc}
    49       *
    50       * <p>This method always returns {@code false}.</p>
    51       */
    52      @Override
    53      public boolean isFull() {
    54          return false;
    55      }
    56
    57      /** {@inheritDoc}
    58       *
    59       * <p>This method always returns {@code true}.</p>
    60       */
    61      @Override
    62      public boolean isInfinite() {
    63          return true;
    64      }
    65
    66      /** {@inheritDoc}
    67       *
    68       * <p>This method always returns {@code false}.</p>
    69       */
    70      @Override
    71      public boolean isFinite() {
    72          return false;
    73      }
    74
    75      /** {@inheritDoc}
    76       *
    77       * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
    78       */
    79      @Override
    80      public double getSize() {
    81          return Double.POSITIVE_INFINITY;
    82      }
    83
    84      /** {@inheritDoc}
    85       *
    86       * <p>This method always returns {@code null}.</p>
    87       */
    88      @Override
    89      public Vector2D getCentroid() {
    90          return null;
    91      }
    92
    93      /** {@inheritDoc}
    94       *
    95       * <p>This method always returns {@code null}.</p>
    96       */
    97      @Override
    98      public Vector2D getStartPoint() {
    99          return null;
    100     }
    101
    102     /** {@inheritDoc}
    103     *
    104     * <p>This method always returns {@link Double#NEGATIVE_INFINITY}.</p>
    105     */
    106     @Override
    107     public double getSubspaceStart() {
    108         return Double.NEGATIVE_INFINITY;
    109     }
    110
    111     /** {@inheritDoc} */
    112     @Override
    113     public Vector2D getEndPoint() {
    114         return endPoint;
    115     }
    116
    117     /** {@inheritDoc} */
    118     @Override
    119     public double getSubspaceEnd() {
    120         return getLine().abscissa(endPoint);
    121     }
    122
    123     /** {@inheritDoc}
    124     *
    125     * <p>This method always returns {@code null}.</p>
    126     */
    127     @Override
    128     public Bounds2D getBounds() {
    129         return null; // infinite; no bounds
    130     }
    131
    132     /** {@inheritDoc} */
    133     @Override
    134     public ReverseRay transform(final Transform<Vector2D> transform) {
    135         final Line tLine = getLine().transform(transform);
    136         final Vector2D tEnd = transform.apply(getEndPoint());
    137
    138         return new ReverseRay(tLine, tEnd);
    139     }
    140
    141     /** {@inheritDoc} */
    142     @Override
    143     public Ray reverse() {
    144         return new Ray(getLine().reverse(), endPoint);
    145     }
    146
    147     /** {@inheritDoc} */
    148     @Override
    149     public String toString() {
    150         final StringBuilder sb = new StringBuilder();
    151         sb.append(getClass().getSimpleName())
    152             .append("[direction= ")
    153             .append(getLine().getDirection())
    154             .append(", endPoint= ")
    155             .append(getEndPoint())
    156             .append(']');
    157
    158         return sb.toString();
    159     }
    160
    161     /** {@inheritDoc} */
    162     @Override
    163     RegionLocation classifyAbscissa(final double abscissa) {
    164         final int cmp = getPrecision().compare(abscissa, getSubspaceEnd());
    165         if (cmp < 0) {
    166             return RegionLocation.INSIDE;
    167         } else if (cmp == 0) {
    168             return RegionLocation.BOUNDARY;
    169         }
    170
    171         return RegionLocation.OUTSIDE;
    172     }
    173
    174     /** {@inheritDoc} */
    175     @Override
    176     double closestAbscissa(final double abscissa) {
    177         return Math.min(getSubspaceEnd(), abscissa);
    178     }
    179
    180     /** {@inheritDoc} */
    181     @Override
    182     protected Split<LineConvexSubset> splitOnIntersection(final Line splitter, final Vector2D intersection) {
    183         final Line line = getLine();
    184         final DoublePrecisionContext splitterPrecision = splitter.getPrecision();
    185
    186         final int endCmp = splitterPrecision.compare(splitter.offset(endPoint), 0.0);
    187         final boolean pointsTowardPlus = splitter.getOffsetDirection().dot(line.getDirection()) >= 0.0;
    188
    189         if (pointsTowardPlus && endCmp < 1) {
    190             // entirely on minus side
    191             return new Split<>(this, null);
    192         } else if (!pointsTowardPlus && endCmp > -1) {
    193             // entirely on plus side
    194             return new Split<>(null, this);
    195         }
    196
    197         // we're going to be split
    198         final Segment splitSeg = new Segment(line, intersection, endPoint);
    199         final ReverseRay splitRevRay = new ReverseRay(line, intersection);
    200
    201         final LineConvexSubset minus = (endCmp > 0) ? splitRevRay : splitSeg;
    202         final LineConvexSubset plus = (endCmp > 0) ? splitSeg : splitRevRay;
    203
    204         return new Split<>(minus, plus);
    205     }
    206 }