计算几何(三)多边形

写在前面

本文基于fxj巨佬的计算几何全家桶,并基于原文进行了自己的一些整理了经验补充,阅读本文前请前往支持巨佬fxj

表示:

用一个 V V V数组顺时针或者逆时针存储多边形的所有顶点。
调用函数时传入数组和顶点数。

求多边形面积:

取任意一个点 O O O,多边形面积为:
S = 1 2 ∑ i = 1 n O A i → × O A → i % n + 1 S=\frac{1}{2}\sum^{n}_{i=1} \overrightarrow{OA_i} \times\overrightarrow{OA}_{i\%n+1} S=21i=1nOAi ×OA i%n+1

inline double S(const V *a,const int n)
{
	double res(0);
	for(int i=1;i<=n;++i) res+=(a[i]^a[i%n+1]);
	return res/2;
}

判断多边形的凹凸性

取相邻的三个点 ( a , b , c ) ( a , b , c ) (a,b,c)作为一个三元组。
判断多边形凹凸的充要条件:对于多边形所有的 n n n个这样三元组, c c c a b ab ab的位置关系(指顺时针或逆时针)必然全部都是相同的。
叉积判断符号即可。
注意如果没有保证相邻三个点不共线的话需要特判。
时间复杂度 O ( n ) O ( n ) O(n).

bool is_convex(const V *a,const int n)
{
	a[0]=a[n],a[n+1]=a[1];
	int op=0;
	for(int i=1;i<=n;++i)
	{
		double o=(a[i+1]-a[i])^(a[i]-a[i-1]);
		if(abs(o)<eps) continue;
		int nop=o>0?1:-1;
		if(!op) op=nop;
		else if(op!=nop) return false;
	}
	return true;
}

判定点在多边形内

一个看起来很好写但写起来很恶心的东西。
推荐使用点数判别法
向左水平引出一条射线,计算其与多边形产生多少个交点,奇内偶外,然后还有亿点点细节:

  1. 如果当前边经过了该点,直接返回相应结果
  2. 由于可能出现射线经过多边形顶点导致一个点被计算两次的情况,强制令这个点在下面的边被统计。实现上,当 m a x ( y 1 , y 2 ) = y 0 max(y_1,y_2)=y_0 max(y1,y2)=y0时,统计该次答案, m i n ( y 1 , y 2 ) = y 0 min(y_1,y_2)=y_0 min(y1,y2)=y0而当时,不统计该次答案。
  3. 出现水平边时,直接忽略即可,结合第二条的处理原则,就依然是正确的.
int in_poly(const V *a,const int n,const V o){
 int res(0);
 for(int i=1;i<=n;i++){
   V u=a[i],v=a[i+1];
   if(on_seg(trans(u,v),o)) return 1;//on the edge
   if(abs(u.y-v.y)<eps) continue;//ignore horizontal
   if(max(u.y,v.y)<o.y-eps) continue;//equal will not continue
   if(min(u.y,v.y)>o.y-eps) continue;//equal will continue
   double x=u.x+(o.y-u.y)/(v.y-u.y)*(v.x-u.x);
   if(x<o.x) res^=1;
 }
 return res?2:0;//odd:in even:out
}

关于判断射线和多边形的某一条边是否有交点的正确性。
在这里插入图片描述
函数中给出的算法就是求点 K K K的坐标,通过比较 X K X_K XK X O X_O XO即可判断从 O O O水平向左的射线是否与线段 U V UV UV有交点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值