/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2001-2006 Vivid Solutions * (C) 2001-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.geometry.iso.topograph2D; import java.io.PrintStream; import org.geotools.geometry.iso.util.Assert; import org.geotools.geometry.iso.util.algorithm2D.CGAlgorithms; /** * Models the end of an edge incident on a node. EdgeEnds have a direction * determined by the direction of the ray from the initial point to the next * point. EdgeEnds are comparable under the ordering "a has a greater angle with * the x-axis than b". This ordering is used to sort EdgeEnds around a node. * * @source $URL$ */ public class EdgeEnd implements Comparable { protected Edge edge; // the parent edge of this edge end protected Label label; // the node this edge end originates at private Node node; // points of initial line segment private Coordinate p0, p1; // the direction vector for this edge from its starting point private double dx, dy; private int quadrant; protected EdgeEnd(Edge edge) { this.edge = edge; } public EdgeEnd(Edge edge, Coordinate p0, Coordinate p1) { this(edge, p0, p1, null); } public EdgeEnd(Edge edge, Coordinate p0, Coordinate p1, Label label) { this(edge); init(p0, p1); this.label = label; } protected void init(Coordinate p0, Coordinate p1) { this.p0 = p0; this.p1 = p1; dx = p1.x - p0.x; dy = p1.y - p0.y; quadrant = Quadrant.quadrant(dx, dy); Assert.isTrue(!(dx == 0 && dy == 0), "EdgeEnd with identical endpoints found"); } public Edge getEdge() { return edge; } public Label getLabel() { return label; } public Coordinate getCoordinate() { return p0; } public Coordinate getDirectedCoordinate() { return p1; } public int getQuadrant() { return quadrant; } public double getDx() { return dx; } public double getDy() { return dy; } public void setNode(Node node) { this.node = node; } public Node getNode() { return node; } public int compareTo(Object obj) { EdgeEnd e = (EdgeEnd) obj; return compareDirection(e); } /** * Implements the total order relation: * <p> * a has a greater angle with the positive x-axis than b * <p> * Using the obvious algorithm of simply computing the angle is not robust, * since the angle calculation is obviously susceptible to roundoff. A * robust algorithm is: - first compare the quadrant. If the quadrants are * different, it it trivial to determine which vector is "greater". - if the * vectors lie in the same quadrant, the computeOrientation function can be * used to decide the relative orientation of the vectors. */ public int compareDirection(EdgeEnd e) { if (dx == e.dx && dy == e.dy) return 0; // if the rays are in different quadrants, determining the ordering is // trivial if (quadrant > e.quadrant) return 1; if (quadrant < e.quadrant) return -1; // vectors are in the same quadrant - check relative orientation of // direction vectors // this is > e if it is CCW of e return CGAlgorithms.computeOrientation(e.p0, e.p1, p1); } public void computeLabel() { // subclasses should override this if they are using labels } public void print(PrintStream out) { double angle = Math.atan2(dy, dx); String className = getClass().getName(); int lastDotPos = className.lastIndexOf('.'); String name = className.substring(lastDotPos + 1); out.print(" " + name + ": " + p0 + " - " + p1 + " " + quadrant + ":" + angle + " " + label); } public String toString() { return "DE(" + this.p0 + ", " + this.p1 + ")"; } }