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.spherical.twod;
    18
    19  import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
    20  import org.apache.commons.geometry.euclidean.threed.Vector3D;
    21  import org.apache.commons.geometry.spherical.oned.AngularInterval;
    22  import org.apache.commons.geometry.spherical.oned.Point1S;
    23  import org.apache.commons.numbers.angle.PlaneAngleRadians;
    24
    25  /** Class containing factory methods for constructing {@link GreatCircle} and {@link GreatCircleSubset} instances.
    26   */
    27  public final class GreatCircles {
    28
    29      /** Utility class; no instantiation. */
    30      private GreatCircles() {
    31      }
    32
    33      /** Create a great circle instance from its pole vector. An arbitrary u-axis is chosen.
    34       * @param pole pole vector for the great circle
    35       * @param precision precision context used to compare floating point values
    36       * @return a great circle defined by the given pole vector
    37       */
    38      public static GreatCircle fromPole(final Vector3D pole, final DoublePrecisionContext precision) {
    39          final Vector3D.Unit u = pole.orthogonal();
    40          final Vector3D.Unit v = pole.cross(u).normalize();
    41          return new GreatCircle(pole.normalize(), u, v, precision);
    42      }
    43
    44      /** Create a great circle instance from its pole vector and a vector representing the u-axis
    45       * in the equator plane. The u-axis vector defines the {@code 0pi} location for the embedded
    46       * subspace.
    47       * @param pole pole vector for the great circle
    48       * @param u u-axis direction for the equator plane
    49       * @param precision precision context used to compare floating point values
    50       * @return a great circle defined by the given pole vector and u-axis direction
    51       */
    52      public static GreatCircle fromPoleAndU(final Vector3D pole, final Vector3D u,
    53              final DoublePrecisionContext precision) {
    54
    55          final Vector3D.Unit unitPole = pole.normalize();
    56          final Vector3D.Unit unitX = pole.orthogonal(u);
    57          final Vector3D.Unit unitY = pole.cross(u).normalize();
    58
    59          return new GreatCircle(unitPole, unitX, unitY, precision);
    60      }
    61
    62      /** Create a great circle instance from two points on the circle. The u-axis of the
    63       * instance points to the location of the first point. The orientation of the circle
    64       * is along the shortest path between the two points.
    65       * @param a first point on the great circle
    66       * @param b second point on the great circle
    67       * @param precision precision context used to compare floating point values
    68       * @return great circle instance containing the given points
    69       * @throws IllegalArgumentException if either of the given points is NaN or infinite, or if the given points are
    70       *      equal or antipodal as evaluated by the given precision context
    71       */
    72      public static GreatCircle fromPoints(final Point2S a, final Point2S b,
    73              final DoublePrecisionContext precision) {
    74
    75          if (!a.isFinite() || !b.isFinite()) {
    76              throw new IllegalArgumentException("Invalid points for great circle: " + a + ", " + b);
    77          }
    78
    79          String err = null;
    80
    81          final double dist = a.distance(b);
    82          if (precision.eqZero(dist)) {
    83              err = "equal";
    84          } else if (precision.eq(dist, PlaneAngleRadians.PI)) {
    85              err = "antipodal";
    86          }
    87
    88          if (err != null) {
    89              throw new IllegalArgumentException("Cannot create great circle from points " + a + " and " + b +
    90                      ": points are " + err);
    91          }
    92
    93          final Vector3D.Unit u = a.getVector().normalize();
    94          final Vector3D.Unit pole = u.cross(b.getVector()).normalize();
    95          final Vector3D.Unit v = pole.cross(u).normalize();
    96
    97          return new GreatCircle(pole, u, v, precision);
    98      }
    99
    100     /** Construct an arc along the shortest path between the given points. The underlying
    101      * great circle is oriented in the direction from {@code start} to {@code end}.
    102      * @param start start point for the interval
    103      * @param end end point point for the interval
    104      * @param precision precision context used to compare floating point numbers
    105      * @return an arc representing the shortest path between the given points
    106      * @throws IllegalArgumentException if either of the given points is NaN or infinite, or if the given
    107      *      points are equal or antipodal as evaluated by the given precision context
    108      * @see GreatCircles#fromPoints(Point2S, Point2S, org.apache.commons.geometry.core.precision.DoublePrecisionContext)
    109      */
    110     public static GreatArc arcFromPoints(final Point2S start, final Point2S end,
    111             final DoublePrecisionContext precision) {
    112         final GreatCircle circle = GreatCircles.fromPoints(start, end, precision);
    113
    114         final Point1S subspaceStart = circle.toSubspace(start);
    115         final Point1S subspaceEnd = circle.toSubspace(end);
    116         final AngularInterval.Convex interval = AngularInterval.Convex.of(subspaceStart, subspaceEnd, precision);
    117
    118         return arcFromInterval(circle, interval);
    119     }
    120
    121     /** Construct an arc from a great circle and an angular interval.
    122      * @param circle circle defining the arc
    123      * @param interval interval representing the portion of the circle contained
    124      *      in the arc
    125      * @return an arc created from the given great circle and interval
    126      */
    127     public static GreatArc arcFromInterval(final GreatCircle circle, final AngularInterval.Convex interval) {
    128         return new GreatArc(circle, interval);
    129     }
    130
    131     /** Validate that the actual great circle is equivalent to the expected great circle,
    132      * throwing an exception if not.
    133      * @param expected the expected great circle
    134      * @param actual the actual great circle
    135      * @throws IllegalArgumentException if the actual great circle is not equivalent to the
    136      *      expected great circle
    137      */
    138     static void validateGreatCirclesEquivalent(final GreatCircle expected, final GreatCircle actual) {
    139         if (!expected.eq(actual, expected.getPrecision())) {
    140             throw new IllegalArgumentException("Arguments do not represent the same great circle. Expected " +
    141                     expected + " but was " + actual + ".");
    142         }
    143     }
    144 }