 |
|
 |
I implemented this in a pet silverlight project. It works well.
|
|
|
|
 |
|
 |
thank you very much for the douglas-peucker algorithm, i have been working on a project that uses that. i have a question, is there way to calculate an optimum epsilon value within the algorithm? or does it have to be user defined?
|
|
|
|
 |
|
 |
I have found some issues with your implementation of this code. here are the changes that i have made.
Double maxDistance = 0;
Int32 indexFarthest = 0;
if (lastPointIndex - firstPointIndex > 1) {
for (Int32 index = firstPointIndex; index < lastPointIndex; index++)
{
Double distance = PerpendicularDistance(points[firstPointIndex], points[lastPointIndex], points[index]);
if (distance > maxDistance)
{
maxDistance = distance;
indexFarthest = index;
}
}
if (maxDistance > Tolerance && indexFarthest != firstPointIndex) {
pointIndexsToKeep.Add(indexFarthest);
Reduction(points, firstPointIndex, indexFarthest, ref pointIndexsToKeep);
Reduction(points, indexFarthest, lastPointIndex, ref pointIndexsToKeep);
}
}
|
|
|
|
 |
|
 |
Maybe some god modification ?? check that out
tolerance in % of Maximum distance in plot
private static void DouglasPeuckerReduction(List<PointD> points, Int32 firstPoint, Int32 lastPoint, Double tolerance, Double recursionMaxDistance, ref List<Int32> pointIndexsToKeep)
{
Double maxDistance = 0;
Int32 indexFarthest = 0;
List<PointD> indexError = new List<PointD>();
// count error for new points - take lower error index
List<double> distanceList = new List<double>();
for (Int32 index = firstPoint; index < lastPoint; index++)
{
Double distance = PerpendicularDistance(points[firstPoint], points[lastPoint], points[index]);
distanceList.Add(distance);
if (distance > maxDistance)
{
maxDistance = distance;
indexFarthest = index;
}
}
// check if current recursion distance is greater than passed through args
if (maxDistance > recursionMaxDistance) recursionMaxDistance = maxDistance;
// check relevant tolerance to recursionMaxDistance
if (maxDistance > (recursionMaxDistance * tolerance) / 100 && indexFarthest != 0)
{
//Add the largest point that exceeds the tolerance
pointIndexsToKeep.Add(indexFarthest);
DouglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance, recursionMaxDistance, ref pointIndexsToKeep);
DouglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance, recursionMaxDistance, ref pointIndexsToKeep);
}
}
public static List<PointD> DouglasPeuckerReduction(this List<PointD> Points, Double Tolerance)
{
if (Points == null || Points.Count < 3)
return Points;
Int32 firstPoint = 0;
Int32 lastPoint = Points.Count - 1;
List<Int32> pointIndexsToKeep = new List<Int32>();
//Add the first and last index to the keepers
pointIndexsToKeep.Add(firstPoint);
pointIndexsToKeep.Add(lastPoint);
//The first and the last point can not be the same
while (Points[firstPoint].Equals(Points[lastPoint]))
{
lastPoint--;
}
// start Approx with 0 recursionMaxDistance
DouglasPeuckerReduction(Points, firstPoint, lastPoint, Tolerance,0, ref pointIndexsToKeep);
List<PointD> returnPoints = new List<PointD>();
pointIndexsToKeep.Sort();
foreach (Int32 index in pointIndexsToKeep)
{
returnPoints.Add(Points[index]);
}
return returnPoints;modified on Thursday, March 4, 2010 12:32 PM
|
|
|
|
 |
|
 |
I have used this and it does a nice job of reducing a series of lat/longs for display on maps.
A couple of points for people looking to use the code:
I spent ages trying to hunt down a stack over flow error, before realising that the algo was crashing when passed a tolerance of 0. I'd suggest a simple sanity check of the arguments that get passed is a useful addition.
If you want to reduce the number of points to a useful number for display on Google maps or Bing maps (more than 2000 points in a polyline is slow!), it's quite useful to add a little bit of code to work out a tolerance value to get the right reduction. You could do that with either looking at the point count and picking a relevant tolerance, or interatively running the algo with progressively higher tolerances until the number of points returned was small enough.
|
|
|
|
 |
|
 |
This is awesome! I need to simplify some polygons and your work is a great help.
|
|
|
|
 |
|
 |
"Plot Graphic Library" has very useful others functions with LineApproximator and class KeyContainer. Do you planning remake this on C#?
|
|
|
|
 |
|
 |
Double area = Math.Abs(.5 * (Point1.X * Point2.Y + Point2.X * Point.Y + Point.X * Point1.Y - Point2.X * Point1.Y - Point.X * Point2.Y - Point1.X * Point.Y));
Double bottom = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + Math.Pow(Point1.Y - Point2.Y, 2));
Double height = area / bottom * 2;
//it's only for rectangular triangle
//i think must be someting like this:
Double a = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + Math.Pow(Point1.Y - Point2.Y, 2));
Double b = Math.Sqrt(Math.Pow(Point2.X - Point.X, 2) + Math.Pow(Point2.Y - Point.Y, 2));
Double c = Math.Sqrt(Math.Pow(Point.X - Point1.X, 2) + Math.Pow(Point.Y - Point1.Y, 2));
Double p = (a + b + c) / 2;
Double perpendicular = 2 * (Math.Sqrt(p*(p - a)*(p - b)*(p - c))) / a;
|
|
|
|
 |
