大致方法可以有3种:
方法1:面积法
判断目标点与多边形的每条边组成的三角形面积和是否等于该多边形,相等则在多边形内部。
方法2:角度法
判断目标点与所有边的夹角和是否为360度,为360度则在多边形内部。
方法3:射线法
从目标点出发引一条射线,看这条射线和多边形所有边的交点数目:
如果有奇数个交点,则说明在内部
如果有偶数个交点,则说明在外部
方法1,2对精度要求高,且计算效率较低,故经常使用射线法;
射线法逻辑:
从点P作y轴正向的射线:
(1)若射线与多边形的交点为奇数,则P在多边形内部;
(2)若射线与多边形的交点为偶数,则P在多边形外部。
特殊情况(若边为(P1,P2)):
(1)如果射线正好穿过P1或者P2点,那么这个交点会被算作2次,处理办法取(P1,P2];
(2)如果边与射线平行,则射线要么与其无交点,要么有无数个,这种情况也直接忽略;(实际上,此类情况存在bug)
(3)如果边与射线垂直,而P的y坐标小于P1,P2的y坐标,则必然相交;
(4)再判断相交之前,先判断P是否在边(P1,P2)的上面,如果在,则直接得出结论:P再多边形内部。
射线法c++实现代码:
struct Point
{
double x;
double y;
double z;
};
bool IsPointInPolygon(const Point& vtPoint, const vector<Point>& vecPoints)
{
bool bResult = false; //判断结果(true;点落在多边形内;false:点未落在多边形内)
int nSize = vecPoints.size();
int pre = nSize - 1;//nSize -1 是多边形的最后一个顶点
for (int cur = 0; cur < nSize; ++cur)
{
//判断点是否在线段的两侧
if ((vecPoints[cur].x < vtPoint.x && vecPoints[pre].x >= vtPoint.x)
|| (vecPoints[pre].x < vtPoint.x && vecPoints[cur].x >= vtPoint.x))
{
//根据两点式方程计算出过点P且平行于X轴的直线与线段的交点,两点式方程:
// y = p1.y + (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x)
double line_p_y = vecPoints[cur].y + (vtPoint.x - vecPoints[cur].x) * (vecPoints[pre].y - vecPoints[cur].y)
/ (vecPoints[pre].x - vecPoints[cur].x);
if (line_p_y > vtPoint.y)
{
bResult = !bResult;
}
else if(line_p_y == vtPoint.y)
{
return true;
}
}
//进行下一线段判断
pre = cur;
}
return bResult;
}