一个拥有3A游戏梦的不正经大学生|

shadow_lr

园龄:4年10个月粉丝:41关注:1

判断点在多边形内算法(凸多边形和复杂多边形)

判断点是否在凸多边形内

  • 这个判断比较的简单,只需要按一定顺序遍历三角形顶点,与红点进行连线,按照顺时针或逆时针进行叉乘
	bool PointIsInPolygon()
    {
        int j = points.Length - 1;

        bool oddNodes = false;

        for (int i = 0; i < points.Length; ++i)
        {
            // y1 < y && y >= y2
            // y2 < y && y >= y1
            float z = testPoint.position.z;
            float z1 = points[i].position.z;
            float z2 = points[j].position.z;

            float x = testPoint.position.x;
            float x1 = points[i].position.x;
            float x2 = points[j].position.x;

            // 向量PC
            float difXPC = x2 - x;
            float difZPC = z2 - z;

            // 向量PA
            float difXPA = x1 - x;
            float difZPA = z1 - z;

            float crossResult = difXPC * difZPA - difZPC * difXPA;

            if (i == 0)
            {
                oddNodes = (crossResult >= 0) ? true : false;
            }

            bool cross = (crossResult >= 0) ? true : false;

            if (cross != oddNodes)
            {
                return false;
            }
            j = i;
        }

        return true;
    }

image-20210509214230818

image-20210509214230818

判断点是否在任意多边形内

判断流程:

  • 随便选取多边形边上的一点(comparePoint),并且与判断的点形成射线(originPoint射向comparePoint)
  • 判断两个线段是否相交,通过两次叉乘的形式,分别计算是否在不同侧

image-20210510103528757

  • 遍历多边形的每个边,计算边与之相交的次数,如果是奇数就在多边形内,否则则在多边形外
	// 主函数中判断点是否在任意三角形内
	if (CheckPointIsInPolygon())
    {
		Debug.Log("Point is in Polygon");
		drawColor = Color.red;
	}
	else
	{
		drawColor = Color.white;
	}    
	bool CheckPointIsInPolygon()
    {
        if (points.Length < 3)
        {
            return false;
        }

        float raycastLen = 10000f;
        Vector3 comparePoint = (points[0].position + points[1].position) * 0.5f;
        // 此处一定要这样写表示射线,不然comparePoint在边上计算会有误差
        comparePoint += (comparePoint - testPoint.position).normalized * raycastLen;
        Gizmos.DrawLine(testPoint.position, comparePoint);

        int count = 0;

        for (int i = 0; i < points.Length; ++i)
        {
            Vector3 a = points[i].position;
            Vector3 b = points[(i + 1) % points.Length].position;
            
            // 循环判断每条边与testPoint射向comparePoint的射线是否有交点
            if (IsIntersection(a, b, testPoint.position, comparePoint))
            {
                ++count;
            }
        }

        if (count % 2 == 1) return true;

        return false;
    }

    bool IsIntersection(Vector3 a, Vector3 b, Vector3 originPoint, Vector3 comparePoint)
    {
            // 判断是否同向
            float crossA = Mathf.Sign(Vector3.Cross(comparePoint - originPoint, a - originPoint).y);
            float crossB = Mathf.Sign(Vector3.Cross(comparePoint - originPoint, b - originPoint).y);

            if (Mathf.Approximately(crossA, crossB)) return false;

            float crossC = Mathf.Sign(Vector3.Cross(b - a, originPoint - a).y);
            float crossD = Mathf.Sign(Vector3.Cross(b - a, comparePoint - a).y);

            if (Mathf.Approximately(crossC, crossD)) return false;

            return true;
    }

特殊情况

  • 刚好在点上或者在线上。实际运用时会有误差,但不影响

2021-05-10-10-38-55

参考博文

点在多边形内算法——判断一个点是否在一个复杂多边形的内部:https://blog.csdn.net/hjh2005/article/details/9246967

2D空间中求一点是否在多边形内:https://www.cnblogs.com/hont/p/6105997.html)https://www.cnblogs.com/dabiaoge/p/4491540.html

本文作者:shadow_lr

本文链接:https://www.cnblogs.com/shadow-lr/p/JudgePointIsInPolygon.html

版权声明:本作品采用shadow-lr许可协议进行许可。

posted @   shadow_lr  阅读(2369)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起