InteriorAngleLinePathConnector.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.euclidean.twod.path;

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

  20. import org.apache.commons.geometry.euclidean.twod.Line;
  21. import org.apache.commons.geometry.euclidean.twod.LineConvexSubset;

  22. /** Line subset 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 line subset and an outgoing
  25.  * line subset as measured on the minus (interior) side of the incoming line.
  26.  * If looking along the direction of the incoming line subset, smaller interior
  27.  * angles 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 InteriorAngleLinePathConnector extends AbstractLinePathConnector {
  35.     /** {@inheritDoc} */
  36.     @Override
  37.     protected ConnectableLineSubset selectConnection(final ConnectableLineSubset incoming,
  38.             final List<ConnectableLineSubset> outgoing) {

  39.         // search for the best connection
  40.         final Line incomingLine = incoming.getLineSubset().getLine();

  41.         double selectedInteriorAngle = Double.POSITIVE_INFINITY;
  42.         ConnectableLineSubset selected = null;

  43.         for (final ConnectableLineSubset candidate : outgoing) {
  44.             final double interiorAngle =
  45.                     Math.PI - incomingLine.angle(candidate.getLineSubset().getLine());

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

  51.         return selected;
  52.     }

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

  59.     /** Convenience method for connecting a collection of line subsets with interior angles
  60.      * maximized when possible. This method is equivalent to {@code new Maximize().connect(subsets)}.
  61.      * @param subsets line subsets to connect
  62.      * @return a list of connected line subset paths
  63.      * @see Maximize
  64.      */
  65.     public static List<LinePath> connectMaximized(final Collection<LineConvexSubset> subsets) {
  66.         return new Maximize().connectAll(subsets);
  67.     }

  68.     /** Convenience method for connecting a collection of line subsets with interior angles minimized
  69.      * when possible. This method is equivalent to {@code new Minimize().connect(subsets)}.
  70.      * @param subsets line subsets to connect
  71.      * @return a list of connected line subset paths
  72.      * @see Minimize
  73.      */
  74.     public static List<LinePath> connectMinimized(final Collection<LineConvexSubset> subsets) {
  75.         return new Minimize().connectAll(subsets);
  76.     }

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

  90.     /** Implementation of {@link InteriorAngleLinePathConnector} that chooses line subset
  91.      * connections that produce the smallest interior angles. Another way to visualize this is
  92.      * that when presented multiple connection options for a given line subset, this class will
  93.      * choose the option that points most to the left when viewed in the direction of the incoming
  94.      * line subset.
  95.      */
  96.     public static final class Minimize extends InteriorAngleLinePathConnector {
  97.         /** {@inheritDoc} */
  98.         @Override
  99.         protected boolean isBetterAngle(final double newAngle, final double previousAngle) {
  100.             return newAngle < previousAngle;
  101.         }
  102.     }
  103. }