using System.Collections;
using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Algorithm;
using GisSharpBlog.NetTopologySuite.GeometriesGraph;
using GisSharpBlog.NetTopologySuite.GeometriesGraph.Index;
using Wintellect.PowerCollections;
namespace GisSharpBlog.NetTopologySuite.Operation
{
///
/// Tests whether a Geometry is simple.
/// Only Geometrys whose definition allows them
/// to be simple or non-simple are tested. (E.g. Polygons must be simple
/// by definition, so no test is provided. To test whether a given Polygon is valid,
/// use Geometry.IsValid)
///
public class IsSimpleOp
{
///
///
///
public IsSimpleOp() {}
///
///
///
///
///
public bool IsSimple(ILineString geom)
{
return IsSimpleLinearGeometry(geom);
}
///
///
///
///
///
public bool IsSimple(IMultiLineString geom)
{
return IsSimpleLinearGeometry(geom);
}
///
/// A MultiPoint is simple if it has no repeated points.
///
public bool IsSimple(IMultiPoint mp)
{
if (mp.IsEmpty)
{
return true;
}
Set points = new Set();
for (int i = 0; i < mp.NumGeometries; i++)
{
IPoint pt = (IPoint) mp.GetGeometryN(i);
ICoordinate p = pt.Coordinate;
if (points.Contains(p))
{
return false;
}
points.Add(p);
}
return true;
}
///
///
///
///
///
private bool IsSimpleLinearGeometry(IGeometry geom)
{
if (geom.IsEmpty)
{
return true;
}
GeometryGraph graph = new GeometryGraph(0, geom);
LineIntersector li = new RobustLineIntersector();
SegmentIntersector si = graph.ComputeSelfNodes(li, true);
// if no self-intersection, must be simple
if (!si.HasIntersection)
{
return true;
}
if (si.HasProperIntersection)
{
return false;
}
if (HasNonEndpointIntersection(graph))
{
return false;
}
if (HasClosedEndpointIntersection(graph))
{
return false;
}
return true;
}
///
/// For all edges, check if there are any intersections which are NOT at an endpoint.
/// The Geometry is not simple if there are intersections not at endpoints.
///
///
private bool HasNonEndpointIntersection(GeometryGraph graph)
{
for (IEnumerator i = graph.GetEdgeEnumerator(); i.MoveNext();)
{
Edge e = (Edge) i.Current;
int maxSegmentIndex = e.MaximumSegmentIndex;
for (IEnumerator eiIt = e.EdgeIntersectionList.GetEnumerator(); eiIt.MoveNext();)
{
EdgeIntersection ei = (EdgeIntersection) eiIt.Current;
if (!ei.IsEndPoint(maxSegmentIndex))
{
return true;
}
}
}
return false;
}
///
/// Test that no edge intersection is the
/// endpoint of a closed line. To check this we compute the
/// degree of each endpoint. The degree of endpoints of closed lines
/// must be exactly 2.
///
///
private bool HasClosedEndpointIntersection(GeometryGraph graph)
{
IDictionary endPoints = new OrderedDictionary();
for (IEnumerator i = graph.GetEdgeEnumerator(); i.MoveNext();)
{
Edge e = (Edge) i.Current;
bool isClosed = e.IsClosed;
ICoordinate p0 = e.GetCoordinate(0);
AddEndpoint(endPoints, p0, isClosed);
ICoordinate p1 = e.GetCoordinate(e.NumPoints - 1);
AddEndpoint(endPoints, p1, isClosed);
}
for (IEnumerator i = endPoints.Values.GetEnumerator(); i.MoveNext();)
{
EndpointInfo eiInfo = (EndpointInfo) i.Current;
if (eiInfo.IsClosed && eiInfo.Degree != 2)
{
return true;
}
}
return false;
}
///
/// Add an endpoint to the map, creating an entry for it if none exists.
///
///
///
///
private void AddEndpoint(IDictionary endPoints, ICoordinate p, bool isClosed)
{
EndpointInfo eiInfo = (EndpointInfo) endPoints[p];
if (eiInfo == null)
{
eiInfo = new EndpointInfo(p);
endPoints.Add(p, eiInfo);
}
eiInfo.AddEndpoint(isClosed);
}
///
///
///
public class EndpointInfo
{
private bool isClosed = false;
///
///
///
///
public EndpointInfo(ICoordinate pt)
{
this.Point = pt;
isClosed = false;
Degree = 0;
}
///
///
///
public ICoordinate Point { get; set; }
///
///
///
public bool IsClosed
{
get
{
return isClosed;
}
set
{
isClosed = value;
}
}
///
///
///
public int Degree { get; set; }
///
///
///
///
public void AddEndpoint(bool isClosed)
{
Degree++;
IsClosed |= isClosed;
}
}
}
}