在 C#/WPF 中获取 PathGeometry(行)的长度
如果我有一条闭合路径,我可以使用 Geometry.GetArea()
来近似形状的面积。这太棒了,节省了我很多时间。但是周围有什么东西可以帮助我找到一条未闭合路径的长度吗?
我目前能想到的最好方法是确保我使用 PathGeometry 并多次调用 GetPointAtFractionLength 方法,获取点并将所有这些点之间的距离。
代码:
public double LengthOfPathGeometry(PathGeometry path, double steps)
{
Point pointOnPath;
Point previousPointOnPath;
Point tangent;
double length = 0;
path.GetPointAtFractionLength(0, out previousPointOnPath, out tangent);
for (double progress = (1 / steps); progress < 1; progress += (1 / steps))
{
path.GetPointAtFractionLength(progress, out pointOnPath, out tangent);
length += Distance(previousPointOnPath, pointOnPath);
previousPointOnPath = pointOnPath;
}
path.GetPointAtFractionLength(1, out pointOnPath, out tangent);
length += Distance(previousPointOnPath, pointOnPath);
return length;
}
public static double Distance(Point p0, Point p1)
{
return Math.Sqrt((Math.Pow((p1.X - p0.X),2) + Math.Pow((p1.Y - p0.Y),2)));
}
用法 (XAML):
<Path Stroke="Beige" StrokeThickness="5" x:Name="Robert">
<Path.Data>
<PathGeometry x:Name="Bob">
<PathGeometry.Figures>
<PathFigure StartPoint="20,10" IsClosed="False" IsFilled="False">
<PathFigure.Segments>
<BezierSegment
Point1="100,50"
Point2="100,200"
Point3="70,200"/>
<LineSegment Point="200,300" />
<ArcSegment
Size="50,50" RotationAngle="45"
IsLargeArc="True" SweepDirection="Counterclockwise"
Point="250,150"/>
<PolyLineSegment Points="450,75 190,100" />
<QuadraticBezierSegment Point1="50,250" Point2="180,70"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
用法(代码):
double length = LengthOfPathGeometry(Bob, 10000);
对于此示例,返回的结果应该大约在:1324.37
这似乎工作正常,但有其缺陷。如果我想要一条非常大的线的更准确的数字,我需要更多的步骤。如果您的步数超过 100000 步,则需要很长时间才能进行近似。在我的测试机器上,每个方法调用需要几秒钟。
有谁知道更好的方法来近似任何形状的线的长度?
If I have a closed path, I can use Geometry.GetArea()
to approximate the area of my shape. This is great and saves me a lot of time. But is there anything around that will help me find the length of a unclosed path?
The best I've been able to come up with for now is to make sure I am using PathGeometry
and call the GetPointAtFractionLength
method multiple times, get the points and add up the distance between all those points.
Code:
public double LengthOfPathGeometry(PathGeometry path, double steps)
{
Point pointOnPath;
Point previousPointOnPath;
Point tangent;
double length = 0;
path.GetPointAtFractionLength(0, out previousPointOnPath, out tangent);
for (double progress = (1 / steps); progress < 1; progress += (1 / steps))
{
path.GetPointAtFractionLength(progress, out pointOnPath, out tangent);
length += Distance(previousPointOnPath, pointOnPath);
previousPointOnPath = pointOnPath;
}
path.GetPointAtFractionLength(1, out pointOnPath, out tangent);
length += Distance(previousPointOnPath, pointOnPath);
return length;
}
public static double Distance(Point p0, Point p1)
{
return Math.Sqrt((Math.Pow((p1.X - p0.X),2) + Math.Pow((p1.Y - p0.Y),2)));
}
Usage (XAML):
<Path Stroke="Beige" StrokeThickness="5" x:Name="Robert">
<Path.Data>
<PathGeometry x:Name="Bob">
<PathGeometry.Figures>
<PathFigure StartPoint="20,10" IsClosed="False" IsFilled="False">
<PathFigure.Segments>
<BezierSegment
Point1="100,50"
Point2="100,200"
Point3="70,200"/>
<LineSegment Point="200,300" />
<ArcSegment
Size="50,50" RotationAngle="45"
IsLargeArc="True" SweepDirection="Counterclockwise"
Point="250,150"/>
<PolyLineSegment Points="450,75 190,100" />
<QuadraticBezierSegment Point1="50,250" Point2="180,70"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
Usage (Code):
double length = LengthOfPathGeometry(Bob, 10000);
For this example the result returned should be somewhere around: 1324.37
This seems to work out fine, but has its flaws. If I want a more accurate number for a very large line, I need more steps. And if you get above 100000 steps, you run into a long time to approximate. A couple of seconds per method call on my test machine.
Does anyone know a better way to approximate a length of any shape of line?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了更快地进行近似,请调用 GetFlattenedPathGeometry,它将您的路径转换为一系列直线,并将直线长度相加。
这与您现有的代码几乎做同样的事情,除了它更智能地选择线段(例如,贝塞尔曲线分割成的线段数量取决于曲率),因此您的点将减少几个数量级。相同的精度。
For a quicker approximation call GetFlattenedPathGeometry, which will convert your path to a series of straight lines, and add up the line lengths.
This is pretty much doing the same thing as your existing code except that it selects the line segments more intelligently (e.g. the number of segments a bezier curve is split into depends on the curvature) so you'll have orders of magnitude fewer points for the same accuracy.
为什么要近似长度?为什么不计算实际长度?
PathGeometry 包含 PathFigures 的集合。每个 PathFigure 都包含 PathSegments 的集合(目前共有7种)。您可以迭代所有内容并计算实际长度并将它们相加。
我认为这是一项值得做的一次性投资。你需要温习一些几何知识,但谷歌现在让一切变得简单。
Why do you want to approximate the length? Why not calculate the actual length?
A PathGeometry contains a collection of PathFigures. Each PathFigure contains a collection of PathSegments(7 types in total at the moment). You can iterate over everything and calculate the actual lengths and add them up.
Its a one time investment worth doing I think. You'll need to brush up a little geometry but Google makes everything easy these days.