001:
002: /*
003: * The JTS Topology Suite is a collection of Java classes that
004: * implement the fundamental operations required to validate a given
005: * geo-spatial data set to a known topological specification.
006: *
007: * Copyright (C) 2001 Vivid Solutions
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: *
023: * For more information, contact:
024: *
025: * Vivid Solutions
026: * Suite #1A
027: * 2328 Government Street
028: * Victoria BC V8T 5G5
029: * Canada
030: *
031: * (250)385-6040
032: * www.vividsolutions.com
033: */
034: package com.vividsolutions.jts.geomgraph;
035:
036: import java.io.PrintStream;
037: import java.util.Iterator;
038: import com.vividsolutions.jts.algorithm.LineIntersector;
039: import com.vividsolutions.jts.geom.*;
040: import com.vividsolutions.jts.util.*;
041: import com.vividsolutions.jts.geomgraph.*;
042: import com.vividsolutions.jts.geomgraph.index.*;
043:
044: /**
045: * @version 1.7
046: */
047: public class Edge extends GraphComponent {
048:
049: /**
050: * Updates an IM from the label for an edge.
051: * Handles edges from both L and A geometries.
052: */
053: public static void updateIM(Label label, IntersectionMatrix im) {
054: im.setAtLeastIfValid(label.getLocation(0, Position.ON), label
055: .getLocation(1, Position.ON), 1);
056: if (label.isArea()) {
057: im.setAtLeastIfValid(label.getLocation(0, Position.LEFT),
058: label.getLocation(1, Position.LEFT), 2);
059: im.setAtLeastIfValid(label.getLocation(0, Position.RIGHT),
060: label.getLocation(1, Position.RIGHT), 2);
061: }
062: }
063:
064: Coordinate[] pts;
065: private Envelope env;
066: EdgeIntersectionList eiList = new EdgeIntersectionList(this );
067: private String name;
068: private MonotoneChainEdge mce;
069: private boolean isIsolated = true;
070: private Depth depth = new Depth();
071: private int depthDelta = 0; // the change in area depth from the R to L side of this edge
072:
073: public Edge(Coordinate[] pts, Label label) {
074: this .pts = pts;
075: this .label = label;
076: }
077:
078: public Edge(Coordinate[] pts) {
079: this (pts, null);
080: }
081:
082: public int getNumPoints() {
083: return pts.length;
084: }
085:
086: public void setName(String name) {
087: this .name = name;
088: }
089:
090: public Coordinate[] getCoordinates() {
091: return pts;
092: }
093:
094: public Coordinate getCoordinate(int i) {
095: return pts[i];
096: }
097:
098: public Coordinate getCoordinate() {
099: if (pts.length > 0)
100: return pts[0];
101: return null;
102: }
103:
104: public Envelope getEnvelope() {
105: // compute envelope lazily
106: if (env == null) {
107: env = new Envelope();
108: for (int i = 0; i < pts.length; i++) {
109: env.expandToInclude(pts[i]);
110: }
111: }
112: return env;
113: }
114:
115: public Depth getDepth() {
116: return depth;
117: }
118:
119: /**
120: * The depthDelta is the change in depth as an edge is crossed from R to L
121: * @return the change in depth as the edge is crossed from R to L
122: */
123: public int getDepthDelta() {
124: return depthDelta;
125: }
126:
127: public void setDepthDelta(int depthDelta) {
128: this .depthDelta = depthDelta;
129: }
130:
131: public int getMaximumSegmentIndex() {
132: return pts.length - 1;
133: }
134:
135: public EdgeIntersectionList getEdgeIntersectionList() {
136: return eiList;
137: }
138:
139: public MonotoneChainEdge getMonotoneChainEdge() {
140: if (mce == null)
141: mce = new MonotoneChainEdge(this );
142: return mce;
143: }
144:
145: public boolean isClosed() {
146: return pts[0].equals(pts[pts.length - 1]);
147: }
148:
149: /**
150: * An Edge is collapsed if it is an Area edge and it consists of
151: * two segments which are equal and opposite (eg a zero-width V).
152: */
153: public boolean isCollapsed() {
154: if (!label.isArea())
155: return false;
156: if (pts.length != 3)
157: return false;
158: if (pts[0].equals(pts[2]))
159: return true;
160: return false;
161: }
162:
163: public Edge getCollapsedEdge() {
164: Coordinate newPts[] = new Coordinate[2];
165: newPts[0] = pts[0];
166: newPts[1] = pts[1];
167: Edge newe = new Edge(newPts, Label.toLineLabel(label));
168: return newe;
169: }
170:
171: public void setIsolated(boolean isIsolated) {
172: this .isIsolated = isIsolated;
173: }
174:
175: public boolean isIsolated() {
176: return isIsolated;
177: }
178:
179: /**
180: * Adds EdgeIntersections for one or both
181: * intersections found for a segment of an edge to the edge intersection list.
182: */
183: public void addIntersections(LineIntersector li, int segmentIndex,
184: int geomIndex) {
185: for (int i = 0; i < li.getIntersectionNum(); i++) {
186: addIntersection(li, segmentIndex, geomIndex, i);
187: }
188: }
189:
190: /**
191: * Add an EdgeIntersection for intersection intIndex.
192: * An intersection that falls exactly on a vertex of the edge is normalized
193: * to use the higher of the two possible segmentIndexes
194: */
195: public void addIntersection(LineIntersector li, int segmentIndex,
196: int geomIndex, int intIndex) {
197: Coordinate intPt = new Coordinate(li.getIntersection(intIndex));
198: int normalizedSegmentIndex = segmentIndex;
199: double dist = li.getEdgeDistance(geomIndex, intIndex);
200: //Debug.println("edge intpt: " + intPt + " dist: " + dist);
201: // normalize the intersection point location
202: int nextSegIndex = normalizedSegmentIndex + 1;
203: if (nextSegIndex < pts.length) {
204: Coordinate nextPt = pts[nextSegIndex];
205: //Debug.println("next pt: " + nextPt);
206:
207: // Normalize segment index if intPt falls on vertex
208: // The check for point equality is 2D only - Z values are ignored
209: if (intPt.equals2D(nextPt)) {
210: //Debug.println("normalized distance");
211: normalizedSegmentIndex = nextSegIndex;
212: dist = 0.0;
213: }
214: }
215: /**
216: * Add the intersection point to edge intersection list.
217: */
218: EdgeIntersection ei = eiList.add(intPt, normalizedSegmentIndex,
219: dist);
220: //ei.print(System.out);
221:
222: }
223:
224: /**
225: * Update the IM with the contribution for this component.
226: * A component only contributes if it has a labelling for both parent geometries
227: */
228: public void computeIM(IntersectionMatrix im) {
229: updateIM(label, im);
230: }
231:
232: /**
233: * equals is defined to be:
234: * <p>
235: * e1 equals e2
236: * <b>iff</b>
237: * the coordinates of e1 are the same or the reverse of the coordinates in e2
238: */
239: public boolean equals(Object o) {
240: if (!(o instanceof Edge))
241: return false;
242: Edge e = (Edge) o;
243:
244: if (pts.length != e.pts.length)
245: return false;
246:
247: boolean isEqualForward = true;
248: boolean isEqualReverse = true;
249: int iRev = pts.length;
250: for (int i = 0; i < pts.length; i++) {
251: if (!pts[i].equals2D(e.pts[i])) {
252: isEqualForward = false;
253: }
254: if (!pts[i].equals2D(e.pts[--iRev])) {
255: isEqualReverse = false;
256: }
257: if (!isEqualForward && !isEqualReverse)
258: return false;
259: }
260: return true;
261: }
262:
263: /**
264: * @return true if the coordinate sequences of the Edges are identical
265: */
266: public boolean isPointwiseEqual(Edge e) {
267: if (pts.length != e.pts.length)
268: return false;
269:
270: for (int i = 0; i < pts.length; i++) {
271: if (!pts[i].equals2D(e.pts[i])) {
272: return false;
273: }
274: }
275: return true;
276: }
277:
278: public void print(PrintStream out) {
279: out.print("edge " + name + ": ");
280: out.print("LINESTRING (");
281: for (int i = 0; i < pts.length; i++) {
282: if (i > 0)
283: out.print(",");
284: out.print(pts[i].x + " " + pts[i].y);
285: }
286: out.print(") " + label + " " + depthDelta);
287: }
288:
289: public void printReverse(PrintStream out) {
290: out.print("edge " + name + ": ");
291: for (int i = pts.length - 1; i >= 0; i--) {
292: out.print(pts[i] + " ");
293: }
294: out.println("");
295: }
296:
297: }
|