模板 多边形

多边形

struct polygon{
	int n;
	Point p[maxp];
	Line l[maxp];
	void input(int _n){
		n=_n;
		for(int i=0;i< n;i++)
			p[i].input();
	}
	void add(Point q){
		p[n++]=q;
	}
	void getline(){
		for(int i=0;i<n;i++){
			l[i]=Line(p[i],p[(i+1)%n]);
		}
	}
	struct cmp{
		Point p;
		cmp(const Point &p0){
			p=p0;
		}
		bool operator()(const Point &aa,const Point &bb){
			Point a=aa,b=bb;
			int d=sgn((a-p)^(b-p));
			if(d==0){
				return sgn(a.distance(p)-b.distance(p))<0;
			}
			return d > 0;
		}
	};
	//进行极角排序
	//首先需要找到最左下角的点
	//需要重载号好Point的 < 操作符(min函数要用)
	void norm(){
		Point mi=p[0];
		for(int i=1;i<n;i++) mi=min(mi,p[i]);
		sort(p,p+n,cmp(mi));
	}
	//得到凸包
	//得到的凸包里面的点编号是[0,n-1]的
	//两种凸包的方法
	//注意如果有影响,要特判下所有点共点,或者共线的特殊情况
	void getconvex(polygon &convex){
		sort(p,p+n);
		convex.n=n;
		for(int i=0;i<min(n,2);i++){
			convex.p[i]=p[i];
		}
		//特判
		if(convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
		if(n<=2) return;
		int &top=convex.n;
		top=1;
		for(int i=2;i<n;i++){
			while(top && sgn((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0)
				top--;
			convex.p[++top]=p[i];
		}
		int temp=top;
		convex.p[++top]=p[n-2];
		for(int i=n-3;i>=0;i--){
			while(top!=temp && sgn((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0)
				top--;
			convex.p[++top]=p[i];
		}
		//特判
		if(convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
		//原来得到的是顺时针的点,排序后逆时针
		convex.norm();
	}
	//得到凸包的另外一种方法,Graham算法
	void Graham(polygon &convex){
		norm();
		int &top=convex.n;
		top=0;
		if(n==1){
			top=1;
			convex.p[0]=p[0];
			return;
		}
		if(n==2){
			top=2;
			convex.p[0]=p[0];
			convex.p[1]=p[1];
			if(convex.p[0]==convex.p[1]) top--;
			return;
		}
		convex.p[0]=p[0];
		convex.p[1]=p[1];
		top=2;
		for(int i=2;i<n;i++){
			while( top>1 && sgn((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))<=0 )
				top--;
			convex.p[top++]=p[i];
		}
		//特判
		if(convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
	}
	//判断是不是凸的
	bool isconvex(){
		bool s[2];
		memset(s,false,sizeof(s));
		for(int i=0;i<n;i++){
			int j=(i+1)%n;
			int k=(j+1)%n;
			s[sgn((p[j]-p[i])^(p[k]-p[i]))+1]=true;
			if(s[0] && s[2]) return false;
		}
		return true;
	}
	//判断点和任意多边形的关系
	//3 点上
	//2 边上
	//1 内部
	//0 外部
	int relationpoint(Point q){
		for(int i=0;i<n;i++){
			if(p[i]==q) return 3;
		}
		getline();
		for(int i=0;i<n;i++){
			if(l[i].pointonseg(q)) return 2;
		}
		int cnt=0;
		for(int i=0;i<n;i++){
			int j=(i+1)%n;
			int k=sgn((q-p[j])^(p[i]-p[j]));
			int u=sgn(p[i].y-q.y);
			int v=sgn(p[j].y-q.y);
			if(k>0 && u<0 && v>=0) cnt++;
			if(k<0 && v<0 && u>=0) cnt--;
		}
		return cnt!=0;
	}
	//直线u切割凸多边形左侧
	//注意直线方向
	void convexcut(Line u,polygon &po){
		//注意引用
		int &top=po.n;
		top=0;
		for(int i=0;i<n;i++){
			int d1=sgn((u.e-u.s)^(p[i]-u.s));
			int d2=sgn((u.e-u.s)^(p[(i+1)%n]-u.s));
			if(d1>=0) po.p[top++]=p[i];
			if(d1*d2<0) po.p[top++]=u.crosspoint(Line(p[i],p[(i+1)%n]));
		}
	}
	//得到周长
	double getcircumference(){
		double sum=0;
		for(int i=0;i<n;i++){
			sum+=p[i].distance(p[(i+1)%n]);
		}
		return sum;
	}
	//得到面积
	double getarea(){
		double sum=0;
		for(int i=0;i<n;i++){
			sum+=(p[i]^p[(i+1)%n]);
		}
		return fabs(sum)/2;
	}
	//得到方向
	//1 表示逆时针,0表示顺时针
	bool getdir(){
		double sum=0;
		for(int i=0;i<n;i++)
			sum+=(p[i]^p[(i+1)%n]);
		if(sgn(sum)>0) return 1;
		return 0;
	}
	//得到重心
	Point getbarycentre(){
		Point ret(0,0);
		double area=0;
		for(int i=1;i<n-1;i++){
			double tmp=(p[i]-p[0])^(p[i+1]-p[0]);
			if(sgn(tmp)==0) continue;
			area+=tmp;
			ret.x+=(p[0].x+p[i].x+p[i+1].x)/3*tmp;
			ret.y+=(p[0].y+p[i].y+p[i+1].y)/3*tmp;
		}
		if(sgn(area)) ret=ret/area;
		return ret;
	}
	//多边形和圆交的面积
	double areacircle(circle c){
		double ans=0;
		for(int i=0;i<n;i++){
			int j=(i+1)%n;
			if(sgn((p[j]-c.p)^(p[i]-c.p))>=0)
				ans+=c.areatriangle(p[i],p[j]);
			else ans-=c.areatriangle(p[i],p[j]);
		}
		return fabs(ans);
	}
	//多边形和圆的关系
	//2 圆完全在多边形内
	//1 圆在多边形里面,碰到了多边形边界
	//0 其它
	int relationcircle(circle c){
		getline();
		int x=2;
		//圆心不在内部
		if(relationpoint(c.p)!=1) return 0;
		for(int i=0;i<n;i++){
			if(c.relationseg(l[i])==2) return 0;
			if(c.relationseg(l[i])==1) x = 1;
		}
		return x;
	}
};
posted @ 2020-07-11 00:32  fxq1304  阅读(15)  评论(0编辑  收藏  举报