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