点在多边形内判定模板(射线法,凹凸多边形均可)

8 篇文章 0 订阅

首先明白 在任意多边形内一点,发射一条射线(以水平为例),必然与奇数条变相交。

如下图为例:

那么我们得到判定条件:

 奇数个交点          ==》 点在多边形内

偶数个交点          ==》  点在多边形外

 特例说明,如果要是设定,在线段上也算点在多边形内

那么判断共线且非射线即可。

代码如下:

#include<iostream>
#include<vector>
using namespace std;
const double eps=1e-8;
inline int dcmp(double x){
	return x<-eps ? -1:x>eps;
}

struct Point{
	double x,y;
	Point(){}
	Point(double a,double b):x(a),y(b){}

	Point operator -(const Point &rhs) const{
		return Point(x-rhs.x,y-rhs.y);
	}
};
double det(const Point &a,const Point &b)
{
	return a.x*b.y-a.y*b.x;
}
double dot(const Point &a,const Point &b)
{
	return a.x*b.x+a.y*b.y;
}
bool on_point_segment(Point p,Point a1,Point a2)
{
	return dcmp(det(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<=0;
}
int in_point_polygon(Point o,const vector<Point> &poly,bool flag)
{
	int t=0,k;
	Point a,b;
	int n=poly.size();
	for(int i=0;i<n;i++)
	{
		if(on_point_segment(o,poly[i],poly[(i+1)%n]))
			return flag;
	}
	for(int i=0;i<n;i++)
	{
		a=poly[i];
		b=poly[(i+1)%n];
		if(dcmp(a.y-b.y)>0)swap(a,b);
		if(dcmp(det(a-o,b-o))<0&&dcmp(a.y-o.y)<0&&dcmp(o.y-b.y)<=0)
			t++;
	}
	k=t&1;
	if(k==1)
		return 2;
	else 
		return 0;
}

int main()
{
	vector <Point> a;
	vector <Point> b;
	int n,m;
	Point s;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>s.x>>s.y;
		a.push_back(s);
	}
	cin>>m;
	for(int i=0;i<m;i++)
	{
		cin>>s.x>>s.y;
		b.push_back(s);
	}

	for(int i=0;i<m;i++)
	{
		printf("%d\n",in_point_polygon(b[i],a,1));

	}

}

例题:

题目背景

原魔在最近一次更新中,上线了「层岩巨渊」。其中许多区域分布着神秘的「黑泥」,角色处于「黑泥」中,攻击力会变得更强,与旅行者战斗时具有巨大优势。但「层岩巨渊」非常昏暗,原魔们需要你来帮助他们判断他与「黑泥」的位置关系。

题目描述

「黑泥」呈区域性分布,具体来说是一个凸多边形。逆时针给出每个顶点的坐标,并给出若干角色的坐标。请你判断角色与「黑泥」的位置关系。若角色在「黑泥」外请输出0,若角色在「黑泥」边界上请输出1,若角色在「黑泥」内请输出2,

输入格式

第一行一个正整数n,表明这是一个n边形 接下来n行,每行两个数x,y。表明这个顶点的横坐标与纵坐标。 第n+1行一个正整数m,表明接下来有m次查询。 接下来m行,每行两个整数x,y。表明这个查询点(即角色所在坐标)的横坐标与纵坐标。

输出格式

输出m行,每行为角色与「黑泥」的位置关系(0或1或2)

样例输入

4
0 0
3 1
2 3
0 3
3
2 1
0 2
3 2

样例输出

2
1
0

数据范围

  • 凸多边形的端点互不相同

  • 凸多边形的任意两边最多只有一个交点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值