您的位置:首页 > 其它

计算几何工具算法-判断点与一个多边形的位置关系

2018-01-30 15:55 477 查看

题目描述

给出一个n边形的n个顶点坐标 然后给出一个点的坐标,判断这个点与多边形的位置关系

题目分析:

对于在边上的情况很好搞,直接遍历n条边,然后依次用叉积判断即可

对于此点在多边形内部还是外部的问题 可以利用一个性质

从点P画一条足够长的射线 我们会发现 如点P在多边形内部 这条射线与多边形的交点个数为奇数

反之,如果点P在多边形外部,那么这条射线与多边形的交点个数为偶数(包括0)

但会有这样一种特殊情况 如果这条边经过多边形的一个顶点或者另外一个端点就是多边形的某个顶点 就会出现下面的情况



虽然在内部,但是也为偶数个交点

对于这种情况,我们有两种解决办法

1.在画一条射线,直到不出现这种特殊情况为止

2.对特殊情况另做处理

由于我们在做射线时使用的是一种随机化的算法,这种特殊情况出现的概率非常小,于是我们采取第一种策略.

算法流程:

1.输入数据

2.逐一判断是否在边上

3.随机在多边形外产生一个点,做出射线,直到射线不过多边形的任何一个点且不予任何一个边共线为止.

4.通过交点个数判断位置关系

代码实现:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>
#define eps 1e-10
using namespace std;
int n;
struct Point{
double x,y;
Point operator -(Point &s)
{return (Point){x-s.x,y-s.y};}
};
Point d[2005];
double operator *(Point a,Point b)
{
return a.x*b.y-b.x*a.y;
}
bool atedge(Point p0,Point p1,Point p2)
{
return fabs((p0-p1)*(p2-p1))<eps&&min(p1.x,p2.x)-eps<=p0.x&&p0.x-eps<=max(p1.x,p2.x)&&min(p1.y,p2.y)-eps<=p0.y&&p0.y-eps<=max(p1.y,p2.y);//边上判断,使用叉积
}
bool cross(Point p1,Point p2,Point p3,Point p4)
{
if(!(max(p1.x,p2.x)>=min(p3.x,p4.x)+eps&&max(p3.x,p4.x)>=min(p1.x,p2.x)+eps)) return 0;
if(!(max(p1.y,p2.y)>=min(p3.y,p4.y)+eps&&max(p3.y,p4.y)>=min(p1.y,p2.y)+eps)) return 0;
if(((p3-p1)*(p2-p1))*((p4-p1)*(p2-p1))>eps) return 0;
if(((p1-p3)*(p4-p3))*((p2-p3)*(p4-p3))>eps) return 0;
return 1;
}
int check(Point p)
{
for(int i=1;i<=n;i++)
if(atedge(p,d[i],d[i==n?1:i+1])) return -1;
Point prand;
while(1)
{
bool flag=1;
prand.x=(rand()<<15)+rand()+1e7;
prand.y=(rand()<<15)+rand()+1e7;
for(int i=1;i<=n&&flag;i++)
if(atedge(d[i],p,prand)) flag=0;
if(flag) break;
}
int sum=0;
for(int i=1;i<=n;i++)
sum+=cross(p,prand,d[i],d[i==n?1:i+1]);
return sum;
}
int main()
{
Point P;
scanf("%d",&n);
srand(time(0));
for(int i=1;i<=n;i++)
scanf("%lf%lf",&d[i].x,&d[i].y);
scanf("%lf%lf",&P.x,&P.y);
int ans=check(P);
if(ans==-1) puts("Bian");
else if(ans%2) puts("Neibu");
else puts("Waibu");
return 0;
}


测试数据:

8
2 2
3 6
3 2
6 3
6 4
4 3
7 6
7 1
5 3 外部

8
2 2
3 6
3 2
6 3
6 4
4 3
7 6
7 1
5 2 内部

8
2 2
3 6
3 2
6 3
6 4
4 3
7 6
7 1
5 4 边上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: