【问题标题】:How to implement Efficient Test for a Point to Be in a Convex Polygon algorithm in C#?如何在 C# 的凸多边形算法中实现一个点的有效测试?
【发布时间】:2025-11-28 21:10:01
【问题描述】:

简单的问题 - 找出一个点是否在凸多边形内。 There is algorithm described yet due to be beeng an in Wolfram language 我出了点问题。这就是我所拥有的:

private static bool PointInside2D(Vector2 point, Vector2 lineStart, Vector2 lineEnd) {
    var v1 = lineStart - point;
    var edge = lineStart - lineEnd;
    return !(edge.x * v1.y - edge.y * v1.x < 0);
}

private static bool PointInsideRect2D(Vector2 point, IList<Vector2> rect) {
    var lastPoint = rect.Count - 1;
    bool? lastResult = null;
    for (var i = 0; i < lastPoint; ++i) {
        if (lastResult == null) {
            lastResult = PointInside2D(point, rect[i], rect[i + 1]);
        }
        else {
            if (lastResult != PointInside2D(point, rect[i], rect[i + 1])) {
                return false;
            }
        }
    }
    return lastResult == PointInside2D( point, rect[lastPoint], rect[0] );
}

很遗憾,它不起作用...我看了一些refrence implementations here 尝试过它们似乎也不起作用..

我使用的测试数据是针对凸的:

 [(262.8, 669.1); (1623.9, 718.2); (200.4, 895.4); (1817.8, 1540.8)]

(288, 815)(1078, 890) 作为测试点。

谁能解释我在该算法/它的实现中出了什么问题?

【问题讨论】:

  • 当你说“我使用的测试数据是凸的”时,你的意思是这些点是多边形中的点吗?

标签: c# algorithm mono unity3d .net-3.5


【解决方案1】:

我相信您的算法可以正常工作。它测试,如果测试点位于多边形所有边缘的同一侧(左侧或右侧)。但它要求多边形声明中的所有点都按顺时针或逆时针顺序排序,这不适用于 [(262.8, 669.1); (1623.9、718.2); (200.4, 895.4); (1817.8, 1540.8)]。

当我更改多边形中点的顺序时,以下程序似乎返回了正确的结果:

    public static void Main()
    {
        Vector2 p1 = new Vector2(288, 815);
        Vector2 p2 = new Vector2(1078, 890);

        //Please notice order of points is changed to clockwise
        IList<Vector2> Polygon = new List<Vector2>(new Vector2[] { new Vector2(262.8f, 669.1f), new Vector2(200.4f, 895.4f), new Vector2(1817.8f, 1540.8f), new Vector2(1623.9f, 718.2f) });

        bool p1Result = PointInsideRect2D(p1, Polygon);
        bool p2Result = PointInsideRect2D(p2, Polygon);
    }

    private static bool PointInside2D(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
    {
        var v1 = lineStart - point;
        var edge = lineStart - lineEnd;
        return !(edge.X * v1.Y - edge.Y * v1.X < 0);
    }

    private static bool PointInsideRect2D(Vector2 point, IList<Vector2> rect)
    {
        var lastPoint = rect.Count - 1;
        bool? lastResult = null;
        for (var i = 0; i < lastPoint; ++i)
        {
            if (lastResult == null)
            {
                lastResult = PointInside2D(point, rect[i], rect[i + 1]);
            }
            else
            {
                if (lastResult != PointInside2D(point, rect[i], rect[i + 1]))
                {
                    return false;
                }
            }
        }
        return lastResult == PointInside2D(point, rect[lastPoint], rect[0]);
    }

【讨论】: