/*
* Copyright (c) 2016 Vivid Solutions.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jts.geomgraph;
import java.io.PrintStream;
import org.locationtech.jts.algorithm.BoundaryNodeRule;
import org.locationtech.jts.algorithm.CGAlgorithms;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.util.Assert;
/**
* 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.
* @version 1.7
*/
public class EdgeEnd
implements Comparable
{
protected Edge edge; // the parent edge of this edge end
protected Label label;
private Node node; // the node this edge end originates at
private Coordinate p0, p1; // points of initial line segment
private double dx, dy; // the direction vector for this edge from its starting point
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(BoundaryNodeRule boundaryNodeRule)
{
// 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()
{
double angle = Math.atan2(dy, dx);
String className = getClass().getName();
int lastDotPos = className.lastIndexOf('.');
String name = className.substring(lastDotPos + 1);
return " " + name + ": " + p0 + " - " + p1 + " " + quadrant + ":" + angle + " " + label;
}
}