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 com.vividsolutions.jts.geom.*;
038: import com.vividsolutions.jts.algorithm.*;
039: import com.vividsolutions.jts.util.*;
040: import com.vividsolutions.jts.geomgraph.Label;
041: import com.vividsolutions.jts.geomgraph.Edge;
042:
043: /**
044: * Models the end of an edge incident on a node.
045: * EdgeEnds have a direction
046: * determined by the direction of the ray from the initial
047: * point to the next point.
048: * EdgeEnds are comparable under the ordering
049: * "a has a greater angle with the x-axis than b".
050: * This ordering is used to sort EdgeEnds around a node.
051: * @version 1.7
052: */
053: public class EdgeEnd implements Comparable {
054: protected Edge edge; // the parent edge of this edge end
055: protected Label label;
056:
057: private Node node; // the node this edge end originates at
058: private Coordinate p0, p1; // points of initial line segment
059: private double dx, dy; // the direction vector for this edge from its starting point
060: private int quadrant;
061:
062: protected EdgeEnd(Edge edge) {
063: this .edge = edge;
064: }
065:
066: public EdgeEnd(Edge edge, Coordinate p0, Coordinate p1) {
067: this (edge, p0, p1, null);
068: }
069:
070: public EdgeEnd(Edge edge, Coordinate p0, Coordinate p1, Label label) {
071: this (edge);
072: init(p0, p1);
073: this .label = label;
074: }
075:
076: protected void init(Coordinate p0, Coordinate p1) {
077: this .p0 = p0;
078: this .p1 = p1;
079: dx = p1.x - p0.x;
080: dy = p1.y - p0.y;
081: quadrant = Quadrant.quadrant(dx, dy);
082: Assert.isTrue(!(dx == 0 && dy == 0),
083: "EdgeEnd with identical endpoints found");
084: }
085:
086: public Edge getEdge() {
087: return edge;
088: }
089:
090: public Label getLabel() {
091: return label;
092: }
093:
094: public Coordinate getCoordinate() {
095: return p0;
096: }
097:
098: public Coordinate getDirectedCoordinate() {
099: return p1;
100: }
101:
102: public int getQuadrant() {
103: return quadrant;
104: }
105:
106: public double getDx() {
107: return dx;
108: }
109:
110: public double getDy() {
111: return dy;
112: }
113:
114: public void setNode(Node node) {
115: this .node = node;
116: }
117:
118: public Node getNode() {
119: return node;
120: }
121:
122: public int compareTo(Object obj) {
123: EdgeEnd e = (EdgeEnd) obj;
124: return compareDirection(e);
125: }
126:
127: /**
128: * Implements the total order relation:
129: * <p>
130: * a has a greater angle with the positive x-axis than b
131: * <p>
132: * Using the obvious algorithm of simply computing the angle is not robust,
133: * since the angle calculation is obviously susceptible to roundoff.
134: * A robust algorithm is:
135: * - first compare the quadrant. If the quadrants
136: * are different, it it trivial to determine which vector is "greater".
137: * - if the vectors lie in the same quadrant, the computeOrientation function
138: * can be used to decide the relative orientation of the vectors.
139: */
140: public int compareDirection(EdgeEnd e) {
141: if (dx == e.dx && dy == e.dy)
142: return 0;
143: // if the rays are in different quadrants, determining the ordering is trivial
144: if (quadrant > e.quadrant)
145: return 1;
146: if (quadrant < e.quadrant)
147: return -1;
148: // vectors are in the same quadrant - check relative orientation of direction vectors
149: // this is > e if it is CCW of e
150: return CGAlgorithms.computeOrientation(e.p0, e.p1, p1);
151: }
152:
153: public void computeLabel(BoundaryNodeRule boundaryNodeRule) {
154: // subclasses should override this if they are using labels
155: }
156:
157: public void print(PrintStream out) {
158: double angle = Math.atan2(dy, dx);
159: String className = getClass().getName();
160: int lastDotPos = className.lastIndexOf('.');
161: String name = className.substring(lastDotPos + 1);
162: out.print(" " + name + ": " + p0 + " - " + p1 + " " + quadrant
163: + ":" + angle + " " + label);
164: }
165: }
|