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

发布于 2024-10-20 12:21:05 字数 2705 浏览 2 评论 0原文

如果我有一条闭合路径,我可以使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

辞旧 2024-10-27 12:21:05

为了更快地进行近似,请调用 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.

征﹌骨岁月お 2024-10-27 12:21:05

为什么要近似长度?为什么不计算实际长度?

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文