php 判断点在多边形内,判断点是否在多边形内 (附C实现代码)

如何判断一个点是否在多边形内部?

(1)面积和判别法:判断目标点与多边形的每条边组成的三角形面积和是否等于该多边形,相等则在多边形内部。

(2)夹角和判别法:判断目标点与所有边的夹角和是否为360度,为360度则在多边形内部。

(3)引射线法:从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。

本文采用引射线法。

原理:从测试点引一条垂直于y轴的射线,若射线与多边形交点为奇数时,则测试点在多边形内,若为偶数点,则在多边形外。测试点在多边形的边上时则需特殊考虑。

f052a1d9aaeb9f303ed9240255aec5ba.png

如图所示 交点为2点,点在图形外。

算法图解:

0116a4761e433802010a67e3a6dbe769.png

参考代码:

1 /************************************************************2 ** 函数名称: InOrOutPolygon3 ** 功能描述: 判断点在多边形内外4 ** 输入参数: nvert 顶点个数 vertx 多边形顶点x坐标数组 verty 多边形顶点y坐标数组5 testx 被判断点位置x坐标 testy 被判断点位置y坐标6 ** 输出参数: NULL7 ** 返 回 值: 0:外 1:内8 ** 作 者:9 ** 日 期: 2018年3月21日10 **************************************************************/

11 int InOrOutPolygon(int nvert, float *vertx, float *verty, float testx, floattesty)12 {13 int i, j, crossings = 0;14 for (i = 0, j = nvert-1; i < nvert; j = i++)15 {16 //点在两个x之间 且以点垂直y轴向上做射线

17 if(((vertx[i]>testx) != (vertx[j]>testx))18 && (testx > (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) +vertx[i]))19 crossings++;20 }21 return (crossings % 2 != 0);22 }

代码原理:

引射线法是做一条射线,判断与多边形每条边的交点。

那么我们即可认为做一条方向向上且与y轴垂直的射线。

所以只要测试点在边的下方且横坐标在边两顶点之间,即有一个交点,否则无交点。

那么我们只需要通过2点((x1,y1)(x2,y2))求出边的直线方程,将测试点(x,y)带入边的直线方程,测试点满足 x1

若点在边界则测试点满足 x1

参考资料:http://www.cnblogs.com/luxiaoxun/p/3722358.html

2018.3.30 更新

以上方法针对普通情况可适用,但是针对某些特殊情况,可能出现判断错误的情况

1.若射线引出的点直接穿过顶点。若按上述算法进行计算,则穿过点的数量为0 得出点在多边形外。

4bef7e89f85b086e9c1f42b757bf3f38.png

所以我们计算时,应当取半开半闭区间,即将顶点算入线中,但是每条线只计算其一边的顶点(若为闭区间,则会重复计算顶点)

2.若射线穿过定点

fb021b2ded91a32f5c035b976d506e17.png

使用1所述方法可以解决。

参考代码:

int InOrOutPolygon(int nvert, float *vertx, float *verty, float testx, floattesty)

{//int i, j, crossings = 0;

crossings = 0;for (i = 0, j = nvert-1; i < nvert; j = i++)

{//点在两个x之间 且以点垂直y轴向上做射线

x1[i] =vertx[i];

x1[j]=vertx[j];

y1[i]=verty[i];

y1[j]=verty[j];if((((vertx[i] < testx) && (vertx[j] >= testx))||((vertx[i] >= testx) && (vertx[j] (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) +vertx[i]))

crossings++;

}return (crossings % 2 != 0);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值