Class SegmentIntersectionDetector

  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.algorithm.RobustLineIntersector;
 16 import org.locationtech.jts.geom.Coordinate;
 17  
 18 /**
 19  * Detects and records an intersection between two {@link SegmentString}s,
 20  * if one exists.  Only a single intersection is recorded.
 21  * This strategy can be configured to search for <b>proper intersections</b>.
 22  * In this case, the presence of <i>any</i> kind of intersection will still be recorded,
 23  * but searching will continue until either a proper intersection has been found
 24  * or no intersections are detected.
 25  *
 26  * @version 1.7
 27  */
 28 public class SegmentIntersectionDetector
 29     implements SegmentIntersector
 30 {
 31   private LineIntersector li;
 32   private boolean findProper = false;
 33   private boolean findAllTypes = false;
 34   
 35   private boolean hasIntersection = false;
 36   private boolean hasProperIntersection = false;
 37   private boolean hasNonProperIntersection = false;
 38   
 39   private Coordinate intPt = null;
 40   private Coordinate[] intSegments = null;
 41  
 42   /**
 43    * Creates an intersection finder using a {@link RobustLineIntersector}.
 44    */
 45   public SegmentIntersectionDetector()
 46   {
 47     this(new RobustLineIntersector());
 48   }
 49  
 50   /**
 51    * Creates an intersection finder using a given LineIntersector.
 52    *
 53    * @param li the LineIntersector to use
 54    */
 55   public SegmentIntersectionDetector(LineIntersector li)
 56   {
 57     this.li = li;
 58   }
 59  
 60   /**
 61    * Sets whether processing must continue until a proper intersection is found.
 62    * 
 63    * @param findProper true if processing should continue until a proper intersection is found
 64    */
 65   public void setFindProper(boolean findProper)
 66   {
 67     this.findProper = findProper;
 68   }
 69   
 70   /**
 71    * Sets whether processing can terminate once any intersection is found.
 72    * 
 73    * @param findAllTypes true if processing can terminate once any intersection is found.
 74    */
 75   public void setFindAllIntersectionTypes(boolean findAllTypes)
 76   {
 77     this.findAllTypes = findAllTypes;
 78   }
 79   
 80   /**
 81    * Tests whether an intersection was found.
 82    * 
 83    * @return true if an intersection was found
 84    */
 85   public boolean hasIntersection() 
 86   { 
 87       return hasIntersection; 
 88   }
 89   
 90   /**
 91    * Tests whether a proper intersection was found.
 92    * 
 93    * @return true if a proper intersection was found
 94    */
 95   public boolean hasProperIntersection() 
 96   { 
 97     return hasProperIntersection; 
 98   }
 99   
100   /**
101    * Tests whether a non-proper intersection was found.
102    * 
103    * @return true if a non-proper intersection was found
104    */
105   public boolean hasNonProperIntersection() 
106   { 
107     return hasNonProperIntersection; 
108   }
109   
110   /**
111    * Gets the computed location of the intersection.
112    * Due to round-off, the location may not be exact.
113    * 
114    * @return the coordinate for the intersection location
115    */
116   public Coordinate getIntersection()  
117   {    
118       return intPt;  
119   }
120  
121  
122   /**
123    * Gets the endpoints of the intersecting segments.
124    * 
125    * @return an array of the segment endpoints (p00, p01, p10, p11)
126    */
127   public Coordinate[] getIntersectionSegments()
128   {
129       return intSegments;
130   }
131   
132   /**
133    * This method is called by clients
134    * of the {@link SegmentIntersector} class to process
135    * intersections for two segments of the {@link SegmentString}s being intersected.
136    * Note that some clients (such as <code>MonotoneChain</code>s) may optimize away
137    * this call for segment pairs which they have determined do not intersect
138    * (e.g. by an disjoint envelope test).
139    */
140   public void processIntersections(
141       SegmentString e0,  int segIndex0,
142       SegmentString e1,  int segIndex1
143       )
144   {      
145     // don't bother intersecting a segment with itself
146     if (e0 == e1 && segIndex0 == segIndex1) return;
147     
148     Coordinate p00 = e0.getCoordinates()[segIndex0];
149     Coordinate p01 = e0.getCoordinates()[segIndex0 + 1];
150     Coordinate p10 = e1.getCoordinates()[segIndex1];
151     Coordinate p11 = e1.getCoordinates()[segIndex1 + 1];
152     
153     li.computeIntersection(p00, p01, p10, p11);
154 //  if (li.hasIntersection() && li.isProper()) Debug.println(li);
155  
156     if (li.hasIntersection()) {
157             // System.out.println(li);
158         
159         // record intersection info
160             hasIntersection = true;
161             
162             boolean isProper = li.isProper();
163             if (isProper)
164                 hasProperIntersection = true;
165       if (! isProper)
166         hasNonProperIntersection = true;
167             
168             /**
169              * If this is the kind of intersection we are searching for
170              * OR no location has yet been recorded
171              * save the location data
172              */
173             boolean saveLocation = true;
174             if (findProper && ! isProper) saveLocation = false;
175             
176             if (intPt == null || saveLocation) {
177  
178                 // record intersection location (approximate)
179                 intPt = li.getIntersection(0);
180  
181                 // record intersecting segments
182                 intSegments = new Coordinate[4];
183                 intSegments[0] = p00;
184                 intSegments[1] = p01;
185                 intSegments[2] = p10;
186                 intSegments[3] = p11;
187             }
188         }
189   }
190   
191   /**
192    * Tests whether processing can terminate,
193    * because all required information has been obtained
194    * (e.g. an intersection of the desired type has been detected).
195    * 
196    * @return true if processing can terminate
197    */
198   public boolean isDone()
199   { 
200     /**
201      * If finding all types, we can stop
202      * when both possible types have been found.
203      */
204     if (findAllTypes) {
205       return hasProperIntersection && hasNonProperIntersection;
206     }
207     
208       /**
209        * If searching for a proper intersection, only stop if one is found
210        */
211       if (findProper) {
212           return hasProperIntersection;
213       }
214       return hasIntersection;
215   }
216 }
217