计算几何模板

发布时间 2023-08-22 16:51:50作者: One_JuRuo
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8,pi=acos(-1.0);
const int N=100005;
inline int dcmp(double x){return (x<-eps)?-1:(x>eps)?1:0;}//判断正负
inline double dabs(double x){return x*dcmp(x);}//绝对值 
/*向量(点)*/
struct vec{double x,y;vec(double _x=0,double _y=0){x=_x;y=_y;}};
inline bool cmp_vec(vec a,vec b){return (a.x!=b.x)?a.x<b.x:a.y<b.y;}
inline double len(vec a){return sqrt(a.x*a.x+a.y*a.y);}//模长 
inline double ang(vec a){return atan2(a.y,a.x);}//角度 
inline vec operator +(const vec &a,const vec &b){return vec(a.x+b.x,a.y+b.y);}
inline vec operator -(const vec &a,const vec &b){return vec(a.x-b.x,a.y-b.y);}
inline vec operator *(const vec &a,const double &b){return vec(a.x*b,a.y*b);}
inline vec operator /(const vec &a,const double &b){return vec(a.x/b,a.y/b);}
inline double operator *(const vec &a,const vec &b){return a.x*b.x+a.y*b.y;}//点积 
inline double operator ^(const vec &a,const vec &b){return a.x*b.y-a.y*b.x;}//叉积
inline vec rot(vec a,double the){return vec(a.x*cos(the)-a.y*sin(the),a.x*sin(the)+a.y*cos(the));}//旋转 
inline vec rot90(vec a){return vec(a.y,-a.x);}//特殊角旋转
inline vec rotpt(vec a,vec b,double the){return b+rot(a-b,the);}//a绕b旋转
/*线*/ 
struct line{vec s,t;line(vec _s=vec(0,0),vec _t=vec(0,0)){s=_s;t=_t;}};//线 
inline double maxx(line l){return max(l.s.x,l.t.x);}//大x
inline double maxy(line l){return max(l.s.y,l.t.y);}//大y 
inline double minx(line l){return min(l.s.x,l.t.x);}//小x
inline double miny(line l){return min(l.s.y,l.t.y);}//小y
inline double ang(line l){return ang(l.t-l.s);}//角度 
inline bool operator <(line &a,line &b){double a1=ang(a.t-a.s),a2=ang(b.t-b.s);return (dcmp(a2-a1))?a2>a1:dcmp((a.t-a.s)^(b.t-b.s))<0;} 
inline bool operator ==(vec &a,vec &b){return (!dcmp(a.x-b.x)&&!dcmp(a.y-b.y));}//点是否相等 
inline double dis(vec a,vec b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}//点距离
inline bool pd_pl(vec a,line b){return !dcmp((a-b.s)^(b.t-b.s));}//点是否在直线上
inline bool pd_px(vec a,line b){return pd_pl(a,b)&&(dcmp((a-b.s)*(a-b.t))<=0);}//点是否在线段上
inline vec footpt(vec a,line b){vec x=a-b.s,y=a-b.t,z=b.t-b.s;double s1=x*z,s2=-1.0*(y*z);return b.s+z*(s1/(s1+s2));}//求垂足(分别求as,at关于st的投影)
inline vec mirror(vec a,line b){return a+(footpt(a,b)-a)*2.0;}//a关于b的对称点
inline double dis_pl(vec a,line b){return dabs((a-b.s)^(a-b.t))/len(b.t-b.s);}//求a到直线b的距离(面积除以底边长)
inline double dis_px(vec a,line b){return (dcmp((a-b.s)*(b.t-b.s))<0)?len(a-b.s):(dcmp((a-b.t)*(b.t-b.s))>0)?len(a-b.t):dis_pl(a,b);}//求a到线段b的距离
inline vec pt_px(vec a,line b){return (dcmp((a-b.s)*(b.t-b.s))<0)?b.s:(dcmp((a-b.t)*(b.t-b.s))>0)?b.t:footpt(a,b);}//在线段b上与a最近的点
inline vec cross(line a,line b){vec x=a.t-a.s,y=b.t-b.s,z=a.s-b.s;return a.s+x*((y^z)/(x^y));}//求a与b的交点
inline bool pd_cross_lx(line a,line b){return (!dcmp((a.t-a.s)^(b.t-b.s)))?0:pd_px(cross(a,b),a);}//线段a与直线b是否相交
inline bool pd_cross_xx(line a,line b){return pd_cross_lx(a,b)&&pd_cross_lx(b,a);}//判断线段a是否与线段b相交
inline bool pd_cross_xx_(line a,line b)//判断两线段是否相交 (另一种方法,是否跨立) 
{
	if(maxx(a)<minx(b)||maxy(a)<miny(b)) return false;
	if(maxx(b)<minx(a)||maxy(b)<miny(a)) return false;
	double s1=(a.t-a.s)^(b.s-a.s),s2=(a.t-a.s)^(b.t-a.s);
	double s3=(b.t-b.s)^(a.s-b.s),s4=(b.t-b.s)^(a.t-b.s);
	return dcmp(s1)*dcmp(s2)<=0&&dcmp(s3)*dcmp(s4)<=0;//a的端点在b的两侧且b的端点在a的两侧 
}
inline double s_t(vec a,vec b,vec c){return dabs((b-a)*(c-a))/2;}//已知三点求三角形面积 
/*多边形*/
struct pol
{
	vector<vec> pt;
	inline vec& operator [](int x){return pt[x];}
	inline int ne(int x){return (x<pt.size()-1)?x+1:0;}
	inline void insert(vec p){pt.push_back(p);}
	inline void clear(){pt.clear();}
	inline int include(vec p)//点在多边形外:0,在多边形内:1,在多边形边上:2 
	{
		int cnt=0;
		for(int i=0;i<pt.size();i++)//射线法判断,射线方向为x轴正方向 
		{
			vec s=pt[i],t=pt[ne(i)];line l=line(s,t);
			if(pd_px(p,l)) return 2;
			if(dcmp(p.y-miny(l))>=0&&dcmp(maxy(l)-p.y)>0)
			if(dcmp(s.x+((p.y-s.y)/(t.y-s.y)*(t.x-s.x))-p.x)>0) cnt++;
		}
		return cnt&1;//偶数个交点则在多边形外,奇数个交点则在多边形内 
	}
	inline double s_p()//多边形面积 
	{
		double ans=0;
		for(int i=1;i<pt.size()-1;i++) ans+=(pt[i]-pt[0])^(pt[ne(i)]-pt[0]);
		return dabs(ans)/2;
	}
	inline double c_p()//多边形周长 
	{
		double ans=0;
		for(int i=0;i<pt.size();i++) ans+=dis(pt[i],pt[ne(i)]);
		return ans;
	}
	inline bool pd_l(vec x,vec l,vec r){return dcmp((l-x)^(r-x))<=0;}//xl是否在xr的左侧
	inline int include_(vec p)//二分法判断点是否在多边形内
	{
		int n=pt.size();
		if(!pd_l(pt[0],p,pt[1])) return 0;
		if(!pd_l(pt[0],pt[n-1],p)) return 0; 
		if(pd_px(p,line(pt[0],pt[1]))) return 2;
		if(pd_px(p,line(pt[0],pt[n-1]))) return 2;
		int l=1,r=n-2,ans=1,mid;
		while(l<=r)//二分找到最接近线(pt[0],p)的(pt[0],pt[ans]) 
		{
			mid=l+r>>1;
			if(!pd_l(pt[0],pt[mid],p)) l=mid+1,ans=mid;
			else r=mid-1;
		}
		if(!pd_l(pt[ans],p,pt[ne(ans)])) return 0;
		if(pd_px(p,line(pt[ans],pt[ne(ans)]))) return 2;
		return 1;
	} 
};
/*凸包*/
inline void andrew(pol &p)
{
	vector<vec>q(p.pt.size()<<1);int top=0,n=p.pt.size();
	sort(p.pt.begin(),p.pt.end(),cmp_vec),q[top]=p[0];
	for(int i=1;i<n;i++)
	{
		while(top&&dcmp((q[top-1]-q[top])^(q[top-1]-p[i]))<=0) top--;
		q[++top]=p[i];
	}
	int tot=top;
	for(int i=n-2;i>=0;i--)
	{
		while(top>tot&&dcmp((q[top-1]-q[top])^(q[top-1]-p[i]))<=0) top--;
		q[++top]=p[i];
	}
	if(n>1) top--;
	p.clear();
	for(int i=0;i<=top;i++) p.insert(q[i]);
}
/*旋转卡壳*/
inline double diam(pol p)
{
	int n=p.pt.size();double ans=0;
	for(int i=0,j=1;i<n;i++)
	{
		for(;;j=p.ne(j)) if(dcmp(s_t(p[j],p[i],p[p.ne(i)])-s_t(p[p.ne(j)],p[i],p[p.ne(i)]))>=0) break;
		ans=max(ans,max(dis(p[j],p[i]),dis(p[j],p[p.ne(i)])));
	}
	return ans;
}```