在C# / WPF中获取PathGeometry(线条)的长度

4
如果我有一个封闭路径,我可以使用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步,你会遇到近似的漫长时间。在我的测试机器上,每个方法调用需要几秒钟。

有没有人知道一种更好的方法来近似计算任何形状线的长度?


请查看此处的解决方案:https://dev59.com/JHzaa4cB1Zd3GeqPPmln#52645819 - google dev
2个回答

7

为了更快的近似值,调用GetFlattenedPathGeometry函数,它将把你的路径转换成一系列直线,并计算这些直线长度的总和。

这实际上和你现有的代码做的事情差不多,只是它更加智能地选择线段(例如,贝塞尔曲线分割成的线段数量取决于曲率),所以你会得到同样精确度下数量级更少的点。


2
为什么您想要近似长度?为什么不计算实际长度呢?
一个PathGeometry包含PathFigures的集合。每个PathFigure都包含PathSegments的集合(目前共有7种类型)。您可以遍历所有内容并计算实际长度,然后将它们相加。
我认为这是一次值得做的一次性投资。您需要稍微了解一些几何知识,但现在谷歌使一切变得容易了。

如果我需要更准确的数字,这可能是未来前进的方式。我一直在寻找最简单的方法来获取长度。贝塞尔曲线只能被近似,但我相信有比我的蛮力更准确和高效的方法来得到这个近似值。 - Ross Graeber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接