Class IntersectionAdder

  1 /*
  2  * Copyright (c) 2016 Vivid Solutions.
  3  *
  4  * All rights reserved. This program and the accompanying materials
  5  * are made available under the terms of the Eclipse Public License 2.0
  6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  8  * and the Eclipse Distribution License is available at
  9  *
 10  * http://www.eclipse.org/org/documents/edl-v10.php.
 11  */
 12 package org.locationtech.jts.noding;
 13  
 14 import org.locationtech.jts.algorithm.LineIntersector;
 15 import org.locationtech.jts.geom.Coordinate;
 16  
 17 /**
 18  * Computes the possible intersections between two line segments in {@link NodedSegmentString}s
 19  * and adds them to each string 
 20  * using {@link NodedSegmentString#addIntersection(LineIntersector, int, int, int)}.
 21  *
 22  * @version 1.7
 23  */
 24 public class IntersectionAdder
 25     implements SegmentIntersector
 26 {
 27   public static boolean isAdjacentSegments(int i1, int i2)
 28   {
 29     return Math.abs(i1 - i2) == 1;
 30   }
 31  
 32   /**
 33    * These variables keep track of what types of intersections were
 34    * found during ALL edges that have been intersected.
 35    */
 36   private boolean hasIntersection = false;
 37   private boolean hasProper = false;
 38   private boolean hasProperInterior = false;
 39   private boolean hasInterior = false;
 40  
 41   // the proper intersection point found
 42   private Coordinate properIntersectionPoint = null;
 43  
 44   private LineIntersector li;
 45   private boolean isSelfIntersection;
 46   //private boolean intersectionFound;
 47   public int numIntersections = 0;
 48   public int numInteriorIntersections = 0;
 49   public int numProperIntersections = 0;
 50  
 51   // testing only
 52   public int numTests = 0;
 53  
 54   public IntersectionAdder(LineIntersector li)
 55   {
 56     this.li = li;
 57   }
 58  
 59   public LineIntersector getLineIntersector() { return li; }
 60  
 61   /**
 62    * @return the proper intersection point, or <code>null</code> if none was found
 63    */
 64   public Coordinate getProperIntersectionPoint()  {    return properIntersectionPoint;  }
 65  
 66   public boolean hasIntersection() { return hasIntersection; }
 67   /**
 68    * A proper intersection is an intersection which is interior to at least two
 69    * line segments.  Note that a proper intersection is not necessarily
 70    * in the interior of the entire Geometry, since another edge may have
 71    * an endpoint equal to the intersection, which according to SFS semantics
 72    * can result in the point being on the Boundary of the Geometry.
 73    */
 74   public boolean hasProperIntersection() { return hasProper; }
 75   /**
 76    * A proper interior intersection is a proper intersection which is <b>not</b>
 77    * contained in the set of boundary nodes set for this SegmentIntersector.
 78    */
 79   public boolean hasProperInteriorIntersection() { return hasProperInterior; }
 80   /**
 81    * An interior intersection is an intersection which is
 82    * in the interior of some segment.
 83    */
 84   public boolean hasInteriorIntersection() { return hasInterior; }
 85  
 86   /**
 87    * A trivial intersection is an apparent self-intersection which in fact
 88    * is simply the point shared by adjacent line segments.
 89    * Note that closed edges require a special check for the point shared by the beginning
 90    * and end segments.
 91    */
 92   private boolean isTrivialIntersection(SegmentString e0, int segIndex0, SegmentString e1, int segIndex1)
 93   {
 94     if (e0 == e1) {
 95       if (li.getIntersectionNum() == 1) {
 96         if (isAdjacentSegments(segIndex0, segIndex1))
 97           return true;
 98         if (e0.isClosed()) {
 99           int maxSegIndex = e0.size() - 1;
100           if (    (segIndex0 == 0 && segIndex1 == maxSegIndex)
101               ||  (segIndex1 == 0 && segIndex0 == maxSegIndex) ) {
102             return true;
103           }
104         }
105       }
106     }
107     return false;
108   }
109  
110   /**
111    * This method is called by clients
112    * of the {@link SegmentIntersector} class to process
113    * intersections for two segments of the {@link SegmentString}s being intersected.
114    * Note that some clients (such as <code>MonotoneChain</code>s) may optimize away
115    * this call for segment pairs which they have determined do not intersect
116    * (e.g. by an disjoint envelope test).
117    */
118   public void processIntersections(
119     SegmentString e0,  int segIndex0,
120     SegmentString e1,  int segIndex1
121      )
122   {
123     if (e0 == e1 && segIndex0 == segIndex1) return;
124 numTests++;
125     Coordinate p00 = e0.getCoordinates()[segIndex0];
126     Coordinate p01 = e0.getCoordinates()[segIndex0 + 1];
127     Coordinate p10 = e1.getCoordinates()[segIndex1];
128     Coordinate p11 = e1.getCoordinates()[segIndex1 + 1];
129  
130     li.computeIntersection(p00, p01, p10, p11);
131 //if (li.hasIntersection() && li.isProper()) Debug.println(li);
132     if (li.hasIntersection()) {
133       //intersectionFound = true;
134       numIntersections++;
135       if (li.isInteriorIntersection()) {
136         numInteriorIntersections++;
137         hasInterior = true;
138 //System.out.println(li);
139       }
140       // if the segments are adjacent they have at least one trivial intersection,
141       // the shared endpoint.  Don't bother adding it if it is the
142       // only intersection.
143       if (! isTrivialIntersection(e0, segIndex0, e1, segIndex1)) {
144         hasIntersection = true;
145         ((NodedSegmentString) e0).addIntersections(li, segIndex0, 0);
146         ((NodedSegmentString) e1).addIntersections(li, segIndex1, 1);
147         if (li.isProper()) {
148           numProperIntersections++;
149 //Debug.println(li.toString());  Debug.println(li.getIntersection(0));
150           //properIntersectionPoint = (Coordinate) li.getIntersection(0).clone();
151           hasProper = true;
152           hasProperInterior = true;
153         }
154       }
155     }
156   }
157   
158   /**
159    * Always process all intersections
160    * 
161    * @return false always
162    */
163   public boolean isDone() { return false; }
164 }
165