点是否在多边形内的射线判别法及其特殊处理C程序

        点是否在多边形内,是一个很经典的问题,方法也很成熟,但是去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

这篇文章总结了一下点是否在多边形内的多种判别方法。

5、https://blog.csdn.net/liangzhaoyang1/article/details/51088475?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

这篇博客用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");
}

下面是上述多边形和测试点

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值