C# 折线是自交叉的

发布于 2024-10-14 18:30:09 字数 1117 浏览 1 评论 0原文

我有一项任务要随时检查一条折线是否自交叉。此检查必须非常快,因为我的折线很长(大约有 50 个点)并且我有一个超时。这是我写的:

    public bool IsSelfCrossing()
    {
        if (size <= 5)
            return false;
        Point first = body.Points.ElementAt(size - 1);
        Point second = body.Points.ElementAt(size - 2);
        for (int i = 0; i < size - 3; i++)
        {
            if (Intersect(first, second, body.Points.ElementAt(i),
                body.Points.ElementAt(i + 1)))
            {
                return true;
            }
        }
        return false;
    }

    private double Orientation(Point p1, Point p2, Point p3)
    {
        double dx1 = p2.X - p1.X;
        double dy1 = p2.Y - p1.Y;
        double dx2 = p3.X - p1.X;
        double dy2 = p3.Y - p1.Y;
        return dx1 * dy2 - dy1 * dx2;
    }


    bool Intersect(Point p1, Point p2, Point p3, Point p4)
    {
        return
              Orientation(p1, p3, p4) * Orientation(p2, p3, p4) < 0 &&
              Orientation(p3, p1, p2) * Orientation(p4, p1, p2) < 0;
    }

这些方法的问题是有时会失败(这些方法告诉我折线是自交叉的,但事实并非如此)。 您能帮我提供更好的解决方案吗?

I've got a task to check if one polyline is self-crossing at any time. This check must be very fast because my polyline is long (have about 50 points) and I've got a timeout. Here is what I wrote:

    public bool IsSelfCrossing()
    {
        if (size <= 5)
            return false;
        Point first = body.Points.ElementAt(size - 1);
        Point second = body.Points.ElementAt(size - 2);
        for (int i = 0; i < size - 3; i++)
        {
            if (Intersect(first, second, body.Points.ElementAt(i),
                body.Points.ElementAt(i + 1)))
            {
                return true;
            }
        }
        return false;
    }

    private double Orientation(Point p1, Point p2, Point p3)
    {
        double dx1 = p2.X - p1.X;
        double dy1 = p2.Y - p1.Y;
        double dx2 = p3.X - p1.X;
        double dy2 = p3.Y - p1.Y;
        return dx1 * dy2 - dy1 * dx2;
    }


    bool Intersect(Point p1, Point p2, Point p3, Point p4)
    {
        return
              Orientation(p1, p3, p4) * Orientation(p2, p3, p4) < 0 &&
              Orientation(p3, p1, p2) * Orientation(p4, p1, p2) < 0;
    }

The problem of these methods is that sometimes it fails (the methods are telling me that the polyline is self-crossing but it's not).
Can you help me with better solution, please?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(2

爱,才寂寞 2024-10-21 18:30:09

本文描述了用于查找线段集中交点的扫线算法。它的预期运行时间为 O(n + k),其中 n 是路段数,k 是交叉点数。

http://www.cs.tufts.edu/comp/163/notes05 /seg_intersection_handout.pdf

This paper describes sweep-line algorithm for finding intersections in set of line segments. It has expected running time of O(n + k) where n is number of segments and k is number of intersections.

http://www.cs.tufts.edu/comp/163/notes05/seg_intersection_handout.pdf

眼眸 2024-10-21 18:30:09

这是“方向”函数的更好实现,避免了舍入错误的问题。也许这对你的情况有帮助。如果 p0 位于 p1 和 p2 之间的直线上,则返回 0。

    public static int Clockwise (Point p0, Point p1, Point p2)
    {
        const double epsilon = 1e-13;

        double dx1 = p1.X - p0.X;
        double dy1 = p1.Y - p0.Y;
        double dx2 = p2.X - p0.X;
        double dy2 = p2.Y - p0.Y;
        double d = dx1 * dy2 - dy1 * dx2;
        if(d > epsilon) return 1;
        if(d < -epsilon) return -1;
        if((dx1*dx2 < -epsilon) || (dy1*dy2 < -epsilon)) return -1;
        if((dx1*dx1+dy1*dy1) < (dx2*dx2+dy2*dy2)+epsilon) return 1;
        return 0;
    }

这是我的“相交”函数:

    public static bool LineIntersects(Point p1,Point p2, Point q1,Point q2)
    {
        return (Clockwise(p1,p2,q1) * Clockwise(p1,p2,q2) <=0) &&
            (Clockwise(q1,q2,p1) * Clockwise(q1,q2,p2) <=0);
    }

Here is a better implementation of your "Orientation" function, avoiding problems with rounding errors. Perhaps this helps in your case. It returns 0 if p0 is on a straight line between p1 and p2.

    public static int Clockwise (Point p0, Point p1, Point p2)
    {
        const double epsilon = 1e-13;

        double dx1 = p1.X - p0.X;
        double dy1 = p1.Y - p0.Y;
        double dx2 = p2.X - p0.X;
        double dy2 = p2.Y - p0.Y;
        double d = dx1 * dy2 - dy1 * dx2;
        if(d > epsilon) return 1;
        if(d < -epsilon) return -1;
        if((dx1*dx2 < -epsilon) || (dy1*dy2 < -epsilon)) return -1;
        if((dx1*dx1+dy1*dy1) < (dx2*dx2+dy2*dy2)+epsilon) return 1;
        return 0;
    }

And here is my "Intersect" function:

    public static bool LineIntersects(Point p1,Point p2, Point q1,Point q2)
    {
        return (Clockwise(p1,p2,q1) * Clockwise(p1,p2,q2) <=0) &&
            (Clockwise(q1,q2,p1) * Clockwise(q1,q2,p2) <=0);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文