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 java.util.Collection;
    20  import java.util.List;
    21
    22  import org.apache.commons.numbers.angle.PlaneAngleRadians;
    23
    24  /** Great arc connector that selects between multiple connection options
    25   * based on the resulting interior angle. An interior angle in this
    26   * case is the angle created between an incoming arc and an outgoing arc
    27   * as measured on the minus (interior) side of the incoming arc. If looking
    28   * along the direction of the incoming arc, smaller interior angles
    29   * point more to the left and larger ones point more to the right.
    30   *
    31   * <p>This class provides two concrete implementations: {@link Maximize} and
    32   * {@link Minimize}, which choose connections with the largest or smallest interior
    33   * angles respectively.
    34   * </p>
    35   */
    36  public abstract class InteriorAngleGreatArcConnector extends AbstractGreatArcConnector {
    37      /** {@inheritDoc} */
    38      @Override
    39      protected ConnectableGreatArc selectConnection(final ConnectableGreatArc incoming,
    40              final List<ConnectableGreatArc> outgoing) {
    41
    42          // search for the best connection
    43          final GreatCircle circle = incoming.getArc().getCircle();
    44
    45          double selectedInteriorAngle = Double.POSITIVE_INFINITY;
    46          ConnectableGreatArc selected = null;
    47
    48          for (final ConnectableGreatArc candidate : outgoing) {
    49              final double interiorAngle = PlaneAngleRadians.PI - circle.angle(candidate.getArc().getCircle(),
    50                      incoming.getArc().getEndPoint());
    51
    52              if (selected == null || isBetterAngle(interiorAngle, selectedInteriorAngle)) {
    53                  selectedInteriorAngle = interiorAngle;
    54                  selected = candidate;
    55              }
    56          }
    57
    58          return selected;
    59      }
    60
    61      /** Return true if {@code newAngle} represents a better interior angle than {@code previousAngle}.
    62       * @param newAngle the new angle under consideration
    63       * @param previousAngle the previous best angle
    64       * @return true if {@code newAngle} represents a better interior angle than {@code previousAngle}
    65       */
    66      protected abstract boolean isBetterAngle(double newAngle, double previousAngle);
    67
    68      /** Convenience method for connecting a set of arcs with interior angles maximized
    69       * when possible. This method is equivalent to {@code new Maximize().connect(segments)}.
    70       * @param arcs arcs to connect
    71       * @return a list of connected arc paths
    72       * @see Maximize
    73       */
    74      public static List<GreatArcPath> connectMaximized(final Collection<GreatArc> arcs) {
    75          return new Maximize().connectAll(arcs);
    76      }
    77
    78      /** Convenience method for connecting a set of line segments with interior angles minimized
    79       * when possible. This method is equivalent to {@code new Minimize().connect(segments)}.
    80       * @param arcs arcs to connect
    81       * @return a list of connected arc paths
    82       * @see Minimize
    83       */
    84      public static List<GreatArcPath> connectMinimized(final Collection<GreatArc> arcs) {
    85          return new Minimize().connectAll(arcs);
    86      }
    87
    88      /** Implementation of {@link InteriorAngleGreatArcConnector} that chooses arc
    89       * connections that produce the largest interior angles. Another way to visualize this is
    90       * that when presented multiple connection options for a given arc, this class will
    91       * choose the option that points most to the right when viewed in the direction of the incoming
    92       * arc.
    93       */
    94      public static class Maximize extends InteriorAngleGreatArcConnector {
    95          /** {@inheritDoc} */
    96          @Override
    97          protected boolean isBetterAngle(final double newAngle, final double previousAngle) {
    98              return newAngle > previousAngle;
    99          }
    100     }
    101
    102     /** Implementation of {@link InteriorAngleGreatArcConnector} that chooses arc
    103      * connections that produce the smallest interior angles. Another way to visualize this is
    104      * that when presented multiple connection options for a given arc, this class will
    105      * choose the option that points most to the left when viewed in the direction of the incoming
    106      * arc.
    107      */
    108     public static class Minimize extends InteriorAngleGreatArcConnector {
    109         /** {@inheritDoc} */
    110         @Override
    111         protected boolean isBetterAngle(final double newAngle, final double previousAngle) {
    112             return newAngle < previousAngle;
    113         }
    114     }
    115 }