Class DirectedEdge

  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.geom.Location;
 20 import org.locationtech.jts.geom.TopologyException;
 21  
 22  
 23 /**
 24  * @version 1.7
 25  */
 26 public class DirectedEdge
 27   extends EdgeEnd
 28 {
 29  
 30   /**
 31    * Computes the factor for the change in depth when moving from one location to another.
 32    * E.g. if crossing from the INTERIOR to the EXTERIOR the depth decreases, so the factor is -1
 33    */
 34   public static int depthFactor(int currLocation, int nextLocation)
 35   {
 36     if (currLocation == Location.EXTERIOR && nextLocation == Location.INTERIOR)
 37        return 1;
 38     else if (currLocation == Location.INTERIOR && nextLocation == Location.EXTERIOR)
 39        return -1;
 40     return 0;
 41   }
 42  
 43   protected boolean isForward;
 44   private boolean isInResult = false;
 45   private boolean isVisited = false;
 46  
 47   private DirectedEdge sym// the symmetric edge
 48   private DirectedEdge next;  // the next edge in the edge ring for the polygon containing this edge
 49   private DirectedEdge nextMin;  // the next edge in the MinimalEdgeRing that contains this edge
 50   private EdgeRing edgeRing;  // the EdgeRing that this edge is part of
 51   private EdgeRing minEdgeRing;  // the MinimalEdgeRing that this edge is part of
 52   /**
 53    * The depth of each side (position) of this edge.
 54    * The 0 element of the array is never used.
 55    */
 56   private int[] depth = { 0, -999, -999 };
 57  
 58   public DirectedEdge(Edge edge, boolean isForward)
 59   {
 60     super(edge);
 61     this.isForward = isForward;
 62     if (isForward) {
 63       init(edge.getCoordinate(0), edge.getCoordinate(1));
 64     }
 65     else {
 66       int n = edge.getNumPoints() - 1;
 67       init(edge.getCoordinate(n), edge.getCoordinate(n-1));
 68     }
 69     computeDirectedLabel();
 70   }
 71   public Edge getEdge() { return edge; }
 72   public void setInResult(boolean isInResult) { this.isInResult = isInResult; }
 73   public boolean isInResult() { return isInResult; }
 74   public boolean isVisited() { return isVisited; }
 75   public void setVisited(boolean isVisited) { this.isVisited = isVisited; }
 76   public void setEdgeRing(EdgeRing edgeRing) { this.edgeRing = edgeRing; }
 77   public EdgeRing getEdgeRing() { return edgeRing; }
 78   public void setMinEdgeRing(EdgeRing minEdgeRing) { this.minEdgeRing = minEdgeRing; }
 79   public EdgeRing getMinEdgeRing() { return minEdgeRing; }
 80   public int getDepth(int position) { return depth[position]; }
 81  
 82   public void setDepth(int position, int depthVal)
 83   {
 84     if (depth[position] != -999) {
 85 //      if (depth[position] != depthVal) {
 86 //        Debug.print(this);
 87 //      }
 88       if (depth[position] != depthVal)
 89         throw new TopologyException("assigned depths do not match", getCoordinate());
 90       //Assert.isTrue(depth[position] == depthVal, "assigned depths do not match at " + getCoordinate());
 91     }
 92     depth[position] = depthVal;
 93   }
 94  
 95   public int getDepthDelta()
 96   {
 97     int depthDelta = edge.getDepthDelta();
 98     if (! isForward) depthDelta = -depthDelta;
 99     return depthDelta;
100   }
101  
102   /**
103    * setVisitedEdge marks both DirectedEdges attached to a given Edge.
104    * This is used for edges corresponding to lines, which will only
105    * appear oriented in a single direction in the result.
106    */
107   public void setVisitedEdge(boolean isVisited)
108   {
109     setVisited(isVisited);
110     sym.setVisited(isVisited);
111   }
112   /**
113    * Each Edge gives rise to a pair of symmetric DirectedEdges, in opposite
114    * directions.
115    * @return the DirectedEdge for the same Edge but in the opposite direction
116    */
117   public DirectedEdge getSym() { return sym; }
118   public boolean isForward() { return isForward; }
119   public void setSym(DirectedEdge de)
120   {
121     sym = de;
122   }
123   public DirectedEdge getNext() { return next; }
124   public void setNext(DirectedEdge next) { this.next = next; }
125   public DirectedEdge getNextMin() { return nextMin; }
126   public void setNextMin(DirectedEdge nextMin) { this.nextMin = nextMin; }
127  
128   /**
129    * This edge is a line edge if
130    * <ul>
131    * <li> at least one of the labels is a line label
132    * <li> any labels which are not line labels have all Locations = EXTERIOR
133    * </ul>
134    */
135   public boolean isLineEdge()
136   {
137     boolean isLine = label.isLine(0) || label.isLine(1);
138     boolean isExteriorIfArea0 =
139       ! label.isArea(0) || label.allPositionsEqual(0, Location.EXTERIOR);
140     boolean isExteriorIfArea1 =
141       ! label.isArea(1) || label.allPositionsEqual(1, Location.EXTERIOR);
142  
143     return isLine && isExteriorIfArea0 && isExteriorIfArea1;
144   }
145   /**
146    * This is an interior Area edge if
147    * <ul>
148    * <li> its label is an Area label for both Geometries
149    * <li> and for each Geometry both sides are in the interior.
150    * </ul>
151    *
152    * @return true if this is an interior Area edge
153    */
154   public boolean isInteriorAreaEdge()
155   {
156     boolean isInteriorAreaEdge = true;
157     for (int i = 0; i < 2; i++) {
158       if (! ( label.isArea(i)
159             && label.getLocation(i, Position.LEFT ) == Location.INTERIOR
160             && label.getLocation(i, Position.RIGHT) == Location.INTERIOR) ) {
161         isInteriorAreaEdge = false;
162       }
163     }
164     return isInteriorAreaEdge;
165   }
166  
167   /**
168    * Compute the label in the appropriate orientation for this DirEdge
169    */
170   private void computeDirectedLabel()
171   {
172     label = new Label(edge.getLabel());
173     if (! isForward)
174       label.flip();
175   }
176  
177   /**
178    * Set both edge depths.  One depth for a given side is provided.  The other is
179    * computed depending on the Location transition and the depthDelta of the edge.
180    */
181   public void setEdgeDepths(int position, int depth)
182   {
183     // get the depth transition delta from R to L for this directed Edge
184     int depthDelta = getEdge().getDepthDelta();
185     if (! isForward) depthDelta = -depthDelta;
186  
187     // if moving from L to R instead of R to L must change sign of delta
188     int directionFactor = 1;
189     if (position == Position.LEFT)
190       directionFactor = -1;
191  
192     int oppositePos = Position.opposite(position);
193     int delta = depthDelta * directionFactor;
194     //TESTINGint delta = depthDelta * DirectedEdge.depthFactor(loc, oppositeLoc);
195     int oppositeDepth = depth + delta;
196     setDepth(position, depth);
197     setDepth(oppositePos, oppositeDepth);
198   }
199  
200   public void print(PrintStream out)
201   {
202     super.print(out);
203     out.print(" " + depth[Position.LEFT] + "/" + depth[Position.RIGHT]);
204     out.print(" (" + getDepthDelta() + ")");
205     //out.print(" " + this.hashCode());
206     //if (next != null) out.print(" next:" + next.hashCode());
207     if (isInResult) out.print(" inResult");
208   }
209   public void printEdge(PrintStream out)
210   {
211     print(out);
212     out.print(" ");
213     if (isForward)
214       edge.print(out);
215     else
216       edge.printReverse(out);
217   }
218  
219 }
220