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 }