using System; using Core.GIS.GeoApi.Geometries; using Core.GIS.NetTopologySuite.Geometries; using Core.GIS.NetTopologySuite.Utilities; namespace Core.GIS.NetTopologySuite.LinearReferencing { /// /// Computes the of the point /// on a linear nearest a given . /// The nearest point is not necessarily unique; this class /// always computes the nearest point closest to the start of the geometry. /// public class LocationIndexOfPoint { private readonly IGeometry linearGeom; /// /// Initializes a new instance of the class. /// /// A linear geometry. public LocationIndexOfPoint(IGeometry linearGeom) { this.linearGeom = linearGeom; } /// /// /// /// /// /// public static LinearLocation IndexOf(IGeometry linearGeom, ICoordinate inputPt) { LocationIndexOfPoint locater = new LocationIndexOfPoint(linearGeom); return locater.IndexOf(inputPt); } /// /// Find the nearest location along a linear {@link Geometry} to a given point. /// /// The coordinate to locate. /// The location of the nearest point. public LinearLocation IndexOf(ICoordinate inputPt) { return IndexOfFromStart(inputPt, null); } /// /// Find the nearest along the linear /// to a given after the specified minimum . /// If possible the location returned will be strictly greater than the . /// If this is not possible, the value returned will equal . /// (An example where this is not possible is when = [end of line] ). /// /// The coordinate to locate. /// The minimum location for the point location. /// The location of the nearest point. public LinearLocation IndexOfAfter(ICoordinate inputPt, LinearLocation minIndex) { if (minIndex == null) { return IndexOf(inputPt); } // sanity check for minLocation at or past end of line LinearLocation endLoc = LinearLocation.GetEndLocation(linearGeom); if (endLoc.CompareTo(minIndex) <= 0) { return endLoc; } LinearLocation closestAfter = IndexOfFromStart(inputPt, minIndex); /* * Return the minDistanceLocation found. * This will not be null, since it was initialized to minLocation */ Assert.IsTrue(closestAfter.CompareTo(minIndex) >= 0, "computed location is before specified minimum location"); return closestAfter; } /// /// /// /// /// /// public static double SegmentFraction(LineSegment seg, ICoordinate inputPt) { double segFrac = seg.ProjectionFactor(inputPt); if (segFrac < 0.0) { segFrac = 0.0; } else if (segFrac > 1.0) { segFrac = 1.0; } return segFrac; } /// /// /// /// /// /// private LinearLocation IndexOfFromStart(ICoordinate inputPt, LinearLocation minIndex) { double minDistance = Double.MaxValue; int minComponentIndex = 0; int minSegmentIndex = 0; double minFrac = -1.0; LineSegment seg = new LineSegment(); foreach (LinearIterator.LinearElement element in new LinearIterator(linearGeom)) { if (!element.IsEndOfLine) { seg.P0 = element.SegmentStart; seg.P1 = element.SegmentEnd; double segDistance = seg.Distance(inputPt); double segFrac = SegmentFraction(seg, inputPt); int candidateComponentIndex = element.ComponentIndex; int candidateSegmentIndex = element.VertexIndex; if (segDistance < minDistance) { // ensure after minLocation, if any if (minIndex == null || minIndex.CompareLocationValues(candidateComponentIndex, candidateSegmentIndex, segFrac) < 0) { // otherwise, save this as new minimum minComponentIndex = candidateComponentIndex; minSegmentIndex = candidateSegmentIndex; minFrac = segFrac; minDistance = segDistance; } } } } LinearLocation loc = new LinearLocation(minComponentIndex, minSegmentIndex, minFrac); return loc; } } }