using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Geometries;
namespace GisSharpBlog.NetTopologySuite.Simplify
{
///
/// Simplifies a line (sequence of points) using
/// the standard Douglas-Peucker algorithm.
///
public class DouglasPeuckerLineSimplifier
{
private readonly ICoordinate[] pts;
private bool[] usePt;
private readonly LineSegment seg = new LineSegment();
///
///
///
///
public DouglasPeuckerLineSimplifier(ICoordinate[] pts)
{
this.pts = pts;
}
///
///
///
public double DistanceTolerance { get; set; }
///
///
///
///
///
///
public static ICoordinate[] Simplify(ICoordinate[] pts, double distanceTolerance)
{
DouglasPeuckerLineSimplifier simp = new DouglasPeuckerLineSimplifier(pts);
simp.DistanceTolerance = distanceTolerance;
return simp.Simplify();
}
///
///
///
///
public ICoordinate[] Simplify()
{
usePt = new bool[pts.Length];
for (int i = 0; i < pts.Length; i++)
{
usePt[i] = true;
}
SimplifySection(0, pts.Length - 1);
CoordinateList coordList = new CoordinateList();
for (int i = 0; i < pts.Length; i++)
{
if (usePt[i])
{
coordList.Add(new Coordinate(pts[i]));
}
}
return coordList.ToCoordinateArray();
}
///
///
///
///
///
private void SimplifySection(int i, int j)
{
if ((i + 1) == j)
{
return;
}
seg.P0 = pts[i];
seg.P1 = pts[j];
double maxDistance = -1.0;
int maxIndex = i;
for (int k = i + 1; k < j; k++)
{
double distance = seg.Distance(pts[k]);
if (distance > maxDistance)
{
maxDistance = distance;
maxIndex = k;
}
}
if (maxDistance <= DistanceTolerance)
{
for (int k = i + 1; k < j; k++)
{
usePt[k] = false;
}
}
else
{
SimplifySection(i, maxIndex);
SimplifySection(maxIndex, j);
}
}
}
}