PSLG,直線切割凸多邊形,和判斷圓與多邊形相交
阿新 • • 發佈:2019-02-04
分析:
除了圓盤之外,本題的輸入也是一個PSLG,因此可以按照前面敘述的演算法求出各個區域。但由於本題的特殊性,不難發現把線段改成直線後答案不變,因此每個塊都是凸多邊形,
可以用切割凸多邊形的方法求解:每讀入一條線段,都把它當做直線,切割所有塊。這樣,我們最終得到了若干凸多邊形,需要分別判斷是否與圓盤相交。
如何讓判斷多邊形是否和圓盤相交?,顯然,如果多邊形的邊和圓周規範相交,圓盤和多變性一定相交,但反過來卻不成立——圓盤和多邊形相交,多邊形的邊和圓周不一定規範相交。
(1)即使完全沒有公共點的時候,圓盤和多邊形也可以相交,原因是二者可以相互內含。因此,需要判斷多邊形是否有頂點在圓內,還需要判斷圓心是否在多邊形內。
(2)如果是非規範相交,需要分情況討論。在圖中,待判斷的線段(用粗線表示)完全在圓外;在圖中待判斷的線段則是完全在內部。判斷方法很簡單,只需判斷線段中點是否在圓內即可。
直接切割多邊形~ 判斷多邊形和園盤是否有公共點(面積>0)
1 內含的情況--只要多邊形poly[0] 在圓內、或者圓心在多邊形內
2 相交的情況-如果不是規範相交,那麼不是內含,卻有非零公共面積只有一種情況,就是兩個點都在圓上,只有判斷中點在圓上即可。
每一個案例忘記輸出空行 並不提示Presentation Error ,wa每次pieces更新的時候,newpieces 需要清零
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<cctype> #include<string> #include<set> #include<map> #include<queue> #include<stack> #include<vector> using namespace std; const double eps=1e-6; int dcmp(double x) { if(fabs(x)<eps) return 0; return x>0?1:-1; //return fabs(x) < eps ? 0 : (x > 0 ? 1 : -1); } struct point { double x; double y; point(){} point(double x,double y):x(x),y(y){} void in() { cin>>x>>y; } void out() { cout<<x<<' '<<y<<endl; } point operator + (const point &t) const { return point(x+t.x,y+t.y); } point operator - (const point &t) const { return point(x-t.x,y-t.y); } point operator * (const double &t) const { return point(x*t,y*t); } point operator / (const double &t) const { return point(x/t,y/t); } bool operator < (const point &t) const { return (dcmp(x-t.x)<0||(dcmp(x-t.x)==0&&dcmp(y-t.y)<0)); } bool operator == (const point &t) const { return dcmp(x-t.x) ==0 &&dcmp(y-t.y)==0; } }; double cross(point a,point b) { return a.x*b.y-a.y*b.x; } double dot(point a,point b) { return a.x*b.x+a.y*b.y; } double length(point a) { return sqrt(dot(a,a)); } point nomal(point t) { double l=length(t); return point(-t.y/l,t.x/l); } struct line { point p; point v; double ang; line() {} line(point p,point v):p(p),v(v){ ang=atan2(v.y,v.x); } bool operator < (const line &l) const { return ang<l.ang; } point ppoint(double t) { return point(p+v*t); } }; struct Circle { point c; double r; Circle(point c=point(0,0),double r=0):c(c),r(r) {} point ppoint(double a) { return point(c.x+r*cos(a),c.y+r*sin(a)); } }; int getLineCircleIntersection(line l,Circle C,double &t1,double &t2,vector<point> &sol) { double a=l.v.x; double b=l.p.x-C.c.x; double c=l.v.y; double d=l.p.y-C.c.y; double e=a*a+c*c; double f=2*(a*b+c*d); double g=b*b+d*d-C.r*C.r; double delta=f*f-4*e*g; if(dcmp(delta)<0) return 0; if(dcmp(delta)==0) { t1=t2=-f/(2*e); sol.push_back(l.ppoint(t1)); return 1; } else { t1=(-f-sqrt(delta))/(2*e); t2=(-f+sqrt(delta))/(2*e); sol.push_back(l.ppoint(t1)); sol.push_back(l.ppoint(t2)); return 2; } } bool onleft(line l,point p) { return cross(l.v,p-l.p)>0; } point getintersection(line a,line b) { point u=a.p-b.p; double t=cross(b.v,u)/cross(a.v,b.v); return a.p+a.v*t; } bool sgementproperintersection(point a1,point a2,point b1,point b2) { double c1=cross(a2-a1,b1-a1),c2=cross(a2-a1,b2-a1), c3=cross(b2-b1,a1-b1),c4=cross(b2-b1,a2-b1); return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0; } bool onsegment(point p,point a1,point a2) { return dcmp(cross(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<0; } typedef vector<point> Polygon; double PolygonArea(Polygon poly) { double area=0; int n=poly.size(); for(int i=1;i<n-1;i++) { area+=cross(poly[i]-poly[0],poly[(i+1)%n]-poly[0]); } return area/2; } vector<Polygon> pieces,newpieces; Polygon CutPolygon(Polygon poly,point a,point b) { Polygon newPoly; int n=poly.size(); for(int i=0;i<n;i++) { point c=poly[i]; point d=poly[(i+1)%n]; if(dcmp(cross(b-a,c-a))>=0) newPoly.push_back(c); if(dcmp(cross(b-a,d-c))!=0) { point ip=getintersection(line(c,d-c),line(a,b-a)); if(onsegment(ip,c,d)) newPoly.push_back(ip); //此時必須用不含端點的“線上段上" } } return newPoly; } void cut(point a,point b) { newpieces.clear(); //僅僅是一個temp 記得清空 for(int i=0;i<pieces.size();i++) { Polygon poly=pieces[i]; Polygon left=CutPolygon(poly,a,b); Polygon right=CutPolygon(poly,b,a); if(left.size()>=3) newpieces.push_back(left); if(right.size()>=3) newpieces.push_back(right); } pieces=newpieces; } bool isPointInPolygon(point p,Polygon poly) { int wn=0; int n=poly.size(); for(int i=0;i<n;i++) { if(onsegment(p,poly[i],poly[(i+1)%n])) return -1; int k=dcmp(cross(poly[(i+1)%n]-poly[i],p-poly[i])); int d1=dcmp(poly[i].y-p.y); int d2=dcmp(poly[(i+1)%n].y-p.y); if(k>0&&d1<=0&&d2>0) wn++; if(k<0&&d2<=0&&d1>0) wn--; } if(wn!=0) return 1; else return 0; } double length2(point a) { return dot(a,a); } bool inCircle(Circle C,point p) //圓周不算 { if(dcmp(length2(p-C.c)-C.r*C.r)<0) return 1; else return 0; } bool CircleSegIntersection(Circle C,point a,point b) //線段端點不算 { double t1,t2; vector<point> sol; if(getLineCircleIntersection(line(a,b-a),C,t1,t2,sol)<=1) return 0; if(dcmp(t1)>0&&dcmp(t1-1)<0) return 1; if(dcmp(t2)>0&&dcmp(t2-1)<0) return 1; return 0; } bool CirclePolyIntersection(Circle C,Polygon poly) { if(isPointInPolygon(C.c,poly)) return 1; if(inCircle(C,poly[0])) return 1; point a,b; int n=poly.size(); for(int i=0;i<n;i++) { a=poly[i]; b=poly[(i+1)%n]; if(CircleSegIntersection(C,a,b)) return 1; if(inCircle(C,(a+b)/2)) return 1; } return 0; } void Query(Circle circle) { vector<double> ans; for(int i=0;i<pieces.size();i++) if(CirclePolyIntersection(circle,pieces[i])) { ans.push_back(fabs(PolygonArea(pieces[i]))); } sort(ans.begin(),ans.end()); cout<<ans.size(); for(int i=0;i<ans.size();i++) { printf(" %.2f",ans[i]); } cout<<endl; } int main() { int n,m,l,w; Circle C; while(cin>>n>>m>>l>>w) { if(!n) break; pieces.clear(); Polygon bbox; bbox.push_back(point(0,0)); bbox.push_back(point(l,0)); bbox.push_back(point(l,w)); bbox.push_back(point(0,w)); pieces.push_back(bbox); point a,b; for(int i=0;i<n;i++) { a.in(); b.in(); cut(a,b); } for(int i=0;i<m;i++) { cin>>C.c.x>>C.c.y>>C.r; Query(C); } printf("\n"); } return 0; }