using System.Collections; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; using GisSharpBlog.NetTopologySuite.GeometriesGraph; namespace GisSharpBlog.NetTopologySuite.Algorithm { /// /// Computes the topological relationship (Location) of a single point to a Geometry. /// The algorithm obeys the SFS boundaryDetermination rule to correctly determine /// whether the point lies on the boundary or not. /// Note that instances of this class are not reentrant. /// public class PointLocator { private bool isIn; // true if the point lies in or on any Geometry element private int numBoundaries; // the number of sub-elements whose boundaries the point lies in /// /// Initializes a new instance of the class. /// public PointLocator() { } /// /// Convenience method to test a point for intersection with a Geometry /// /// The coordinate to test. /// The Geometry to test. /// true if the point is in the interior or boundary of the Geometry. public bool Intersects(ICoordinate p, IGeometry geom) { return Locate(p, geom) != Locations.Exterior; } /// /// Computes the topological relationship ({Location}) of a single point to a Geometry. /// It handles both single-element and multi-element Geometries. /// The algorithm for multi-part Geometries takes into account the boundaryDetermination rule. /// /// The Location of the point relative to the input Geometry. public Locations Locate(ICoordinate p, IGeometry geom) { if (geom.IsEmpty) return Locations.Exterior; if (geom is ILineString) return Locate(p, (ILineString) geom); else if (geom is IPolygon) return Locate(p, (IPolygon) geom); isIn = false; numBoundaries = 0; ComputeLocation(p, geom); if(GeometryGraph.IsInBoundary(numBoundaries)) return Locations.Boundary; if(numBoundaries > 0 || isIn) return Locations.Interior; return Locations.Exterior; } /// /// /// /// /// private void ComputeLocation(ICoordinate p, IGeometry geom) { if (geom is ILineString) UpdateLocationInfo(Locate(p, (ILineString) geom)); else if(geom is Polygon) UpdateLocationInfo(Locate(p, (IPolygon) geom)); else if(geom is IMultiLineString) { IMultiLineString ml = (IMultiLineString) geom; foreach (ILineString l in ml.Geometries) UpdateLocationInfo(Locate(p, l)); } else if(geom is IMultiPolygon) { IMultiPolygon mpoly = (IMultiPolygon) geom; foreach (IPolygon poly in mpoly.Geometries) UpdateLocationInfo(Locate(p, poly)); } else if (geom is IGeometryCollection) { IEnumerator geomi = new GeometryCollectionEnumerator((IGeometryCollection) geom); while(geomi.MoveNext()) { IGeometry g2 = (IGeometry) geomi.Current; if (g2 != geom) ComputeLocation(p, g2); } } } /// /// /// /// private void UpdateLocationInfo(Locations loc) { if(loc == Locations.Interior) isIn = true; if(loc == Locations.Boundary) numBoundaries++; } /// /// /// /// /// /// private Locations Locate(ICoordinate p, ILineString l) { ICoordinate[] pt = l.Coordinates; if(!l.IsClosed) if(p.Equals(pt[0]) || p.Equals(pt[pt.Length - 1])) return Locations.Boundary; if (CGAlgorithms.IsOnLine(p, pt)) return Locations.Interior; return Locations.Exterior; } /// /// /// /// /// /// private Locations LocateInPolygonRing(ICoordinate p, ILinearRing ring) { // can this test be folded into IsPointInRing? if (CGAlgorithms.IsOnLine(p, ring.Coordinates)) return Locations.Boundary; if (CGAlgorithms.IsPointInRing(p, ring.Coordinates)) return Locations.Interior; return Locations.Exterior; } /// /// /// /// /// /// private Locations Locate(ICoordinate p, IPolygon poly) { if (poly.IsEmpty) return Locations.Exterior; ILinearRing shell = poly.Shell; Locations shellLoc = LocateInPolygonRing(p, shell); if (shellLoc == Locations.Exterior) return Locations.Exterior; if (shellLoc == Locations.Boundary) return Locations.Boundary; // now test if the point lies in or on the holes foreach (ILinearRing hole in poly.InteriorRings) { Locations holeLoc = LocateInPolygonRing(p, hole); if (holeLoc == Locations.Interior) return Locations.Exterior; if (holeLoc == Locations.Boundary) return Locations.Boundary; } return Locations.Interior; } } }