【问题标题】:Point in Polygon including edge cases with margin in c#多边形中的点,包括 c# 中带有边距的边缘情况
【发布时间】:2019-08-22 01:44:47
【问题描述】:

我正在使用 Unity3D,我有一个多边形(Vector2 数组)以及要检查的点。 在过去的几天里,我一直在寻找解决方案,包括 pnpoly 和其他算法。问题是我的误差高达 0.001f,因为我在使用 TransformPoint 之后立即通过与四元数相乘将 3D 面投影到 2D 平面上(以获取网格顶点的世界位置)。

我对多边形一无所知,因为它们是由许多网格三角形组成的——它们可以有任何形状。

我如何处理这种极端的不准确并找到多边形边界内或边界上的所有点?

    public static bool IsInsidePolygon(Vector2[] vertices, Vector2 checkPoint)
    {
        float[] vertX = new float[vertices.Length];
        float[] vertY = new float[vertices.Length];
        for (int i = 0; i < vertices.Length; i++)
        {
            vertX[i] = vertices[i].x;
            vertY[i] = vertices[i].y;
        }

        return IsInsidePolygon(vertices.Length, vertX, vertY, checkPoint.x, checkPoint.y);
    }

    public static bool IsInsidePolygon3(int nvert, float[] vertx, float[] verty, float testx, float testy)
    {
        int i, j = 0;
        bool c = false;
        for (i = 0, j = nvert - 1; i < nvert; j = i++)
        {
            if (((verty[i] > testy) != (verty[j] > testy)) &&
         (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
                c = !c;
        }
        return c;
    }

【问题讨论】:

  • 除了边缘情况之外,您的代码现在还能工作吗?
  • 是的。除了多边形边缘和角落上的点(或稍微偏离 0.001f)之外,一切都很好。
  • 如果您的点最初有错误,则无法确定它们是否在多边形中
  • 我的观点没有错误 - 我一步一步地显示它们(通过使用协程,Debug.Break() 和 Debug.DrawLine()),它们被正确地投影到地板上。
  • 但是你提到投影后二维点有~0.001的误差?

标签: c# unity3d polygon


【解决方案1】:

解决方案是找到到多边形的最近距离,如果距离在边距内,则返回 true,这是整个代码:

'''

public static float DistancePointLine2D(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
{
    return (ProjectPointLine2D(point, lineStart, lineEnd) - point).magnitude;
}
public static Vector2 ProjectPointLine2D(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
{
    Vector2 rhs = point - lineStart;
    Vector2 vector2 = lineEnd - lineStart;
    float magnitude = vector2.magnitude;
    Vector2 lhs = vector2;
    if (magnitude > 1E-06f)
    {
        lhs = (Vector2)(lhs / magnitude);
    }
    float num2 = Mathf.Clamp(Vector2.Dot(lhs, rhs), 0f, magnitude);
    return (lineStart + ((Vector2)(lhs * num2)));
}


public static float ClosestDistanceToPolygon(Vector2[] verts, Vector2 point)
{
    int nvert = verts.Length;
    int i, j = 0;
    float minDistance = Mathf.Infinity;
    for (i = 0, j = nvert - 1; i < nvert; j = i++)
    {
        float distance = DistancePointLine2D(point, verts[i], verts[j]);
        minDistance = Mathf.Min(minDistance, distance);
    }

    return minDistance;
}

public static bool IsInsidePolygon(Vector2[] vertices, Vector2 checkPoint, float margin = 0.01f)
{
    if(ClosestDistanceToPolygon(vertices, checkPoint) < margin)
    {
        return true;
    }

    float[] vertX = new float[vertices.Length];
    float[] vertY = new float[vertices.Length];
    for (int i = 0; i < vertices.Length; i++)
    {
        vertX[i] = vertices[i].x;
        vertY[i] = vertices[i].y;
    }

    return IsInsidePolygon(vertices.Length, vertX, vertY, checkPoint.x, checkPoint.y);
}

public static bool IsInsidePolygon(int nvert, float[] vertx, float[] verty, float testx, float testy)
{
    bool c = false;
    int i, j = 0;
    for (i = 0, j = nvert - 1; i < nvert; j = i++)
    {
        if ((((verty[i] <= testy) && (testy < verty[j])) ||

             ((verty[j] <= testy) && (testy < verty[i]))) &&

            (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
            c = !c;
    }
    return c;
}

'''

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2015-12-13
    • 2014-08-21
    • 2010-10-28
    • 2012-12-25
    • 1970-01-01
    相关资源
    最近更新 更多