点是否在多边形内,是一个很经典的问题,方法也很成熟,但是去github或网上找的资料感觉有些乱,我在他们基础上做了整理,点是否在多边形内的判别方法有多种,其算法具体原理在此不赘述,有比较好的博客,我一并放置在此。我要做的是使用射线法来判断点是否在多边形内部并使用C语言实施了其判定过程。
射线判别法原理如下:
从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。
射线判别法对点在多边形边上的判断时不可靠的,这个需要附加一个点在直线上的判断来完善。点在线段上的判断也是有方法的,原理在此也不赘述。
比较好的参考博客如下:
1、https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
PNPOLY - Point Inclusion in Polygon Test W. Randolph Franklin (WRF)
这篇博客应该是好多使用下面这段代码:
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
最原始的出处吧,这段代码结构很精简,初看时有些懵,仔细一分析,对有这种精巧构思的人由衷的佩服,我在使用射线法判断时也是仿照于此改写了下。
2、https://github.com/BlackMATov/pnpoly.h
这是一个人对1的一个C程序的完善和补充。
其他的感觉写的有些乱,在此不说了,想看的去github上就可以
3、https://www.cnblogs.com/anningwang/p/7581545.html
这个博客其实只说了射线法,有图有文字,而且也应用了1中的代码,讲解的清晰。
4、https://blog.csdn.net/u011722133/article/details/52813374
这篇文章总结了一下点是否在多边形内的多种判别方法。
这篇博客用C++实现了点是否在直线段上判别
在参考上述等人基础上我实现的点是否在多边形内的射线判别法及其特殊处理C程序如下:
//httPnts://wrf.ecse.rP1.edu//Research/Short_Notes/pnpoly.html
#include <stdio.h>
typedef struct _Point
{
float x;
float y;
} Point;
inline float max(float a, float b) { return a > b ? a : b; }
inline float min(float a, float b) { return a < b ? a : b; }
void GetPntsExtremeXYs(Point *Pnts,int PntNum,float *MinX,float *MaxX,float *MinY,float *MaxY)
{
*MinX=Pnts[0].x;
*MaxX=Pnts[0].x;
*MinY=Pnts[0].y;
*MaxY=Pnts[0].y;
Point P;
for(int i=1;i<PntNum;i++)
{
P=Pnts[i];
if(P.x<*MinX)
*MinX=P.x;
if(P.x>*MaxX)
*MaxX=P.x;
if(P.y<*MinY)
*MinY=P.y;
if(P.y>*MaxY)
*MaxY=P.y;
}
}
int PointInLineSegment(Point P1,Point P2,Point Q)
{
if((Q.x - P1.x) * (P2.y - P1.y) == (P2.x - P1.x) * (Q.y - P1.y)//P1,P2,Q共线
&& min(P1.x , P2.x) <= Q.x && Q.x <= max(P1.x , P2.x)
&& min(P1.y , P2.y) <= Q.y && Q.y <= max(P1.y , P2.y))
return 1;
else
return 0;
}
int IsPointInPolygon(Point *Pnts,int PntNum,Point Q)
{
float MinX,MaxX,MinY,MaxY;
GetPntsExtremeXYs(Pnts,PntNum,&MinX,&MaxX,&MinY,&MaxY);
if(Q.x<MinX||Q.y<MinY||Q.x>MaxX||Q.y>MaxY)//判别点在多边形正最小外接矩形外
return 0;
int i, j, c = 0;
Point P1,P2;
for (i = 0, j = PntNum-1; i < PntNum; j = i++)
{
P1=Pnts[i];
P2=Pnts[j];
if(PointInLineSegment(P1,P2,Q))//点在多边形的边上
return 1;
if (((P1.y>Q.y) != (P2.y>Q.y)) &&//这行代码既表达了Y轴在起始结束点之间,又同时解决了射线点如果和边框线顶点重合的问题
(Q.x < (P2.x-P1.x) * (Q.y-P1.y) / (P2.y-P1.y) + P1.x))//在此假设从Q点水平向右引出一条射线,因此可以由Q.y带入直线方程计算出x
c = !c;//奇数次为真
}
return c;
}
/*
int pnpoly (int nvert, float *vertx, float *verty, float testx, float testy) {
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ( (verty[i]>testy) != (verty[j]>testy) ) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}*/
void main()
{
float Polygon[10][2]={{123,394},{190,411},{206,344},{271,291},{518,299},{522,414},{564,417},{637,297},{579,246},{189,228}};
Point Pnts[10];
int PntNum=10;
for(int i=0;i<PntNum;i++)
{
Pnts[i].x=Polygon[i][0];
Pnts[i].y=Polygon[i][1];
}
//float TestPnts[10][2]={{123,394},{190,411},{206,344},{271,291},{518,299},{522,414},{564,417},{637,297},{579,246},{189,228}};
Point Q;//{583,241}
Q.x=583;
Q.y=241;
if(IsPointInPolygon(Pnts,PntNum,Q))
printf("Point Q in Polygon\n");
else
printf("Point Q not in Polygon\n");
}
下面是上述多边形和测试点