ReverseRay.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 org.apache.commons.geometry.core.RegionLocation;
  19. import org.apache.commons.geometry.core.Transform;
  20. import org.apache.commons.geometry.core.partitioning.Split;
  21. import org.apache.commons.numbers.core.Precision;

  22. /** Class representing a portion of a line in 2D Euclidean space that starts at infinity and
  23.  * continues in the direction of the line up to a single end point. This is equivalent to taking a
  24.  * {@link Ray} and reversing the line direction.
  25.  *
  26.  * <p>Instances of this class are guaranteed to be immutable.</p>
  27.  * @see Ray
  28.  * @see Lines
  29.  */
  30. public final class ReverseRay extends LineConvexSubset {

  31.     /** The end point of the reverse ray. */
  32.     private final Vector2D endPoint;

  33.     /** Construct a new instance from the given line and end point. Callers are responsible for ensuring that
  34.      * the given end point lies on the line. No validation is performed.
  35.      * @param line line for the instance
  36.      * @param endPoint end point for the instance
  37.      */
  38.     ReverseRay(final Line line, final Vector2D endPoint) {
  39.         super(line);

  40.         this.endPoint = endPoint;
  41.     }

  42.     /** {@inheritDoc}
  43.      *
  44.      * <p>This method always returns {@code false}.</p>
  45.      */
  46.     @Override
  47.     public boolean isFull() {
  48.         return false;
  49.     }

  50.     /** {@inheritDoc}
  51.      *
  52.      * <p>This method always returns {@code true}.</p>
  53.      */
  54.     @Override
  55.     public boolean isInfinite() {
  56.         return true;
  57.     }

  58.     /** {@inheritDoc}
  59.      *
  60.      * <p>This method always returns {@code false}.</p>
  61.      */
  62.     @Override
  63.     public boolean isFinite() {
  64.         return false;
  65.     }

  66.     /** {@inheritDoc}
  67.      *
  68.      * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
  69.      */
  70.     @Override
  71.     public double getSize() {
  72.         return Double.POSITIVE_INFINITY;
  73.     }

  74.     /** {@inheritDoc}
  75.      *
  76.      * <p>This method always returns {@code null}.</p>
  77.      */
  78.     @Override
  79.     public Vector2D getCentroid() {
  80.         return null;
  81.     }

  82.     /** {@inheritDoc}
  83.      *
  84.      * <p>This method always returns {@code null}.</p>
  85.      */
  86.     @Override
  87.     public Vector2D getStartPoint() {
  88.         return null;
  89.     }

  90.     /** {@inheritDoc}
  91.     *
  92.     * <p>This method always returns {@link Double#NEGATIVE_INFINITY}.</p>
  93.     */
  94.     @Override
  95.     public double getSubspaceStart() {
  96.         return Double.NEGATIVE_INFINITY;
  97.     }

  98.     /** {@inheritDoc} */
  99.     @Override
  100.     public Vector2D getEndPoint() {
  101.         return endPoint;
  102.     }

  103.     /** {@inheritDoc} */
  104.     @Override
  105.     public double getSubspaceEnd() {
  106.         return getLine().abscissa(endPoint);
  107.     }

  108.     /** {@inheritDoc}
  109.     *
  110.     * <p>This method always returns {@code null}.</p>
  111.     */
  112.     @Override
  113.     public Bounds2D getBounds() {
  114.         return null; // infinite; no bounds
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public ReverseRay transform(final Transform<Vector2D> transform) {
  119.         final Line tLine = getLine().transform(transform);
  120.         final Vector2D tEnd = transform.apply(getEndPoint());

  121.         return new ReverseRay(tLine, tEnd);
  122.     }

  123.     /** {@inheritDoc} */
  124.     @Override
  125.     public Ray reverse() {
  126.         return new Ray(getLine().reverse(), endPoint);
  127.     }

  128.     /** {@inheritDoc} */
  129.     @Override
  130.     public String toString() {
  131.         final StringBuilder sb = new StringBuilder();
  132.         sb.append(getClass().getSimpleName())
  133.             .append("[direction= ")
  134.             .append(getLine().getDirection())
  135.             .append(", endPoint= ")
  136.             .append(getEndPoint())
  137.             .append(']');

  138.         return sb.toString();
  139.     }

  140.     /** {@inheritDoc} */
  141.     @Override
  142.     RegionLocation classifyAbscissa(final double abscissa) {
  143.         final int cmp = getPrecision().compare(abscissa, getSubspaceEnd());
  144.         if (cmp < 0) {
  145.             return RegionLocation.INSIDE;
  146.         } else if (cmp == 0) {
  147.             return RegionLocation.BOUNDARY;
  148.         }

  149.         return RegionLocation.OUTSIDE;
  150.     }

  151.     /** {@inheritDoc} */
  152.     @Override
  153.     double closestAbscissa(final double abscissa) {
  154.         return Math.min(getSubspaceEnd(), abscissa);
  155.     }

  156.     /** {@inheritDoc} */
  157.     @Override
  158.     protected Split<LineConvexSubset> splitOnIntersection(final Line splitter, final Vector2D intersection) {
  159.         final Line line = getLine();
  160.         final Precision.DoubleEquivalence splitterPrecision = splitter.getPrecision();

  161.         final int endCmp = splitterPrecision.compare(splitter.offset(endPoint), 0.0);
  162.         final boolean pointsTowardPlus = splitter.getOffsetDirection().dot(line.getDirection()) >= 0.0;

  163.         if (pointsTowardPlus && endCmp < 1) {
  164.             // entirely on minus side
  165.             return new Split<>(this, null);
  166.         } else if (!pointsTowardPlus && endCmp > -1) {
  167.             // entirely on plus side
  168.             return new Split<>(null, this);
  169.         }

  170.         // we're going to be split
  171.         final Segment splitSeg = new Segment(line, intersection, endPoint);
  172.         final ReverseRay splitRevRay = new ReverseRay(line, intersection);

  173.         final LineConvexSubset minus = (endCmp > 0) ? splitRevRay : splitSeg;
  174.         final LineConvexSubset plus = (endCmp > 0) ? splitSeg : splitRevRay;

  175.         return new Split<>(minus, plus);
  176.     }
  177. }