using System.Collections; using System.IO; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Algorithm; namespace GisSharpBlog.NetTopologySuite.GeometriesGraph { /// /// The computation of the IntersectionMatrix relies on the use of a structure /// called a "topology graph". The topology graph contains nodes and edges /// corresponding to the nodes and line segments of a Geometry. Each /// node and edge in the graph is labeled with its topological location relative to /// the source point. /// Note that there is no requirement that points of self-intersection be a vertex. /// Thus to obtain a correct topology graph, Geometrys must be /// self-noded before constructing their graphs. /// Two fundamental operations are supported by topology graphs: /// Computing the intersections between all the edges and nodes of a single graph /// Computing the intersections between the edges and nodes of two different graphs /// public class PlanarGraph { /// /// /// protected IList edges = new ArrayList(); /// /// /// protected NodeMap nodes = null; /// /// /// protected IList edgeEndList = new ArrayList(); /// /// /// /// public PlanarGraph(NodeFactory nodeFact) { nodes = new NodeMap(nodeFact); } /// /// /// public PlanarGraph() { nodes = new NodeMap(new NodeFactory()); } /// /// /// public IList EdgeEnds { get { return edgeEndList; } } /// /// /// public IList Nodes { get { return new ArrayList(nodes.Values); } } /// /// For nodes in the Collection, link the DirectedEdges at the node that are in the result. /// This allows clients to link only a subset of nodes in the graph, for /// efficiency (because they know that only a subset is of interest). /// /// public static void LinkResultDirectedEdges(IList nodes) { for (IEnumerator nodeit = nodes.GetEnumerator(); nodeit.MoveNext();) { Node node = (Node) nodeit.Current; ((DirectedEdgeStar) node.Edges).LinkResultDirectedEdges(); } } /// /// /// /// public IEnumerator GetEdgeEnumerator() { return edges.GetEnumerator(); } /// /// /// /// /// /// public bool IsBoundaryNode(int geomIndex, ICoordinate coord) { Node node = nodes.Find(coord); if (node == null) { return false; } Label label = node.Label; if (label != null && label.GetLocation(geomIndex) == Locations.Boundary) { return true; } return false; } /// /// /// /// public void Add(EdgeEnd e) { nodes.Add(e); edgeEndList.Add(e); } /// /// /// /// public IEnumerator GetNodeEnumerator() { return nodes.GetEnumerator(); } /// /// /// /// /// public Node AddNode(Node node) { return nodes.AddNode(node); } /// /// /// /// /// public Node AddNode(ICoordinate coord) { return nodes.AddNode(coord); } /// /// The node if found; null otherwise /// /// public Node Find(ICoordinate coord) { return nodes.Find(coord); } /// /// Add a set of edges to the graph. For each edge two DirectedEdges /// will be created. DirectedEdges are NOT linked by this method. /// /// public void AddEdges(IList edgesToAdd) { // create all the nodes for the edges for (IEnumerator it = edgesToAdd.GetEnumerator(); it.MoveNext();) { Edge e = (Edge) it.Current; edges.Add(e); DirectedEdge de1 = new DirectedEdge(e, true); DirectedEdge de2 = new DirectedEdge(e, false); de1.Sym = de2; de2.Sym = de1; Add(de1); Add(de2); } } /// /// Link the DirectedEdges at the nodes of the graph. /// This allows clients to link only a subset of nodes in the graph, for /// efficiency (because they know that only a subset is of interest). /// public void LinkResultDirectedEdges() { for (IEnumerator nodeit = nodes.GetEnumerator(); nodeit.MoveNext();) { Node node = (Node) nodeit.Current; ((DirectedEdgeStar) node.Edges).LinkResultDirectedEdges(); } } /// /// Link the DirectedEdges at the nodes of the graph. /// This allows clients to link only a subset of nodes in the graph, for /// efficiency (because they know that only a subset is of interest). /// public void LinkAllDirectedEdges() { for (IEnumerator nodeit = nodes.GetEnumerator(); nodeit.MoveNext();) { Node node = (Node) nodeit.Current; ((DirectedEdgeStar) node.Edges).LinkAllDirectedEdges(); } } /// /// Returns the EdgeEnd which has edge e as its base edge /// (MD 18 Feb 2002 - this should return a pair of edges). /// /// /// The edge, if found null if the edge was not found. public EdgeEnd FindEdgeEnd(Edge e) { for (IEnumerator i = EdgeEnds.GetEnumerator(); i.MoveNext();) { EdgeEnd ee = (EdgeEnd) i.Current; if (ee.Edge == e) { return ee; } } return null; } /// /// Returns the edge whose first two coordinates are p0 and p1. /// /// /// /// The edge, if found null if the edge was not found. public Edge FindEdge(ICoordinate p0, ICoordinate p1) { for (int i = 0; i < edges.Count; i++) { Edge e = (Edge) edges[i]; ICoordinate[] eCoord = e.Coordinates; if (p0.Equals(eCoord[0]) && p1.Equals(eCoord[1])) { return e; } } return null; } /// /// Returns the edge which starts at p0 and whose first segment is /// parallel to p1. /// /// /// /// The edge, if found null if the edge was not found. public Edge FindEdgeInSameDirection(ICoordinate p0, ICoordinate p1) { for (int i = 0; i < edges.Count; i++) { Edge e = (Edge) edges[i]; ICoordinate[] eCoord = e.Coordinates; if (MatchInSameDirection(p0, p1, eCoord[0], eCoord[1])) { return e; } if (MatchInSameDirection(p0, p1, eCoord[eCoord.Length - 1], eCoord[eCoord.Length - 2])) { return e; } } return null; } /// /// /// /// public void WriteEdges(StreamWriter outstream) { outstream.WriteLine("Edges:"); for (int i = 0; i < edges.Count; i++) { outstream.WriteLine("edge " + i + ":"); Edge e = (Edge) edges[i]; e.Write(outstream); e.EdgeIntersectionList.Write(outstream); } } /// /// /// /// protected void InsertEdge(Edge e) { edges.Add(e); } /// /// The coordinate pairs match if they define line segments lying in the same direction. /// E.g. the segments are parallel and in the same quadrant /// (as opposed to parallel and opposite!). /// /// /// /// /// private bool MatchInSameDirection(ICoordinate p0, ICoordinate p1, ICoordinate ep0, ICoordinate ep1) { if (!p0.Equals(ep0)) { return false; } if (CGAlgorithms.ComputeOrientation(p0, p1, ep1) == CGAlgorithms.Collinear && QuadrantOp.Quadrant(p0, p1) == QuadrantOp.Quadrant(ep0, ep1)) { return true; } return false; } } }