Ray.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 ray in 2D Euclidean space. A ray is a portion of a line consisting of
  23.  * a single start point and extending to infinity along the direction of the line.
  24.  *
  25.  * <p>Instances of this class are guaranteed to be immutable.</p>
  26.  * @see ReverseRay
  27.  * @see Lines
  28.  */
  29. public final class Ray extends LineConvexSubset {

  30.     /** The start point for the ray. */
  31.     private final Vector2D startPoint;

  32.     /** Construct a ray from a line and a start point. Callers are responsible for ensuring that the
  33.      * given point lies on the line. No validation is performed.
  34.      * @param line line for the ray
  35.      * @param startPoint start point for the ray
  36.      */
  37.     Ray(final Line line, final Vector2D startPoint) {
  38.         super(line);

  39.         this.startPoint = startPoint;
  40.     }

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

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

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

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

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

  81.     @Override
  82.     public Vector2D getStartPoint() {
  83.         return startPoint;
  84.     }

  85.     /** {@inheritDoc} */
  86.     @Override
  87.     public double getSubspaceStart() {
  88.         return getLine().abscissa(startPoint);
  89.     }

  90.     /** {@inheritDoc}
  91.     *
  92.     * <p>This method always returns {@code null}.</p>
  93.     */
  94.     @Override
  95.     public Vector2D getEndPoint() {
  96.         return null;
  97.     }

  98.     /** {@inheritDoc}
  99.      *
  100.      * <p>This method always returns {@link Double#POSITIVE_INFINITY}.</p>
  101.      */
  102.     @Override
  103.     public double getSubspaceEnd() {
  104.         return Double.POSITIVE_INFINITY;
  105.     }

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

  114.     /** Get the direction of the ray. This is a convenience method for {@code ray.getLine().getDirection()}.
  115.      * @return the direction of the ray
  116.      */
  117.     public Vector2D getDirection() {
  118.         return getLine().getDirection();
  119.     }

  120.     /** {@inheritDoc} */
  121.     @Override
  122.     public Ray transform(final Transform<Vector2D> transform) {
  123.         final Line tLine = getLine().transform(transform);
  124.         final Vector2D tStart = transform.apply(getStartPoint());

  125.         return new Ray(tLine, tStart);
  126.     }

  127.     /** {@inheritDoc} */
  128.     @Override
  129.     public ReverseRay reverse() {
  130.         return new ReverseRay(getLine().reverse(), startPoint);
  131.     }

  132.     /** {@inheritDoc} */
  133.     @Override
  134.     public String toString() {
  135.         final StringBuilder sb = new StringBuilder();
  136.         sb.append(getClass().getSimpleName())
  137.             .append("[startPoint= ")
  138.             .append(getStartPoint())
  139.             .append(", direction= ")
  140.             .append(getLine().getDirection())
  141.             .append(']');

  142.         return sb.toString();
  143.     }

  144.     /** {@inheritDoc} */
  145.     @Override
  146.     RegionLocation classifyAbscissa(final double abscissa) {
  147.         final int cmp = getPrecision().compare(abscissa, getSubspaceStart());
  148.         if (cmp > 0) {
  149.             return RegionLocation.INSIDE;
  150.         } else if (cmp == 0) {
  151.             return RegionLocation.BOUNDARY;
  152.         }

  153.         return RegionLocation.OUTSIDE;
  154.     }

  155.     /** {@inheritDoc} */
  156.     @Override
  157.     double closestAbscissa(final double abscissa) {
  158.         return Math.max(getSubspaceStart(), abscissa);
  159.     }

  160.     /** {@inheritDoc} */
  161.     @Override
  162.     Split<LineConvexSubset> splitOnIntersection(final Line splitter, final Vector2D intersection) {
  163.         final Line line = getLine();
  164.         final Precision.DoubleEquivalence splitterPrecision = splitter.getPrecision();

  165.         final int startCmp = splitterPrecision.compare(splitter.offset(startPoint), 0.0);
  166.         final boolean pointsTowardPlus = splitter.getOffsetDirection().dot(line.getDirection()) >= 0.0;

  167.         if (pointsTowardPlus && startCmp > -1) {
  168.             // entirely on plus side
  169.             return new Split<>(null, this);
  170.         } else if (!pointsTowardPlus && startCmp < 1) {
  171.             // entirely on minus side
  172.             return new Split<>(this, null);
  173.         }

  174.         // we're going to be split
  175.         final Segment splitSeg = new Segment(line, startPoint, intersection);
  176.         final Ray splitRay = new Ray(line, intersection);

  177.         final LineConvexSubset minus = (startCmp > 0) ? splitRay : splitSeg;
  178.         final LineConvexSubset plus = (startCmp > 0) ? splitSeg : splitRay;

  179.         return new Split<>(minus, plus);
  180.     }
  181. }