Edge.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.  *      https://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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.geometry.spherical.twod;

  22. import java.util.List;

  23. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  24. import org.hipparchus.geometry.spherical.oned.Arc;
  25. import org.hipparchus.util.FastMath;
  26. import org.hipparchus.util.MathUtils;

  27. /** Spherical polygons boundary edge.
  28.  * @see SphericalPolygonsSet#getBoundaryLoops()
  29.  * @see Vertex
  30.  */
  31. public class Edge {

  32.     /** Start vertex. */
  33.     private final Vertex start;

  34.     /** End vertex. */
  35.     private Vertex end;

  36.     /** Length of the arc. */
  37.     private double length;

  38.     /** Circle supporting the edge. */
  39.     private final Circle circle;

  40.     /** Build an edge not contained in any node yet.
  41.      * @param start start vertex
  42.      * @param end end vertex
  43.      * @param length length of the arc (it can be greater than \( \pi \))
  44.      * @param circle circle supporting the edge
  45.      */
  46.     Edge(final Vertex start, final Vertex end, final double length, final Circle circle) {

  47.         this.start  = start;
  48.         this.end    = end;
  49.         this.length = length;
  50.         this.circle = circle;

  51.         // connect the vertices back to the edge
  52.         start.setOutgoing(this);
  53.         end.setIncoming(this);

  54.     }

  55.     /** Get start vertex.
  56.      * @return start vertex
  57.      */
  58.     public Vertex getStart() {
  59.         return start;
  60.     }

  61.     /** Get end vertex.
  62.      * @return end vertex
  63.      */
  64.     public Vertex getEnd() {
  65.         return end;
  66.     }

  67.     /** Get the length of the arc.
  68.      * @return length of the arc (can be greater than \( \pi \))
  69.      */
  70.     public double getLength() {
  71.         return length;
  72.     }

  73.     /** Get the circle supporting this edge.
  74.      * @return circle supporting this edge
  75.      */
  76.     public Circle getCircle() {
  77.         return circle;
  78.     }

  79.     /** Get an intermediate point.
  80.      * <p>
  81.      * The angle along the edge should normally be between 0 and {@link #getLength()}
  82.      * in order to remain within edge limits. However, there are no checks on the
  83.      * value of the angle, so user can rebuild the full circle on which an edge is
  84.      * defined if they want.
  85.      * </p>
  86.      * @param alpha angle along the edge, counted from {@link #getStart()}
  87.      * @return an intermediate point
  88.      */
  89.     public Vector3D getPointAt(final double alpha) {
  90.         return circle.getPointAt(alpha + circle.getPhase(start.getLocation().getVector()));
  91.     }

  92.     /** Set the length.
  93.      * @param length new length
  94.      */
  95.     void setLength(final double length) {
  96.         this.length = length;
  97.     }

  98.     /** Connect the instance with a following edge.
  99.      * @param next edge following the instance
  100.      */
  101.     void setNextEdge(final Edge next) {
  102.         end = next.getStart();
  103.         end.setIncoming(this);
  104.     }

  105.     /** Split the edge.
  106.      * <p>
  107.      * Once split, this edge is not referenced anymore by the vertices,
  108.      * it is replaced by the two or three sub-edges and intermediate splitting
  109.      * vertices are introduced to connect these sub-edges together.
  110.      * </p>
  111.      * @param splitCircle circle splitting the edge in several parts
  112.      * @param outsideList list where to put parts that are outside the split circle
  113.      * @param insideList list where to put parts that are inside the split circle
  114.      */
  115.     void split(final Circle splitCircle, final List<Edge> outsideList, final List<Edge> insideList) {

  116.         // get the inside arc, synchronizing its phase with the edge itself
  117.         final double edgeStart        = circle.getPhase(start.getLocation().getVector());
  118.         final Arc    arc              = circle.getInsideArc(splitCircle);
  119.         final double arcRelativeStart = MathUtils.normalizeAngle(arc.getInf(), edgeStart + FastMath.PI) - edgeStart;
  120.         final double arcRelativeEnd   = arcRelativeStart + arc.getSize();
  121.         final double unwrappedEnd     = arcRelativeEnd - MathUtils.TWO_PI;

  122.         // build the sub-edges
  123.         final double tolerance = circle.getTolerance();
  124.         Vertex previousVertex = start;
  125.         if (unwrappedEnd >= length - tolerance) {

  126.             // the edge is entirely contained inside the circle
  127.             // we don't split anything
  128.             insideList.add(this);

  129.         } else {

  130.             // there are at least some parts of the edge that should be outside
  131.             // (even is they are later be filtered out as being too small)
  132.             double alreadyManagedLength = 0;
  133.             if (unwrappedEnd >= 0) {
  134.                 // the start of the edge is inside the circle
  135.                 previousVertex = addSubEdge(previousVertex,
  136.                                             new Vertex(new S2Point(circle.getPointAt(edgeStart + unwrappedEnd))),
  137.                                             unwrappedEnd, insideList);
  138.                 alreadyManagedLength = unwrappedEnd;
  139.             }

  140.             if (arcRelativeStart >= length - tolerance) {
  141.                 // the edge ends while still outside the circle
  142.                 if (unwrappedEnd >= 0) {
  143.                     addSubEdge(previousVertex, end,
  144.                                length - alreadyManagedLength, outsideList);
  145.                 } else {
  146.                     // the edge is entirely outside the circle
  147.                     // we don't split anything
  148.                     outsideList.add(this);
  149.                 }
  150.             } else {
  151.                 // the edge is long enough to enter inside the circle
  152.                 previousVertex = addSubEdge(previousVertex,
  153.                                             new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))),
  154.                                             arcRelativeStart - alreadyManagedLength, outsideList);
  155.                 alreadyManagedLength = arcRelativeStart;

  156.                 if (arcRelativeEnd >= length - tolerance) {
  157.                     // the edge ends while still inside the circle
  158.                     addSubEdge(previousVertex, end,
  159.                                length - alreadyManagedLength, insideList);
  160.                 } else {
  161.                     // the edge is long enough to exit outside the circle
  162.                     previousVertex = addSubEdge(previousVertex,
  163.                                                 new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeEnd))),
  164.                                                 arcRelativeEnd - alreadyManagedLength, insideList);
  165.                     alreadyManagedLength = arcRelativeEnd;
  166.                     addSubEdge(previousVertex, end,
  167.                                length - alreadyManagedLength, outsideList);
  168.                 }
  169.             }

  170.         }

  171.     }

  172.     /** Add a sub-edge to a list if long enough.
  173.      * <p>
  174.      * If the length of the sub-edge to add is smaller than the {@link Circle#getTolerance()}
  175.      * tolerance of the support circle, it will be ignored.
  176.      * </p>
  177.      * @param subStart start of the sub-edge
  178.      * @param subEnd end of the sub-edge
  179.      * @param subLength length of the sub-edge
  180.      * @param list list where to put the sub-edge
  181.      * @return end vertex of the edge ({@code subEnd} if the edge was long enough and really
  182.      * added, {@code subStart} if the edge was too small and therefore ignored)
  183.      */
  184.     private Vertex addSubEdge(final Vertex subStart, final Vertex subEnd, final double subLength, final List<Edge> list) {

  185.         if (subLength <= circle.getTolerance()) {
  186.             // the edge is too short, we ignore it
  187.             return subStart;
  188.         }

  189.         // really add the edge
  190.         final Edge edge = new Edge(subStart, subEnd, subLength, circle);
  191.         list.add(edge);
  192.         return subEnd;

  193.     }

  194. }