C语言判断点是否在多边形内

题目

在这里插入图片描述在这里插入图片描述

解答

在这里插入图片描述

	#include<stdio.h>
	#include<stdlib.h>
	
	#define EXP 1e-8 //精度
	
	typedef struct Point{
		double x;
		double y;
		struct Point *next;
	}Point, *Polygon; //多边形就是点的集合
	
	/*
	创建多边形【将构成多边形的一系列点存储在一个循环队列中】
	返回1:创建成功
	返回0:创建不成功,点没有闭合
	*/
	int CreatePolygon(char *filename, Polygon *pHead){ //由于多边形头指针pHead会发生改变,因此用二级指针
		FILE *fp;
		int n;
		int i;
		Point *p,*q;
		double a,b;
		double suba, subb;
		
		fp = fopen(filename, "r");
		if(!fp) 
			exit(0);
	
		/*n=构成多边形的点数+1【由于原点要遇到两次,因此+1】【构成多边形点数要>=3】*/
		fscanf(fp,"%d", &n);
	
		p = NULL;
		for(i=0; i<n; i++){
			/*读取第i个点的x坐标【a】和y坐标【b】*/
			fscanf(fp,"%lf%lf", &a, &b); 
	
			/*分配一个点的空间并赋予其坐标属性*/
			q = (Point*)malloc(sizeof(Point)); 
			if(!q) 
				exit(0);
			q->x = a;
			q->y = b;
	
			/*将各个点连接成循环队列【队列先进先出】*/
			if(p==NULL){ //第一个点
				q->next = q; //将第一个点q的next指向它自己
				p = q; //令p指向q【p始终指向队尾】
				*pHead = q; //令队头结点指针指向q
			} 
			else{ //第2—>n个点
				/*第1个结点在队头*/
				suba = (*pHead)->x - a; //将【队头结点的x坐标-a】赋给suba
				subb = (*pHead)->y - b; //将【队头结点的y坐标-b】赋给subb
				/*若第一个结点和最后一个结点重合,即x、y坐标均相等,说明多边形闭合了*/
				/*因此按理来讲suba和subb都应为0*/
				/*但我们用EXP控制精度【达到了这个精度,就可以认为这两个点是重合的】*/
				if(suba>=-EXP && suba<=EXP && subb>=-EXP && subb<=EXP){
					free(q);  //释放这个重合的结点【第二次遇到的这个】
					return 1; //构造成功,返回即可
				}
				p->next = q; //将新结点q挂在p后面【p始终指向队尾】
				q->next = *pHead; //新结点q的next指向队头,构成循环队列
				p = q; //p指向新结点q,使其始终指向队尾
			}
		}
	
		fclose(fp);
		return 0;
	}
	
	/*射线法判断点A是否在多边形内部【假设从点A向右作射线】*/
	int PointInPolygon(Point A, Polygon head){
		Point *p, *p1, *p2;
		int cnt; //从A点向右作的射线与多边形的交点个数
		double ymax;
		double ymin;
		double x;
	
		cnt=0;
		p = head; //令p指针指向头结点
		do{
			p1 = p; //令p1指针指向前一个结点		
			p2 = p->next; //令p2指针指向后一个结点
			//将y坐标值大的赋给ymax,小的赋给ymin
			if(p1->y > p2->y){  
				ymax = p1->y;
				ymin = p2->y;
			} 
			else{
				ymax = p2->y;
				ymin = p1->y;
			}
	
			/*如果从点A向右作的射线【或其反向延长线】不与直线p1p2相交【只有一个交点】,则令p指向下一个点,进行下一个线段的判断*/
			/*我们用EXP控制精度【达到了这个精度,就可以认为这两个点的y坐标是相等的】*/
			if( p1->y - p2->y >= -EXP && p1->y - p2->y <= EXP ){ //p1与p2所指点的y坐标相等
				p = p->next; //指针p指向下一个点
				continue;
			}
			else if( A.y < ymin ){ //点A与直线p1p2的交点在p1p2延长线上【下面的延长线】
				p = p->next; //指针p指向下一个点
				continue;
			}
			else if( A.y >= ymax ){ //点A与直线p1p2的交点在p1p2延长线上【上面的延长线】【注意是大于等于】
				p = p->next; //指针p指向下一个点
				continue;
			}
	
			/*求直线p1p2与直线y=A.y的交点的x坐标【根据两点式方程求交点坐标】*/
			x = (double)(p2->x - p1->x) / (double)(p2->y - p1->y) * (double)(A.y - p1->y) + p1->x;
			if(x > A.x) //如果交点在点A的右侧【因为我们是向右作射线的,因此只计算与右边相交的个数】
				cnt++; //从A点向右作的射线与多边形的交点个数++
			p = p->next; //指针p指向下一个点,继续判断下一个线段
		}while(p!=head); //当p不指向头结点时【指向头结点表明队列遍历完毕】
	
		/*当射线与多边形的交点个数为偶数时,返回0【说明A点在多边形外】*/
		/*当射线与多边形的交点个数为奇数时,返回1【说明A点在多边形内】*/
		return cnt%2==1; 
	}
	
	int main(){
		Point A;
		Polygon  P;
		
		CreatePolygon("2013-05_Polygon.txt",&P);
		printf("输入点A的坐标:\n>>> ");
		scanf("%lf%lf", &A.x, &A.y);
		if( PointInPolygon(A,  P))
			printf("A点在多边形内部\n");
		else
			printf("A点在多边形外部\n");
		
		return 0;
	}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值