Class Edge

  1  
  2  
  3  
  4 /*
  5  * Copyright (c) 2016 Vivid Solutions.
  6  *
  7  * All rights reserved. This program and the accompanying materials
  8  * are made available under the terms of the Eclipse Public License 2.0
  9  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 10  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
 11  * and the Eclipse Distribution License is available at
 12  *
 13  * http://www.eclipse.org/org/documents/edl-v10.php.
 14  */
 15 package org.locationtech.jts.geomgraph;
 16  
 17 import java.io.PrintStream;
 18  
 19 import org.locationtech.jts.algorithm.LineIntersector;
 20 import org.locationtech.jts.geom.Coordinate;
 21 import org.locationtech.jts.geom.Envelope;
 22 import org.locationtech.jts.geom.IntersectionMatrix;
 23 import org.locationtech.jts.geomgraph.index.MonotoneChainEdge;
 24  
 25  
 26 /**
 27  * @version 1.7
 28  */
 29 public class Edge
 30   extends GraphComponent
 31 {
 32  
 33   /**
 34    * Updates an IM from the label for an edge.
 35    * Handles edges from both L and A geometries.
 36    */
 37   public static void updateIM(Label label, IntersectionMatrix im)
 38   {
 39     im.setAtLeastIfValid(label.getLocation(0, Position.ON), label.getLocation(1, Position.ON), 1);
 40     if (label.isArea()) {
 41       im.setAtLeastIfValid(label.getLocation(0, Position.LEFT),  label.getLocation(1, Position.LEFT),   2);
 42       im.setAtLeastIfValid(label.getLocation(0, Position.RIGHT), label.getLocation(1, Position.RIGHT),  2);
 43     }
 44   }
 45  
 46   Coordinate[] pts;
 47   private Envelope env;
 48   EdgeIntersectionList eiList = new EdgeIntersectionList(this);
 49   private String name;
 50   private MonotoneChainEdge mce;
 51   private boolean isIsolated = true;
 52   private Depth depth = new Depth();
 53   private int depthDelta = 0;   // the change in area depth from the R to L side of this edge
 54  
 55   public Edge(Coordinate[] pts, Label label)
 56   {
 57     this.pts = pts;
 58     this.label = label;
 59   }
 60   public Edge(Coordinate[] pts)
 61   {
 62     this(pts, null);
 63   }
 64  
 65   public int getNumPoints() { return pts.length; }
 66   public void setName(String name) { this.name = name; }
 67   public Coordinate[] getCoordinates()  {    return pts;  }
 68   public Coordinate getCoordinate(int i)
 69   {
 70     return pts[i];
 71   }
 72   public Coordinate getCoordinate()
 73   {
 74     if (pts.length > 0return pts[0];
 75     return null;
 76   }
 77   public Envelope getEnvelope()
 78   {
 79     // compute envelope lazily
 80     if (env == null) {
 81       env = new Envelope();
 82       for (int i = 0; i < pts.length; i++) {
 83         env.expandToInclude(pts[i]);
 84       }
 85     }
 86     return env;
 87   }
 88  
 89   public Depth getDepth() { return depth; }
 90  
 91   /**
 92    * The depthDelta is the change in depth as an edge is crossed from R to L
 93    * @return the change in depth as the edge is crossed from R to L
 94    */
 95   public int getDepthDelta()  { return depthDelta;  }
 96   public void setDepthDelta(int depthDelta)  { this.depthDelta = depthDelta;  }
 97  
 98   public int getMaximumSegmentIndex()
 99   {
100     return pts.length - 1;
101   }
102   public EdgeIntersectionList getEdgeIntersectionList() { return eiList; }
103  
104   public MonotoneChainEdge getMonotoneChainEdge()
105   {
106     if (mce == nullmce = new MonotoneChainEdge(this);
107     return mce;
108   }
109  
110   public boolean isClosed()
111   {
112     return pts[0].equals(pts[pts.length - 1]);
113   }
114   /**
115    * An Edge is collapsed if it is an Area edge and it consists of
116    * two segments which are equal and opposite (eg a zero-width V).
117    */
118   public boolean isCollapsed()
119   {
120     if (! label.isArea()) return false;
121     if (pts.length != 3return false;
122     if (pts[0].equals(pts[2]) ) return true;
123     return false;
124   }
125   public Edge getCollapsedEdge()
126   {
127     Coordinate newPts[] = new Coordinate[2];
128     newPts[0] = pts[0];
129     newPts[1] = pts[1];
130     Edge newe = new Edge(newPts, Label.toLineLabel(label));
131     return newe;
132   }
133  
134   public void setIsolated(boolean isIsolated)
135   {
136     this.isIsolated = isIsolated;
137   }
138   public boolean isIsolated()
139   {
140     return isIsolated;
141   }
142  
143   /**
144    * Adds EdgeIntersections for one or both
145    * intersections found for a segment of an edge to the edge intersection list.
146    */
147   public void addIntersections(LineIntersector li, int segmentIndex, int geomIndex)
148   {
149     for (int i = 0; i < li.getIntersectionNum(); i++) {
150       addIntersection(li, segmentIndex, geomIndex, i);
151     }
152   }
153   /**
154    * Add an EdgeIntersection for intersection intIndex.
155    * An intersection that falls exactly on a vertex of the edge is normalized
156    * to use the higher of the two possible segmentIndexes
157    */
158   public void addIntersection(LineIntersector li, int segmentIndex, int geomIndex, int intIndex)
159   {
160       Coordinate intPt = new Coordinate(li.getIntersection(intIndex));
161       int normalizedSegmentIndex = segmentIndex;
162       double dist = li.getEdgeDistance(geomIndex, intIndex);
163 //Debug.println("edge intpt: " + intPt + " dist: " + dist);
164       // normalize the intersection point location
165       int nextSegIndex = normalizedSegmentIndex + 1;
166       if (nextSegIndex < pts.length) {
167         Coordinate nextPt = pts[nextSegIndex];
168 //Debug.println("next pt: " + nextPt);
169  
170         // Normalize segment index if intPt falls on vertex
171         // The check for point equality is 2D only - Z values are ignored
172         if (intPt.equals2D(nextPt)) {
173 //Debug.println("normalized distance");
174             normalizedSegmentIndex = nextSegIndex;
175             dist = 0.0;
176         }
177       }
178       /**
179       * Add the intersection point to edge intersection list.
180       */
181       EdgeIntersection ei = eiList.add(intPt, normalizedSegmentIndex, dist);
182 //ei.print(System.out);
183  
184   }
185  
186   /**
187    * Update the IM with the contribution for this component.
188    * A component only contributes if it has a labelling for both parent geometries
189    */
190   public void computeIM(IntersectionMatrix im)
191   {
192     updateIM(label, im);
193   }
194  
195   /**
196    * equals is defined to be:
197    * <p>
198    * e1 equals e2
199    * <b>iff</b>
200    * the coordinates of e1 are the same or the reverse of the coordinates in e2
201    */
202   public boolean equals(Object o)
203   {
204     if (! (o instanceof Edge)) return false;
205     Edge e = (Edge) o;
206  
207     if (pts.length != e.pts.length) return false;
208  
209     boolean isEqualForward = true;
210     boolean isEqualReverse = true;
211     int iRev = pts.length;
212     for (int i = 0; i < pts.length; i++) {
213       if (! pts[i].equals2D(e.pts[i])) {
214          isEqualForward = false;
215       }
216       if (! pts[i].equals2D(e.pts[--iRev])) {
217          isEqualReverse = false;
218       }
219       if (! isEqualForward && ! isEqualReverse) return false;
220     }
221     return true;
222   }
223  
224   /**
225    * @return true if the coordinate sequences of the Edges are identical
226    */
227   public boolean isPointwiseEqual(Edge e)
228   {
229     if (pts.length != e.pts.length) return false;
230  
231     for (int i = 0; i < pts.length; i++) {
232       if (! pts[i].equals2D(e.pts[i])) {
233          return false;
234       }
235     }
236     return true;
237   }
238  
239   public String toString()
240   {
241     StringBuilder builder = new StringBuilder();
242     builder.append("edge " + name + ": ");
243     builder.append("LINESTRING (");
244     for (int i = 0; i < pts.length; i++) {
245       if (i > 0) builder.append(",");
246       builder.append(pts[i].x + " " + pts[i].y);
247     }
248     builder.append(")  " + label + " " + depthDelta);
249     return builder.toString();
250   }
251   public void print(PrintStream out)
252   {
253     out.print("edge " + name + ": ");
254     out.print("LINESTRING (");
255     for (int i = 0; i < pts.length; i++) {
256       if (i > 0) out.print(",");
257       out.print(pts[i].x + " " + pts[i].y);
258     }
259     out.print(")  " + label + " " + depthDelta);
260   }
261   public void printReverse(PrintStream out)
262   {
263     out.print("edge " + name + ": ");
264     for (int i = pts.length - 1; i >= 0; i--) {
265       out.print(pts[i] + " ");
266     }
267     out.println("");
268   }
269  
270 }
271