计算几何全家桶

本文出现的代码不保证正确性,若有错误烦请指出。

指路 wind_whisper 神仙的博客

敲警钟:读入直线千万不要写 line a=trans(read(),read(),read(),read());。这是 UB。

基础运算

typedef double db;
const db eps=1e-10;
struct V{
	db x,y;
};
#define il inline
//向量之间运算 
il bool operator ==(const V &a,const V &b) {return fabs(a.x-b.x)<=eps&&fabs(a.y-b.y)<=eps;}  
il bool operator !=(const V &a,const V &b) {return !(a==b);}

il V operator +(const V &a,const V &b) {return {a.x+b.x,a.y+b.y};}
il V operator -(const V &a,const V &b) {return {a.x-b.x,a.y-b.y};}
il V operator *(const V &a,const db &x) {return {a.x*x,a.y*x};}
il V operator *(const db &x,const V &a) {return {a.x*x,a.y*x};}
il V operator /(const V &a,const db &x) {return {a.x/x,a.y/x};}

il db operator *(const V &a,const V &b) {return a.x*b.x+a.y*b.y;} 
il db operator ^(const V &a,const V &b) {return a.x*b.y-a.y*b.x;}

il db len(const V &a) {return sqrt(a*a);}
il V  mid(const V &a,const V &b) {return {(a.x+b.x)/2,(a.y+b.y)/2};}
il V  cui(const V &a) {return {a.y,-a.x};}
il V   dw(const V &a) {return a/len(a);}

角度

il db tri_S(const V &a,const V &b,const V &c) {return fabs((a-c)^(b-c))/2;}
il db angle(const V &a,const V &b) {return acos(a*b/len(a)/len(b));}
//以下均为角 BAC. 
il bool zhi(const V &a,const V &v,const V &c) {return fabs((b-a)*(c-a))<=eps;} 
il bool dun(const V &a,const V &b,const V &c) {return (b-a)*(c-a)<-eps;}
il bool rui(const V &a,const V &b,const V &c) {return (b-a)*(c-a)>eps;}
il V turn(const V &a,db t){
	db s=sin(t),c=cos(t);
	return {a.x*c-a.y*s,a.x*s+a.y*c};
}

线

struct line{
	V d,a,b;
};
inline line trans(db a,db b,db c,db d)
{
	V dd={c-a,d-b},x={a,b},y={c,d};
	dd=dw(dd);
	return {dd,x,y};
}
inline line trans(const V &a,const V &b)
{
	V dd={b.x-a.x,b.y-a.y};dd=dw(dd);
	return {dd,a,b};
}

点和线的关系

il V cui(const V &o,const line &l) {return ((o-l.a)*l.d)*l.d+l.a;}
il V duichen(const V &o,const line &l)
{
	V qwq=cui(o,l);
	return {2*qwq.x-o.x,2*qwq.y-o.y};
}
il db dis(const V &o,const line &l,int op=0)
{
	if(op&&(dun(l.a,o,l.b)||dun(l.b,o,l.a))) return min(len(l.a-o),len(l.b-o));
	else return fabs((l.a-o)^(l.b-o))/len(l.b-l.a);
}
il bool on_line(const line &l,const V &o) {return fabs((o-l.a)^(l.b-l.a))<eps;}
il bool on_seg(const line &l,const V &o) {return fabs(len(o-l.a)+len(o-l.b)-len(l.b-l.a))<eps;}
il int pos(const line &l,const V &o)
{
	if(!on_line(l,o)) 
	{
		if((o-l.a)^l.d<-eps) return 1;//clockwise
		else return 2;//counter clockwise
	}
	if((o-l.a)*(o-l.b)<-eps) return 5;//on
	else if(len(o-l.a)>len(o-l.b)) return 3;//front
	else return 4;//back
}

线和线的关系

//线和线
il bool gongxian(const line &a,const line &b) {return fabs(a.d^b.d)<eps;}
il bool cuizhi  (const line &a,const line &b) {return fabs(a.d*b.d)<eps;} 
il bool xdjiao(const line &u,const line &v)//拼音太长缩写了>_< 
{
	if(min(u.a.x,u.b.x)>max(v.a.x,v.b.x)+eps||max(u.a.x,u.b.x)<min(v.a.x,v.b.x)-eps) return 0;
	if(min(u.a.y,u.b.y)>max(v.a.y,v.b.y)+eps||max(u.a.y,u.b.y)<min(v.a.y,v.b.y)-eps) return 0;
	return ((u.a-v.a)^v.d)*((u.b-v.a)^v.d)<eps&&((v.a-u.a)^u.d)*((v.b-u.a)^u.d)<eps;
}
il V jiaodian(const line &u,const line &v)
{
	double k=((v.a-u.a)^v.d)/(u.d^v.d);
	return k*u.d+u.a;
}
il line pingfen(const V &a,const V &b,const V &c)//角 BAC 
{
	int d1=dw(b-a),d2=dw(c-a);
	int d=(d1+d2)/2;
	return (line){d,a,a+d};
}

