using System; using System.Collections; using System.IO; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Algorithm; using GisSharpBlog.NetTopologySuite.GeometriesGraph; namespace GisSharpBlog.NetTopologySuite.Planargraph { /// /// Represents a directed edge in a PlanarGraph. A DirectedEdge may or /// may not have a reference to a parent Edge (some applications of /// planar graphs may not require explicit Edge objects to be created). Usually /// a client using a PlanarGraph will subclass DirectedEdge /// to add its own application-specific data and methods. /// public class DirectedEdge : GraphComponent, IComparable { /// /// /// protected Edge parentEdge; /// /// /// protected Node from; /// /// /// protected Node to; /// /// /// protected ICoordinate p0, p1; /// /// /// protected DirectedEdge sym = null; // optional /// /// /// protected bool edgeDirection; /// /// /// protected int quadrant; /// /// /// protected double angle; /// /// Constructs a DirectedEdge connecting the from node to the /// to node. /// /// /// /// /// Specifies this DirectedEdge's direction (given by an imaginary /// line from the from node to directionPt). /// /// /// Whether this DirectedEdge's direction is the same as or /// opposite to that of the parent Edge (if any). /// public DirectedEdge(Node from, Node to, ICoordinate directionPt, bool edgeDirection) { this.from = from; this.to = to; this.edgeDirection = edgeDirection; p0 = from.Coordinate; p1 = directionPt; double dx = p1.X - p0.X; double dy = p1.Y - p0.Y; quadrant = QuadrantOp.Quadrant(dx, dy); angle = Math.Atan2(dy, dx); } /// /// Tests whether this component has been removed from its containing graph. /// /// public override bool IsRemoved { get { return parentEdge == null; } } /// /// Returns this DirectedEdge's parent Edge, or null if it has none. /// Associates this DirectedEdge with an Edge (possibly null, indicating no associated /// Edge). /// public Edge Edge { get { return parentEdge; } set { parentEdge = value; } } /// /// Returns 0, 1, 2, or 3, indicating the quadrant in which this DirectedEdge's /// orientation lies. /// public int Quadrant { get { return quadrant; } } /// /// Returns a point to which an imaginary line is drawn from the from-node to /// specify this DirectedEdge's orientation. /// public ICoordinate DirectionPt { get { return p1; } } /// /// Returns whether the direction of the parent Edge (if any) is the same as that /// of this Directed Edge. /// public bool EdgeDirection { get { return edgeDirection; } } /// /// Returns the node from which this DirectedEdge leaves. /// public Node FromNode { get { return from; } } /// /// Returns the node to which this DirectedEdge goes. /// public Node ToNode { get { return to; } } /// /// Returns the coordinate of the from-node. /// public ICoordinate Coordinate { get { return from.Coordinate; } } /// /// Returns the angle that the start of this DirectedEdge makes with the /// positive x-axis, in radians. /// public double Angle { get { return angle; } } /// /// Returns the symmetric DirectedEdge -- the other DirectedEdge associated with /// this DirectedEdge's parent Edge. /// Sets this DirectedEdge's symmetric DirectedEdge, which runs in the opposite /// direction. /// public DirectedEdge Sym { get { return sym; } set { sym = value; } } /// /// Returns a List containing the parent Edge (possibly null) for each of the given /// DirectedEdges. /// /// /// public static IList ToEdges(IList dirEdges) { IList edges = new ArrayList(); for (IEnumerator i = dirEdges.GetEnumerator(); i.MoveNext();) { edges.Add(((DirectedEdge) i.Current).parentEdge); } return edges; } /// /// Returns 1 if this DirectedEdge has a greater angle with the /// positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. /// Using the obvious algorithm of simply computing the angle is not robust, /// since the angle calculation is susceptible to roundoff. A robust algorithm /// is: /// first compare the quadrants. If the quadrants are different, it it /// trivial to determine which vector is "greater". /// if the vectors lie in the same quadrant, the robust /// RobustCGAlgorithms.ComputeOrientation(Coordinate, Coordinate, Coordinate) /// function can be used to decide the relative orientation of the vectors. /// /// /// public int CompareDirection(DirectedEdge e) { int i = 0; // if the rays are in different quadrants, determining the ordering is trivial if (quadrant > e.Quadrant) { i = 1; } if (quadrant < e.Quadrant) { i = -1; } // vectors are in the same quadrant - check relative orientation of direction vectors // this is > e if it is CCW of e i = CGAlgorithms.ComputeOrientation(e.p0, e.p1, p1); return i; } /// /// Writes a detailed string representation of this DirectedEdge to the given PrintStream. /// /// public void Write(StreamWriter outstream) { string className = GetType().FullName; int lastDotPos = className.LastIndexOf('.'); string name = className.Substring(lastDotPos + 1); outstream.Write(" " + name + ": " + p0 + " - " + p1 + " " + quadrant + ":" + angle); } /// /// /// /// public override string ToString() { return "DirectedEdge: " + p0 + " - " + p1 + " " + quadrant + ":" + angle; } /// /// Returns 1 if this DirectedEdge has a greater angle with the /// positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. /// Using the obvious algorithm of simply computing the angle is not robust, /// since the angle calculation is susceptible to roundoff. A robust algorithm /// is: /// first compare the quadrants. If the quadrants are different, it it /// trivial to determine which vector is "greater". /// if the vectors lie in the same quadrant, the robust /// RobustCGAlgorithms.ComputeOrientation(Coordinate, Coordinate, Coordinate) /// function can be used to decide the relative orientation of the vectors. /// /// /// public int CompareTo(Object obj) { DirectedEdge de = (DirectedEdge) obj; return CompareDirection(de); } /// /// Removes this directed edge from its containing graph. /// internal void Remove() { sym = null; parentEdge = null; } } }