using System.Collections;
using GeoAPI.Geometries;
namespace GisSharpBlog.NetTopologySuite.Operation.Polygonize
{
///
/// Polygonizes a set of Geometrys which contain linework that
/// represents the edges of a planar graph.
/// Any dimension of Geometry is handled - the constituent linework is extracted
/// to form the edges.
/// The edges must be correctly noded; that is, they must only meet
/// at their endpoints. The Polygonizer will still run on incorrectly noded input
/// but will not form polygons from incorrected noded edges.
/// The Polygonizer reports the follow kinds of errors:
/// Dangles - edges which have one or both ends which are not incident on another edge endpoint
/// Cut Edges - edges which are connected at both ends but which do not form part of polygon
/// Invalid Ring Lines - edges which form rings which are invalid
/// (e.g. the component lines contain a self-intersection).
///
public class Polygonizer
{
///
/// Default factory.
///
private readonly LineStringAdder lineStringAdder;
///
///
///
protected PolygonizeGraph graph;
///
/// Initialized with empty collections, in case nothing is computed
///
protected IList dangles = new ArrayList();
///
///
///
protected IList cutEdges = new ArrayList();
///
///
///
protected IList invalidRingLines = new ArrayList();
///
///
///
protected IList holeList;
///
///
///
protected IList shellList;
///
///
///
protected IList polyList;
///
/// Create a polygonizer with the same {GeometryFactory}
/// as the input Geometrys.
///
public Polygonizer()
{
lineStringAdder = new LineStringAdder(this);
}
///
/// Add a collection of geometries to be polygonized.
/// May be called multiple times.
/// Any dimension of Geometry may be added;
/// the constituent linework will be extracted and used.
///
/// A list of Geometrys with linework to be polygonized.
public void Add(IList geomList)
{
for (var i = geomList.GetEnumerator(); i.MoveNext();)
{
var geometry = (IGeometry) i.Current;
Add(geometry);
}
}
///
/// Add a point to the linework to be polygonized.
/// May be called multiple times.
/// Any dimension of Geometry may be added;
/// the constituent linework will be extracted and used
///
/// A Geometry with linework to be polygonized.
public void Add(IGeometry g)
{
g.Apply(lineStringAdder);
}
///
/// Compute and returns the list of polygons formed by the polygonization.
///
public IList GetPolygons()
{
Polygonize();
return polyList;
}
///
/// Compute and returns the list of dangling lines found during polygonization.
///
public IList GetDangles()
{
Polygonize();
return dangles;
}
///
/// Compute and returns the list of cut edges found during polygonization.
///
public IList GetCutEdges()
{
Polygonize();
return cutEdges;
}
///
/// Compute and returns the list of lines forming invalid rings found during polygonization.
///
public IList GetInvalidRingLines()
{
Polygonize();
return invalidRingLines;
}
///
/// Add a linestring to the graph of polygon edges.
///
/// The LineString to add.
private void Add(ILineString line)
{
// create a new graph using the factory from the input Geometry
if (graph == null)
{
graph = new PolygonizeGraph(line.Factory);
}
graph.AddEdge(line);
}
///
/// Perform the polygonization, if it has not already been carried out.
///
private void Polygonize()
{
// check if already computed
if (polyList != null)
{
return;
}
polyList = new ArrayList();
// if no geometries were supplied it's possible graph could be null
if (graph == null)
{
return;
}
dangles = graph.DeleteDangles();
cutEdges = graph.DeleteCutEdges();
var edgeRingList = graph.GetEdgeRings();
IList validEdgeRingList = new ArrayList();
invalidRingLines = new ArrayList();
FindValidRings(edgeRingList, validEdgeRingList, invalidRingLines);
FindShellsAndHoles(validEdgeRingList);
AssignHolesToShells(holeList, shellList);
polyList = new ArrayList();
for (var i = shellList.GetEnumerator(); i.MoveNext();)
{
var er = (EdgeRing) i.Current;
polyList.Add(er.Polygon);
}
}
private static void FindValidRings(IList edgeRingList, IList validEdgeRingList, IList invalidRingList)
{
for (var i = edgeRingList.GetEnumerator(); i.MoveNext();)
{
var er = (EdgeRing) i.Current;
if (er.IsValid)
{
validEdgeRingList.Add(er);
}
else
{
invalidRingList.Add(er.LineString);
}
}
}
private void FindShellsAndHoles(IList edgeRingList)
{
holeList = new ArrayList();
shellList = new ArrayList();
for (var i = edgeRingList.GetEnumerator(); i.MoveNext();)
{
var er = (EdgeRing) i.Current;
if (er.IsHole)
{
holeList.Add(er);
}
else
{
shellList.Add(er);
}
}
}
private static void AssignHolesToShells(IList holeList, IList shellList)
{
for (var i = holeList.GetEnumerator(); i.MoveNext();)
{
var holeER = (EdgeRing) i.Current;
AssignHoleToShell(holeER, shellList);
}
}
private static void AssignHoleToShell(EdgeRing holeER, IList shellList)
{
var shell = EdgeRing.FindEdgeRingContaining(holeER, shellList);
if (shell != null)
{
shell.AddHole(holeER.Ring);
}
}
///
/// Add every linear element in a point into the polygonizer graph.
///
private class LineStringAdder : IGeometryComponentFilter
{
private readonly Polygonizer container;
///
///
///
///
public LineStringAdder(Polygonizer container)
{
this.container = container;
}
///
///
///
///
public void Filter(IGeometry g)
{
if (g is ILineString)
{
container.Add((ILineString) g);
}
}
}
}
}