多边形

il int in_poly(V *a,int n,V o)
{
	int res=0;a[n+1]=a[1];
	for(int i=1;i<=n;i++)
	{
		V u=a[i],v=a[i+1];
		if(on_seg(trans(u,v),o)) return 1;
		if(abs(u.y-v.y)<eps) continue;
		if(max(u.y,v.y)<o.y-eps) continue;
		if(min(u.y,v.y)>o.y-eps) 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;
}
il double S(V *a,int n)
{
	db res=0;
	for(int i=1;i<=n;i++) res+=(a[i]^a[i%n+1]);
	return res/2;
}
il int is_convex(V *a,int n)
{
	a[0]=a[n],a[n+1]=a[1];
	int op=0;
	for(int i=1;i<=n;i++)
	{
		V x=a[i]-a[i-1],y=a[i+1]-a[i];
		if(abs(x^y)<eps) continue;
		int np=((x^y)>0)?1:-1;
		if(!op) op=np;
		else if(op!=np) return 0;
	}
	return 1;
}

凸包

V Q[N];int tp;
bool cmp(V a,V b)
{
	if(a.x==b.x) return a.y<b.y;
	else return a.x<b.x;
}
void andrew(V *a,int n)
{
	sort(a+1,a+n+1,cmp);
	Q[++tp]=a[1];
	for(int i=2;i<=n;Q[++tp]=a[i],i++)
		while(tp>1&&((Q[tp]-Q[tp-1])^(a[i]-Q[tp]))<eps) tp--;
	int pos=tp;
	for(int i=n-1;i;Q[++tp]=a[i],i--)
		while(tp>pos&&((Q[tp]-Q[tp-1])^(a[i]-Q[tp]))<eps) tp--;
	tp--;
}

旋转卡壳

int ans;
void find()
{
    int now=2;
    for(int i=1;i<=tp;i++)
    {
        V a=Q[i],b=Q[i%tp+1];
        while(Dis(a,b,Q[now%tp+1])>Dis(a,b,Q[now])) now=now%tp+1;
        ans=max(ans,dis(a,Q[now]));
        ans=max(ans,dis(b,Q[now]));
    }
}

半平面交

struct line
{
	V a,b,d;
	double angle;
}a[N];
line trans(V a,V b) 
{
	double res=atan2((b-a).y,(b-a).x);V d=(b-a)/len(b-a);
	return {a,b,d,res};
}
V jiaodian(line a,line b)
{
	double k=((b.a-a.a)^(b.d))/(a.d^b.d);
	return a.a+(k*a.d);
}
bool cmp(line x,line y)
{
	if(fabs(x.angle-y.angle)>eps) return x.angle<y.angle;
	else return ((y.a-x.a)^(y.b-x.a))>eps;
}
bool check(line a,line b,line c)
{
	V p=jiaodian(b,c);
	return (a.d^(p-a.a))<-eps;
}
line Q[N];
int h=1,t=0,tot;
V ans[N];
void solve()
{
	sort(a+1,a+tot+1,cmp);
	int cnt=1;
	for(int i=2;i<=tot;i++)
		if(fabs(a[i].angle-a[i-1].angle)>eps) a[++cnt]=a[i];
	tot=cnt;
	
	Q[++t]=a[1],Q[++t]=a[2];
	for(int i=3;i<=tot;i++)
	{
		while(h<t&&check(a[i],Q[t],Q[t-1])) t--;
		while(h<t&&check(a[i],Q[h],Q[h+1])) h++;
		Q[++t]=a[i];
	}
	while(h<t&&check(Q[h],Q[t],Q[t-1])) t--;
	while(h<t&&check(Q[t],Q[h],Q[h+1])) h++;
	int qwq=0;
	for(int i=h;i<t;i++) ans[++qwq]=jiaodian(Q[i],Q[i+1]);
	if(t-h>1) ans[++qwq]=jiaodian(Q[h],Q[t]);
	tot=qwq;
}
int main()
{
	int n=read();tot=0;
	for(int i=1;i<=n;i++)
	{
		int m=read();
		for(int j=1;j<=m;j++)
			b[j].x=read(),b[j].y=read();
		for(int j=1;j<=m;j++) a[++tot]=trans(b[j],b[j%m+1]);
	}
	solve();
	double res=0;
	for(int i=1;i<=tot;i++) res+=(ans[i]^ans[i%tot+1]);
	printf("%.3lf\n",res/2);
	return 0;
}
posted @ 2023-01-16 10:52  樱雪喵  阅读(94)  评论(0编辑  收藏  举报