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