问题
I'm creating a rather dense GraphicsPath by following the MouseMove event. Besides filtering during the movement, is there a routine to simplify the GraphicsPath after the fact?
I also want to implement a 'vector-based flood fill' now and this will create another really dense path.
I guess I will have to step through it and compare the directions of each line until it changes more than a limit or until the changes add up to this limit. Or I could simply erase every other point. Rather crude.
I had hoped for a built-in routine or a standard algorithm; but maybe I have not used the right search words..?
All suggestions appreciated.
回答1:
Reading this question I was reminded of my old post; so I decided to finally implement a simple reduction scheme:
List<PointF> ReducePath(List<PointF> points, float epsilon)
{
if (points.Count < 3) return points;
var newPoints = new List<PointF>();
newPoints.Add(points[0]);
float delta = 0f;
float prevAngle = (float)(Angle(points[0], points[1]) /10f);
for (int i = 1; i < points.Count - 1; i++)
{
float ang = Angle(points[i-1], points[i])/10f;
delta += ang - prevAngle;
prevAngle = ang;
if (Math.Abs(delta) > epsilon)
{
delta = 0;
newPoints.Add(points[i]);
}
}
newPoints.Add(points[ points.Count -1]);
return newPoints;
}
float Angle(PointF p1, PointF p2)
{
if (p1.Y == p2.Y) return p1.X > p2.Y ? 0 : 180;
else if (p1.X == p2.X) return p1.Y > p2.Y ? 90 : 270;
else return (float)Math.Atan((p1.Y - p2.Y)/(p1.X - p2.X));
}
//float Slope(PointF p1, PointF p2)
//{
// if (p1.Y == p2.Y) return 0;
// else if (p1.X == p2.X) return 12345;
// else return (p1.Y - p2.Y)/(p1.X - p2.X);
//}
Here is a result with epsilon values of 1, 0.1 and 0.01:
Note the the GraphicsPath.PathPoints
are read-only, so we have to re-create the path from the new points list!
Update: I have updated the math to work with 1°/10 instead of slopes, replacing the Slope
function with an Angle
function.. This should give more uniform results over various directions..
Update 2:
Kudos to ephraim; I have added the suggested edits to use a proper starting angle..
回答2:
Have you looked into using GraphicsPath.GetBounds ? There's a nice example on that page to.
"The size of the returned bounding rectangle is influenced by the type of end caps, pen width, and pen miter limit, and therefore produces a "loose fit" to the bounded path. The approximate formula is: the initial bounding rectangle is inflated by pen width, and this result is multiplied by the miter limit, plus some additional margin to allow for end caps."
来源:https://stackoverflow.com/questions/22553184/how-can-i-simplify-a-graphicspath