zoukankan      html  css  js  c++  java
  • 判断点是否在多边形中

    给一个 (n) 个点的多边形,给一个点 (P),问点 (P) 是否在多边形内(或多边形上)。

    我们随便画一个多边形,随便在多边形内点一点,随便向外发一条射线,可以发现这条射线与多边形的交点个数为奇数。然后就做完了

    对这条性质的简单证明:我们发现多边形内一点想要到外面,必须经过一条边,如果再进去,同样必须经过一条边,以此类推,可以得到结论。

    还是有很多特殊情况的。例如射线经过多边形一个顶点的情况,或者这个点 (P) 本身就在多边形边上的情况等等。

    所以我们的具体流程是这样的:

    1. 判断点 (P) 在不在多边形的边上,如果不在进行下一步
    2. 随机一个点 (Q),若点 (PQ) 与多边形的交点中有多边形的顶点,则重新随 (Q),直到满足条件
    3. 然后判断 (PQ) 与多边形有多少交点就好啦

    时间复杂度:(O(n))

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    
    using namespace std;
    
    const double eps=1e-10;
    const int N=100009;
    int n;
    struct Point
    {
    	double x,y;
    	
    	Point () {}
    	Point (double X,double Y) : x(X),y(Y) {}
    	Point operator - (const Point a)const { return Point(x-a.x,y-a.y); }
    	double operator * (const Point a)const { return x*a.y-y*a.x; }
    	void read() { scanf("%lf %lf",&x,&y); }
    	void print() { printf("%.2lf %.2lf
    ",x,y); }
    }Q,P,a[N];
    
    void init()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		a[i].read();
    	P.read();
    }
    
    int nxt(int x) { return x==n?1:x+1; }
    
    bool Point_In_Edge(Point A,Point B,Point C)
    {
    	double Minx=min(B.x,C.x),Maxx=max(B.x,C.x),Miny=min(B.y,C.y),Maxy=max(B.y,C.y);
    	if(fabs((C-B)*(A-B))<eps&&A.x+eps>Minx&&A.x<Maxx+eps&&A.y+eps>Miny&&A.y<Maxy+eps)
    		return 1;
    	return 0;
    }
    
    bool Both_Point(Point P1,Point P2,Point P3,Point P4)
    {
    	if(!(max(P1.x,P2.x)+eps>=min(P3.x,P4.x)&&min(P1.x,P2.x)<=max(P3.x,P4.x)+eps))
    		return 0;
    	if(!(max(P1.y,P2.y)+eps>=min(P3.y,P4.y)&&min(P1.y,P2.y)<=max(P3.y,P4.y)+eps))
    		return 0;
    	if(((P2-P1)*(P3-P1))*((P2-P1)*(P4-P1))>eps)
    		return 0;
    	if(((P4-P3)*(P1-P3))*((P4-P3)*(P2-P3))>eps)
    		return 0;
    	return 1;
    }
    
    void work()
    {
    	for (int i=1;i<=n;i++)
    		if(Point_In_Edge(P,a[i],a[nxt(i)]))
    		{
    			puts("Edge");
    			return;
    		}
    	int qwq=1;
    	while(qwq)
    	{
    		qwq=0;
    		Q.x=(rand()<<15)+rand()+10000000;
    		Q.y=(rand()<<15)+rand()+10000000;
    		for (int i=1;i<=n;i++)
    			if(Point_In_Edge(a[i],P,Q))
    			{
    				qwq=1;
    				break;
    			}
    		if(qwq) continue;
    		int sum=0;
    		for (int i=1;i<=n;i++)
    			sum+=Both_Point(a[i],a[nxt(i)],P,Q);
    		if(sum&1) puts("in");
    		else puts("out");
    	}
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    国内开源缺陷管理系统PPM Bug v1.0发布
    LUA、python、注册表和正则表达式简述
    精通Windows API 线程同步控制源码
    博士生传给硕士生的经验 (转载)这实在是一篇少走许多学习弯路的好文章
    得到任务管理器的正在执行的程序列表 系统的临时路径及临时文件绝对路径
    创建设一个开机自动运行的计划任务,并且命名和当前登陆用户名相关
    刚踏实入IT行业几个月感悟
    给IT新人的15点建议:苦逼程序员的辛酸反省与总结
    char转换成WCHAR简单方法
    字符操作、文件操作和CMD命令的使用——c/c++编
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13200744.html
Copyright © 2011-2022 走看看