判断点是否在多边形内(含边界)——射线法

基本思想:从一个点向一个方向作射线(默认向右),若穿过的边的数量为1,则点在多边形内,否则不在多边形内。

判断方式如下:

对于一条边,设其端点为坐标分别为\(A(x_A,y_A)\), \(B(x_B, y_B)\)

设需要判断的点为\(P(x_P, y_P)\)

若满足以下两个条件:

1.\(P\)点纵坐标位于\(A,B\)的纵坐标之间

2.\(P\)该点位于直线\(AB\)左侧

则可判断该边必与射线有一个交点

对于条件1,不妨设\(y_A\) >= \(y_B\),显然\(y_B\) <= \(y_P\) <= \(y_A\) (实际代码实现为\(y_B\) < \(y_P\) <= \(y_A\) ,因为存在特殊情形

对于条件2,可以利用几何相关知识求出交点的横坐标:

  • 利用直线AB的斜率(正切值)。设射线与边的交点为\(Q\),对于点\(A\),已知\(A,Q\)之间的纵坐标之差,则可利用纵坐标之差除以斜率求得\(A,Q\)横坐标之差。进而求得\(Q\)点横坐标

即:\(x_Q = x_A + \frac{(y - y_A)(x_A - x_B)}{y_A-y_B}\),

\(x_P < x_A + \frac{(y - y_A)(x_A - x_B)}{y_A-y_B}\)

若保证\(y_A > y_B\),则可得\((x_P - x_A)(y_A-y_B) < (y - y_A)(x_A - x_B)\)

下面考虑一些特殊情况:

1.射线过顶点:若顶点为一条边中纵坐标较大的点则计数,若为纵坐标较小的点则不计数。处理方法为:将条件“\(y_B\) <= \(y_P\) <= \(y_A\)”修改为“\(y_B\) < \(y_P\) <= \(y_A\)

2.射线覆盖一条边:需要计数。但此时必定满足上一条的“射线过顶点”的条件,故此种情况可以不作特殊处理。

3.点在边上。即\(P,Q\)重合,可直接判定出结论。

代码实现:

struct node{
	ll x, y;
}p[MAX];//多边形顶点
int check(){
	int flag = 1;
	for(int i = 1; i <= n; i++){
		ll x1 = p[i].x, y1 = p[i].y, x2 = p[i + 1].x, y2 = p[i + 1].y;
		if(i == n){x2 = p[1].x, y2 = p[1].y;}
		if(y1 < y2){
			swap(x1, x2);
			swap(y1, y2);
		}//保证y1>y2
		if((x - x1) * (y1 - y2) == (x1 - x2) * (y - y1) && y <= y1 && y >= y2) return 0;//点在边上
		if(y > y2 && y <= y1 && (x - x1) * (y1 - y2) < (x1 - x2) * (y - y1))
			flag = !flag;//满足“P纵坐标在A,B纵坐标之间”和“P在AB左侧”两个条件
	}
	return flag;
}

参考:https://blog.csdn.net/WilliamSun0122/article/details/77994526

posted @ 2025-07-21 14:34  LIGHTB  阅读(165)  评论(0)    收藏  举报