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