题意:
有个矩形,左下角(0,0),左上角(L,W).
思路:
除了圆盘之外,本题的输入也是个PSLG,因此可以按照前面叙述的算法求出各个区域:只需把线段视为直线,用切割凸多边形的方法 :每次读入线段,切割所有块,最终得到若干凸多边形
如何判断多边形是否与圆盘相交:如果多边形的边和圆周规范相交,圆盘和多边形一定相交,
1:即使完全没有公共点,也可以相交,互相内含 需要判断多边形是否有顶点在园内,还需要判断圆心是否在多边形内;
2.如果不规范: a:带判断的线段在园外;
b:带判断的线段在园内即两个端点在圆上,只需要判断中点是否在园内;
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<memory.h> 7 #include<cstdlib> 8 #include<vector> 9 #define clc(a,b) memset(a,b,sizeof(a)) 10 #define LL long long int 11 #define up(i,x,y) for(i=x;i<=y;i++) 12 #define w(a) while(a) 13 const double inf=0x3f3f3f3f; 14 const double eps = 1e-8; 15 const double PI = acos(-1.0); 16 using namespace std; 17 18 double dcmp(double x) 19 { 20 if(fabs(x) < eps) return 0; 21 else return x < 0 ? -1 : 1; 22 } 23 24 struct Point 25 { 26 double x, y; 27 Point(double x=0, double y=0):x(x),y(y) { } 28 }; 29 30 typedef Point Vector; 31 32 typedef vector<Point> Polygon; 33 34 Vector operator + (Vector A, Vector B) 35 { 36 return Vector(A.x+B.x, A.y+B.y); 37 } 38 39 Vector operator - (Point A, Point B) 40 { 41 return Vector(A.x-B.x, A.y-B.y); 42 } 43 44 Vector operator * (Vector A, double p) 45 { 46 return Vector(A.x*p, A.y*p); 47 } 48 49 double Dot(Vector A, Vector B) 50 { 51 return A.x*B.x + A.y*B.y; 52 } 53 double Cross(Vector A, Vector B) 54 { 55 return A.x*B.y - A.y*B.x; 56 } 57 double Length2(Vector A) 58 { 59 return Dot(A, A); 60 } 61 62 Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) 63 { 64 Vector u = P-Q; 65 double t = Cross(w, u) / Cross(v, w); 66 return P+v*t; 67 } 68 69 bool OnSegment(Point p, Point a1, Point a2) 70 { 71 return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0; 72 } 73 74 // 多边形的有向面积 75 double PolygonArea(Polygon poly) 76 { 77 double area = 0; 78 int n = poly.size(); 79 for(int i = 1; i < n-1; i++) 80 area += Cross(poly[i]-poly[0], poly[(i+1)%n]-poly[0]); 81 return area/2; 82 } 83 84 // cut with directed line A->B, return the left part 85 // may return a single point or a line segment 86 Polygon CutPolygon(Polygon poly, Point A, Point B) 87 { 88 Polygon newpoly; 89 int n = poly.size(); 90 for(int i = 0; i < n; i++) 91 { 92 Point C = poly[i]; 93 Point D = poly[(i+1)%n]; 94 if(dcmp(Cross(B-A, C-A)) >= 0) newpoly.push_back(C); 95 if(dcmp(Cross(B-A, C-D)) != 0) 96 { 97 Point ip = GetLineIntersection(A, B-A, C, D-C); 98 if(OnSegment(ip, C, D)) newpoly.push_back(ip); 99 } 100 } 101 return newpoly; 102 } 103 104 int isPointInPolygon(Point p, Polygon v) 105 { 106 int wn = 0; 107 int n = v.size(); 108 for(int i = 0; i < n; i++) 109 { 110 if(OnSegment(p, v[i], v[(i+1)%n])) return -1; // 在边界上 111 int k = dcmp(Cross(v[(i+1)%n]-v[i], p-v[i])); 112 int d1 = dcmp(v[i].y - p.y); 113 int d2 = dcmp(v[(i+1)%n].y - p.y); 114 if(k > 0 && d1 <= 0 && d2 > 0) wn++; 115 if(k < 0 && d2 <= 0 && d1 > 0) wn--; 116 } 117 if (wn != 0) return 1; // 内部 118 return 0; // 外部 119 } 120 121 // 点在圆心内。圆周上不算 122 bool isInCircle(Point p, Point center, double R) 123 { 124 return dcmp(Length2(p-center) - R*R) < 0; 125 } 126 127 // 直线AB和圆心为C,半径为r的圆的交点 128 // 返回交点个数,t1, t2分别为两个交点在直线方程中的参数,p1和p2为交点本身 129 int getLineCircleIntersection(Point A, Point B, Point C, double r, double& t1, double& t2) 130 { 131 // 初始方程:(A.x + t(B.x - A.x) - C.x)^2 + (A.y + t(B.y - A.y) - C.y)^2 = r^2 132 // 整理得:(at + b)^2 + (ct + d)^2 = r^2 133 double a = B.x - A.x; 134 double b = A.x - C.x; 135 double c = B.y - A.y; 136 double d = A.y - C.y; 137 // 展开得:(a^2 + c^2)t^2 + 2(ab + cd)t + b^2 + d^2 - r^2 = 0,即et^2 + ft + g = 0 138 double e = a * a + c * c; 139 double f = 2 * (a * b + c * d); 140 double g = b * b + d * d - r * r; 141 double delta = f * f - 4 * e * g; // 判别式 142 if(dcmp(delta) < 0) return 0; // 相离 143 if(dcmp(delta) == 0) // 相切 144 { 145 t1 = t2 = -f / (2 * e); 146 return 1; 147 } 148 t1 = (-f - sqrt(delta)) / (2 * e); 149 t2 = (-f + sqrt(delta)) / (2 * e); 150 return 2; 151 } 152 153 // 圆和线段是否相交(相切不算)。线段不考虑端点 154 bool CircleIntersectSegment(Point A, Point B, Point p, double R) 155 { 156 double t1, t2; 157 int c = getLineCircleIntersection(A, B, p, R, t1, t2); 158 if(c <= 1) return false; 159 if(dcmp(t1) > 0 && dcmp(t1-1) < 0) return true; // 端点在圆上 160 if(dcmp(t2) > 0 && dcmp(t2-1) < 0) return true; 161 return false; 162 } 163 164 /////////// 题目相关 165 vector<Polygon> pieces, new_pieces; 166 167 void cut(int x1, int y1, int x2, int y2) 168 { 169 new_pieces.clear(); 170 for(int i = 0; i < pieces.size(); i++) 171 { 172 Polygon left = CutPolygon(pieces[i], Point(x1, y1), Point(x2, y2)); 173 Polygon right = CutPolygon(pieces[i], Point(x2, y2), Point(x1, y1)); 174 if(left.size() >= 3) new_pieces.push_back(left); 175 if(right.size() >= 3) new_pieces.push_back(right); 176 } 177 pieces = new_pieces; 178 } 179 180 bool DiscIntersectPolygon(Polygon poly, Point p, double R) 181 { 182 if(isPointInPolygon(p, poly) != 0) return true; 183 if(isInCircle(poly[0], p, R)) return true; 184 int n = poly.size(); 185 for(int i = 0; i < n; i++) 186 { 187 if(CircleIntersectSegment(poly[i], poly[(i+1)%n], p, R)) 188 { 189 return true; // 不考虑线段端点 190 } 191 if(isInCircle((poly[i]+poly[(i+1)%n])*0.5, p, R)) 192 { 193 return true; // 两个端点都在圆上 194 } 195 } 196 return false; 197 } 198 199 void query(Point p, int R) 200 { 201 vector<double> ans; 202 for(int i = 0; i < pieces.size(); i++) 203 { 204 if(DiscIntersectPolygon(pieces[i], p, R)) 205 { 206 ans.push_back(fabs(PolygonArea(pieces[i]))); 207 } 208 } 209 printf("%d", ans.size()); 210 sort(ans.begin(), ans.end()); 211 for(int i = 0; i < ans.size(); i++) 212 printf(" %.2lf", ans[i]); 213 printf(" "); 214 } 215 216 int main() 217 { 218 int n, m, L, W; 219 while(scanf("%d%d%d%d", &n, &m, &L, &W) == 4 && n) 220 { 221 pieces.clear(); 222 223 Polygon bbox; 224 bbox.push_back(Point(0, 0)); 225 bbox.push_back(Point(L, 0)); 226 bbox.push_back(Point(L, W)); 227 bbox.push_back(Point(0, W)); 228 pieces.push_back(bbox); 229 230 for(int i = 0; i < n; i++) 231 { 232 int x1, y1, x2, y2; 233 scanf("%d%d%d%d", &x1, &y1, &x2, &y2); 234 cut(x1, y1, x2, y2); 235 } 236 237 for(int i = 0; i < m; i++) 238 { 239 int x, y, R; 240 scanf("%d%d%d", &x, &y, &R); 241 query(Point(x, y), R); 242 } 243 printf(" "); 244 } 245 return 0; 246 }