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