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