InteriorAngleGreatArcConnector.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.spherical.twod;

  18. import java.util.Collection;
  19. import java.util.List;

  20. /** Great arc connector that selects between multiple connection options
  21.  * based on the resulting interior angle. An interior angle in this
  22.  * case is the angle created between an incoming arc and an outgoing arc
  23.  * as measured on the minus (interior) side of the incoming arc. If looking
  24.  * along the direction of the incoming arc, smaller interior angles
  25.  * point more to the left and larger ones point more to the right.
  26.  *
  27.  * <p>This class provides two concrete implementations: {@link Maximize} and
  28.  * {@link Minimize}, which choose connections with the largest or smallest interior
  29.  * angles respectively.
  30.  * </p>
  31.  */
  32. public abstract class InteriorAngleGreatArcConnector extends AbstractGreatArcConnector {
  33.     /** {@inheritDoc} */
  34.     @Override
  35.     protected ConnectableGreatArc selectConnection(final ConnectableGreatArc incoming,
  36.             final List<ConnectableGreatArc> outgoing) {

  37.         // search for the best connection
  38.         final GreatCircle circle = incoming.getArc().getCircle();

  39.         double selectedInteriorAngle = Double.POSITIVE_INFINITY;
  40.         ConnectableGreatArc selected = null;

  41.         for (final ConnectableGreatArc candidate : outgoing) {
  42.             final double interiorAngle = Math.PI - circle.angle(candidate.getArc().getCircle(),
  43.                     incoming.getArc().getEndPoint());

  44.             if (selected == null || isBetterAngle(interiorAngle, selectedInteriorAngle)) {
  45.                 selectedInteriorAngle = interiorAngle;
  46.                 selected = candidate;
  47.             }
  48.         }

  49.         return selected;
  50.     }

  51.     /** Return true if {@code newAngle} represents a better interior angle than {@code previousAngle}.
  52.      * @param newAngle the new angle under consideration
  53.      * @param previousAngle the previous best angle
  54.      * @return true if {@code newAngle} represents a better interior angle than {@code previousAngle}
  55.      */
  56.     protected abstract boolean isBetterAngle(double newAngle, double previousAngle);

  57.     /** Convenience method for connecting a set of arcs with interior angles maximized
  58.      * when possible. This method is equivalent to {@code new Maximize().connect(segments)}.
  59.      * @param arcs arcs to connect
  60.      * @return a list of connected arc paths
  61.      * @see Maximize
  62.      */
  63.     public static List<GreatArcPath> connectMaximized(final Collection<GreatArc> arcs) {
  64.         return new Maximize().connectAll(arcs);
  65.     }

  66.     /** Convenience method for connecting a set of line segments with interior angles minimized
  67.      * when possible. This method is equivalent to {@code new Minimize().connect(segments)}.
  68.      * @param arcs arcs to connect
  69.      * @return a list of connected arc paths
  70.      * @see Minimize
  71.      */
  72.     public static List<GreatArcPath> connectMinimized(final Collection<GreatArc> arcs) {
  73.         return new Minimize().connectAll(arcs);
  74.     }

  75.     /** Implementation of {@link InteriorAngleGreatArcConnector} that chooses arc
  76.      * connections that produce the largest interior angles. Another way to visualize this is
  77.      * that when presented multiple connection options for a given arc, this class will
  78.      * choose the option that points most to the right when viewed in the direction of the incoming
  79.      * arc.
  80.      */
  81.     public static class Maximize extends InteriorAngleGreatArcConnector {
  82.         /** {@inheritDoc} */
  83.         @Override
  84.         protected boolean isBetterAngle(final double newAngle, final double previousAngle) {
  85.             return newAngle > previousAngle;
  86.         }
  87.     }

  88.     /** Implementation of {@link InteriorAngleGreatArcConnector} that chooses arc
  89.      * connections that produce the smallest 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 left when viewed in the direction of the incoming
  92.      * arc.
  93.      */
  94.     public static class Minimize extends InteriorAngleGreatArcConnector {
  95.         /** {@inheritDoc} */
  96.         @Override
  97.         protected boolean isBetterAngle(final double newAngle, final double previousAngle) {
  98.             return newAngle < previousAngle;
  99.         }
  100.     }
  101. }