判断点在多边形内算法(凸多边形和复杂多边形)
判断点是否在凸多边形内
- 这个判断比较的简单,只需要按一定顺序遍历三角形顶点,与红点进行连线,按照顺时针或逆时针进行叉乘
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;
}
判断点是否在任意多边形内
判断流程:
- 随便选取多边形边上的一点(comparePoint),并且与判断的点形成射线(originPoint射向comparePoint)
- 判断两个线段是否相交,通过两次叉乘的形式,分别计算是否在不同侧
- 遍历多边形的每个边,计算边与之相交的次数,如果是奇数就在多边形内,否则则在多边形外
// 主函数中判断点是否在任意三角形内
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;
}
特殊情况
- 刚好在点上或者在线上。实际运用时会有误差,但不影响
参考博文
点在多边形内算法——判断一个点是否在一个复杂多边形的内部: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许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步