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;
}
}
}