|
 |
Double area = Math.Abs(.5 * (Point1.X * Point2.Y + Point2.X * Point.Y + Point.X * Point1.Y - Point2.X * Point1.Y - Point.X * Point2.Y - Point1.X * Point.Y));
Double bottom = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + Math.Pow(Point1.Y - Point2.Y, 2));
Double height = area / bottom * 2;
//it's true only for rectangular triangle......
//here must be something like this:
Double a = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + Math.Pow(Point1.Y - Point2.Y, 2));
Double b = Math.Sqrt(Math.Pow(Point2.X - Point.X, 2) + Math.Pow(Point2.Y - Point.Y, 2));
Double c = Math.Sqrt(Math.Pow(Point.X - Point1.X, 2) + Math.Pow(Point.Y - Point1.Y, 2));
Double p = (a + b + c) / 2;
Double perpendicular = 2 * (Math.Sqrt(p*(p - a)*(p - b)*(p - c))) / a;
//i think so... ))
|
|
|
|
 |
|
 |
.... from what one would get by projecting a curve via least squares into the piecewise linear space (of parameter n pieces)?
|
|
|
|
 |
|
 |
I do not know. I was just wanting to port varius c and c++ versions to c#, being that I could not find one.
From what I just read about your post, I would hazard to say that yea thwy would give the same result.
|
|
|
|
 |
|
 |
In this code:
for (Int32 index = firstPoint; index < lastPoint; index++)
{
Double distance = PerpendicularDistance(points[firstPoint], points[lastPoint], points[index]);
if (distance > maxDistance)
{
maxDistance = distance;
indexFarthest = index;
}
index++;
}
Is the second index++ correct? It seems to be skipping half of the points.
Jim
|
|
|
|
 |
|
 |
We caught that in unit testing but I forgot to update this post, Been kinda busy. You are right that should not me there. I will update the code sample.
|
|
|
|
 |
|
 |
How about some background on the algorithm, how it works, why its used...you know...an ARTICLE not just code!
John Conwell
|
|
|
|
 |
|
 |
I could have done that but Jonathan de Halleux did an excellent job of that (Here).
I just wanted to get this out there and searchable by others. If I can not find what I am doing and I can release this type of information I do it.
I placed that link in the original post but it is not so easy to see.
|
|
|
|
 |
|
 |
http://nettopologysuite.googlecode.com/svn/trunk/NetTopologySuite/Simplify/
|
|
|
|
 |
|
 |
That is nice, I can't believe that after performing google search for a c# implementation of the Douglas-Peucker algorith I did not find this.
Thanks for the information.
|
|
|
|
 |