【几何】【凸包】【模板】POJ1584 - A Round Peg in a Ground Hole

A Round Peg in a Ground Hole
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 7061   Accepted: 2297

Description

The DIY Furniture company specializes in assemble-it-yourself furniture kits. Typically, the pieces of wood are attached to one another using a wooden peg that fits into pre-cut holes in each piece to be attached. The pegs have a circular cross-section and so are intended to fit inside a round hole.
A recent factory run of computer desks were flawed when an automatic grinding machine was mis-programmed. The result is an irregularly shaped hole in one piece that, instead of the expected circular shape, is actually an irregular polygon. You need to figure out whether the desks need to be scrapped or if they can be salvaged by filling a part of the hole with a mixture of wood shavings and glue.
There are two concerns. First, if the hole contains any protrusions (i.e., if there exist any two interior points in the hole that, if connected by a line segment, that segment would cross one or more edges of the hole), then the filled-in-hole would not be structurally sound enough to support the peg under normal stress as the furniture is used. Second, assuming the hole is appropriately shaped, it must be big enough to allow insertion of the peg. Since the hole in this piece of wood must match up with a corresponding hole in other pieces, the precise location where the peg must fit is known.
Write a program to accept descriptions of pegs and polygonal holes and determine if the hole is ill-formed and, if not, whether the peg will fit at the desired location. Each hole is described as a polygon with vertices (x1, y1), (x2, y2), . . . , (xn, yn). The edges of the polygon are (xi, yi) to (xi+1, yi+1) for i = 1 . . . n − 1 and (xn, yn) to (x1, y1).

Input

Input consists of a series of piece descriptions. Each piece description consists of the following data:
Line 1 < nVertices > < pegRadius > < pegX > < pegY >
number of vertices in polygon, n (integer)
radius of peg (real)
X and Y position of peg (real)
n Lines < vertexX > < vertexY >
On a line for each vertex, listed in order, the X and Y position of vertex The end of input is indicated by a number of polygon vertices less than 3.

Output

For each piece description, print a single line containing the string:
HOLE IS ILL-FORMED if the hole contains protrusions
PEG WILL FIT if the hole contains no protrusions and the peg fits in the hole at the indicated position
PEG WILL NOT FIT if the hole contains no protrusions but the peg will not fit in the hole at the indicated position

Sample Input

5 1.5 1.5 2.0
1.0 1.0
2.0 2.0
1.75 2.0
1.0 3.0
0.0 2.0
5 1.5 1.5 2.0
1.0 1.0
2.0 2.0
1.75 2.5
1.0 3.0
0.0 2.0
1

Sample Output

HOLE IS ILL-FORMED
PEG WILL NOT FIT

Solution

题意:已知一个多边形的n个顶点坐标,然后再给一个钉子,给定钉子的半径和圆心坐标,首先判断多边形是否为凸多边形,若为凸多边形,再判断钉子是否可以放到凸多边形内部。

思路:

先判断给定多边形是否为凸多边形。可以直接求凸包(凸包上可以有连续三点共线)后再判断凸包上点的个数是否小于n,复杂度O(nlogn)。也可以判断所有相邻边的叉积是否同号(偏转方向相同),复杂度O(nlogn)。

再判断给定的钉子是否在多边形内。可以二分判断一个点是否在凸包内,不详述原理,复杂度O(nlogn)。也可以用转角法判断一个点是否在多边形内(不管是不是凸包),复杂度O(n)。也可以用叉积判断所有角度正负,复杂度O(n)。

下面是我的某个版本的代码(多边形部分自己写的,不保证正确):

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <vector>
  5 #include <algorithm>
  6 #include <iomanip>
  7 #define MAX_N 100
  8 using namespace std;
  9 
 10 
 11 ///////////////////////////////////////////////////////////////////
 12 //常量区
 13 const double INF        = 1e12;     // 无穷大
 14 const double EPS        = 1e-9;    // 计算精度
 15 const int LEFT          = 0;        // 点在直线左边
 16 const int RIGHT         = 1;        // 点在直线右边
 17 const int ONLINE        = 2;        // 点在直线上
 18 const int CROSS         = 0;        // 两直线相交
 19 const int COLINE        = 1;        // 两直线共线
 20 const int PARALLEL      = 2;        // 两直线平行
 21 const int NOTCOPLANAR   = 3;        // 两直线不共面
 22 const int INSIDE        = 1;        // 点在图形内部
 23 const int OUTSIDE       = 2;        // 点在图形外部
 24 const int BORDER        = 3;        // 点在图形边界
 25 const int BAOHAN        = 1;        // 大圆包含小圆
 26 const int NEIQIE        = 2;        // 内切
 27 const int XIANJIAO      = 3;        // 相交
 28 const int WAIQIE        = 4;        // 外切
 29 const int XIANGLI       = 5;        // 相离
 30 const double pi         = acos(-1.0);  //圆周率
 31 ///////////////////////////////////////////////////////////////////
 32 
 33 
 34 ///////////////////////////////////////////////////////////////////
 35 //类型定义区
 36 struct Point {              // 二维点或矢量
 37     double x, y;
 38     Point() {}
 39     Point(double x0, double y0): x(x0), y(y0) {}
 40 };
 41 struct Point3D {            //三维点或矢量
 42     double x, y, z;
 43     Point3D() {}
 44     Point3D(double x0, double y0, double z0): x(x0), y(y0), z(z0) {}
 45 };
 46 struct Line {               // 二维的直线或线段
 47     Point p1, p2;
 48     Line() {}
 49     Line(Point p10, Point p20): p1(p10), p2(p20) {}
 50 };
 51 struct Line3D {             // 三维的直线或线段
 52     Point3D p1, p2;
 53     Line3D() {}
 54     Line3D(Point3D p10, Point3D p20): p1(p10), p2(p20) {}
 55 };
 56 struct Rect {              // 用长宽表示矩形的方法 w, h分别表示宽度和高度
 57     double w, h;
 58  Rect() {}
 59  Rect(double _w,double _h) : w(_w),h(_h) {}
 60 };
 61 struct Rect_2 {             // 表示矩形,左下角坐标是(xl, yl),右上角坐标是(xh, yh)
 62     double xl, yl, xh, yh;
 63  Rect_2() {}
 64  Rect_2(double _xl,double _yl,double _xh,double _yh) : xl(_xl),yl(_yl),xh(_xh),yh(_yh) {}
 65 };
 66 struct Circle {            //
 67  Point c;
 68  double r;
 69  Circle() {}
 70  Circle(Point _c,double _r) :c(_c),r(_r) {}
 71 };
 72 typedef vector<Point> Polygon;      // 二维多边形
 73 typedef vector<Point> Points;       // 二维点集
 74 typedef vector<Point3D> Points3D;   // 三维点集
 75 ///////////////////////////////////////////////////////////////////
 76 
 77 
 78 ///////////////////////////////////////////////////////////////////
 79 //基本函数区
 80 inline double max(double x,double y)
 81 {
 82     return x > y ? x : y;
 83 }
 84 inline double min(double x, double y)
 85 {
 86     return x > y ? y : x;
 87 }
 88 inline bool ZERO(double x)              // x == 0
 89 {
 90     return (fabs(x) < EPS);
 91 }
 92 inline bool ZERO(Point p)               // p == 0
 93 {
 94     return (ZERO(p.x) && ZERO(p.y));
 95 }
 96 inline bool ZERO(Point3D p)              // p == 0
 97 {
 98     return (ZERO(p.x) && ZERO(p.y) && ZERO(p.z));
 99 }
100 inline bool EQ(double x, double y)      // eqaul, x == y
101 {
102     return (fabs(x - y) < EPS);
103 }
104 inline bool NEQ(double x, double y)     // not equal, x != y
105 {
106     return (fabs(x - y) >= EPS);
107 }
108 inline bool LT(double x, double y)     // less than, x < y
109 {
110     return ( NEQ(x, y) && (x < y) );
111 }
112 inline bool GT(double x, double y)     // greater than, x > y
113 {
114     return ( NEQ(x, y) && (x > y) );
115 }
116 inline bool LEQ(double x, double y)     // less equal, x <= y
117 {
118     return ( EQ(x, y) || (x < y) );
119 }
120 inline bool GEQ(double x, double y)     // greater equal, x >= y
121 {
122     return ( EQ(x, y) || (x > y) );
123 }
124 inline int dSign(double x){
125     if(ZERO(x)) return 0;
126     return x > 0 ? 1 : -1;
127 }
128 // 注意!!!
129 // 如果是一个很小的负的浮点数
130 // 保留有效位数输出的时候会出现-0.000这样的形式,
131 // 前面多了一个负号
132 // 这就会导致错误!!!!!!
133 // 因此在输出浮点数之前,一定要调用次函数进行修正!
134 inline double FIX(double x)
135 {
136     return (fabs(x) < EPS) ? 0 : x;
137 }
138 //////////////////////////////////////////////////////////////////////////////////////
139 
140 
141 /////////////////////////////////////////////////////////////////////////////////////
142 //二维矢量运算
143 bool operator==(Point p1, Point p2)
144 {
145     return ( EQ(p1.x, p2.x) &&  EQ(p1.y, p2.y) );
146 }
147 bool operator!=(Point p1, Point p2)
148 {
149     return ( NEQ(p1.x, p2.x) ||  NEQ(p1.y, p2.y) );
150 }
151 bool operator<(Point p1, Point p2)
152 {
153     if (NEQ(p1.x, p2.x)) {
154         return (p1.x < p2.x);
155     } else {
156         return (p1.y < p2.y);
157     }
158 }
159 Point operator+(Point p1, Point p2)
160 {
161     return Point(p1.x + p2.x, p1.y + p2.y);
162 }
163 Point operator-(Point p1, Point p2)
164 {
165     return Point(p1.x - p2.x, p1.y - p2.y);
166 }
167 double operator*(Point p1, Point p2) // 计算叉乘 p1 × p2
168 {
169     return (p1.x * p2.y - p2.x * p1.y);
170 }
171 double operator&(Point p1, Point p2) { // 计算点积 p1·p2
172     return (p1.x * p2.x + p1.y * p2.y);
173 }
174 double Norm(Point p) // 计算矢量p的模
175 {
176     return sqrt(p.x * p.x + p.y * p.y);
177 }
178 // 把矢量p旋转角度angle (弧度表示)
179 // angle > 0表示逆时针旋转
180 // angle < 0表示顺时针旋转
181 Point Rotate(Point p, double angle)
182 {
183     Point result;
184     result.x = p.x * cos(angle) - p.y * sin(angle);
185     result.y = p.x * sin(angle) + p.y * cos(angle);
186     return result;
187 }
188 //////////////////////////////////////////////////////////////////////////////////////
189 
190 
191 //////////////////////////////////////////////////////////////////////////////////////
192 //三维矢量运算
193 bool operator==(Point3D p1, Point3D p2)
194 {
195     return ( EQ(p1.x, p2.x) && EQ(p1.y, p2.y) && EQ(p1.z, p2.z) );
196 }
197 bool operator<(Point3D p1, Point3D p2)
198 {
199     if (NEQ(p1.x, p2.x)) {
200         return (p1.x < p2.x);
201     } else if (NEQ(p1.y, p2.y)) {
202         return (p1.y < p2.y);
203     } else {
204         return (p1.z < p2.z);
205     }
206 }
207 Point3D operator+(Point3D p1, Point3D p2)
208 {
209     return Point3D(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
210 }
211 Point3D operator-(Point3D p1, Point3D p2)
212 {
213     return Point3D(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z);
214 }
215 Point3D operator*(Point3D p1, Point3D p2) // 计算叉乘 p1 x p2
216 {
217     return Point3D(p1.y * p2.z - p1.z * p2.y,
218         p1.z * p2.x - p1.x * p2.z,
219         p1.x * p2.y - p1.y * p2.x );
220 }
221 double operator&(Point3D p1, Point3D p2) { // 计算点积 p1·p2
222     return (p1.x * p2.x + p1.y * p2.y + p1.z * p2.z);
223 }
224 double Norm(Point3D p) // 计算矢量p的模
225 {
226     return sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
227 }
228 
229 
230 //////////////////////////////////////////////////////////////////////////////////////
231 
232 
233 /////////////////////////////////////////////////////////////////////////////////////
234 //点.线段.直线问题
235 //
236 double Distance(Point p1, Point p2) //2点间的距离
237 {
238  return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
239 }
240 double Distance(Point3D p1, Point3D p2) //2点间的距离,三维
241 {
242  return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z));
243 }
244 double Distance(Point p, Line L) // 求二维平面上点到直线的距离
245 {
246     return ( fabs((p - L.p1) * (L.p2 - L.p1)) / Norm(L.p2 - L.p1) );
247 }
248 double Distance(Point3D p, Line3D L)// 求三维空间中点到直线的距离
249 {
250     return ( Norm((p - L.p1) * (L.p2 - L.p1)) / Norm(L.p2 - L.p1) );
251 }
252 bool OnLine(Point p, Line L) // 判断二维平面上点p是否在直线L上
253 {
254     return ZERO( (p - L.p1) * (L.p2 - L.p1) );
255 }
256 bool OnLine(Point3D p, Line3D L) // 判断三维空间中点p是否在直线L上
257 {
258     return ZERO( (p - L.p1) * (L.p2 - L.p1) );
259 }
260 int Relation(Point p, Line L) // 计算点p与直线L的相对关系 ,返回ONLINE,LEFT,RIGHT
261 {
262     double res = (L.p2 - L.p1) * (p - L.p1);
263     if (EQ(res, 0)) {
264         return ONLINE;
265     } else if (res > 0) {
266         return LEFT;
267     } else {
268         return RIGHT;
269     }
270 }
271 bool SameSide(Point p1, Point p2, Line L) // 判断点p1, p2是否在直线L的同侧
272 {
273     double m1 = (p1 - L.p1) * (L.p2 - L.p1);
274     double m2 = (p2 - L.p1) * (L.p2 - L.p1);
275     return GT(m1 * m2, 0);
276 }
277 bool IsPointOnLineSeg(Point p, Line L) // 判断二维平面上点p是否在线段l上
278 {
279     return ( ZERO( (L.p1 - p) * (L.p2 - p) ) &&
280         LEQ((p.x - L.p1.x)*(p.x - L.p2.x), 0) &&
281         LEQ((p.y - L.p1.y)*(p.y - L.p2.y), 0) );
282 }
283 bool IsPointOnLineSeg(Point3D p, Line3D L) // 判断三维空间中点p是否在线段l上
284 {
285     return ( ZERO((L.p1 - p) * (L.p2 - p)) &&
286         EQ( Norm(p - L.p1) + Norm(p - L.p2), Norm(L.p2 - L.p1)) );
287 }
288 Point SymPoint(Point p, Line L) // 求二维平面上点p关于直线L的对称点
289 {
290     Point result;
291     double a = L.p2.x - L.p1.x;
292     double b = L.p2.y - L.p1.y;
293     double t = ( (p.x - L.p1.x) * a + (p.y - L.p1.y) * b ) / (a*a + b*b);
294     result.x = 2 * L.p1.x + 2 * a * t - p.x;
295     result.y = 2 * L.p1.y + 2 * b * t - p.y;
296     return result;
297 }
298 bool Coplanar(Points3D points) // 判断一个点集中的点是否全部共面
299 {
300     int i;
301     Point3D p;
302 
303 
304     if (points.size() < 4) return true;
305     p = (points[2] - points[0]) * (points[1] - points[0]);
306     for (i = 3; i < points.size(); i++) {
307         if (! ZERO(p & points[i]) ) return false;
308     }
309     return true;
310 }
311 bool LineIntersect(Line L1, Line L2) // 判断二维的两直线是否相交
312 {
313     return (! ZERO((L1.p1 - L1.p2)*(L2.p1 - L2.p2)) );  // 是否平行
314 }
315 bool LineIntersect(Line3D L1, Line3D L2) // 判断三维的两直线是否相交
316 {
317     Point3D p1 = L1.p1 - L1.p2;
318     Point3D p2 = L2.p1 - L2.p2;
319     Point3D p  = p1 * p2;
320     if (ZERO(p)) return false;      // 是否平行
321     p = (L2.p1 - L1.p2) * (L1.p1 - L1.p2);
322     return ZERO(p & L2.p2);         // 是否共面
323 }
324 bool LineSegIntersect(Line L1, Line L2) // 判断二维的两条线段是否相交
325 {
326     return ( GEQ( max(L1.p1.x, L1.p2.x), min(L2.p1.x, L2.p2.x) ) &&
327         GEQ( max(L2.p1.x, L2.p2.x), min(L1.p1.x, L1.p2.x) ) &&
328         GEQ( max(L1.p1.y, L1.p2.y), min(L2.p1.y, L2.p2.y) ) &&
329         GEQ( max(L2.p1.y, L2.p2.y), min(L1.p1.y, L1.p2.y) ) &&
330         LEQ( ((L2.p1 - L1.p1) * (L1.p2 - L1.p1)) * ((L2.p2 -  L1.p1) * (L1.p2 - L1.p1)), 0 ) &&
331         LEQ( ((L1.p1 - L2.p1) * (L2.p2 - L2.p1)) * ((L1.p2 -  L2.p1) * (L2.p2 - L2.p1)), 0 ) );
332 }
333 bool LineSegIntersect(Line3D L1, Line3D L2) // 判断三维的两条线段是否相交
334 {
335     // todo
336     return true;
337 }
338 // 计算两条二维直线的交点,结果在参数P中返回
339 // 返回值说明了两条直线的位置关系:  COLINE   -- 共线  PARALLEL -- 平行  CROSS    -- 相交
340 int CalCrossPoint(Line L1, Line L2, Point& P)
341 {
342     double A1, B1, C1, A2, B2, C2;
343 
344 
345     A1 = L1.p2.y - L1.p1.y;
346     B1 = L1.p1.x - L1.p2.x;
347     C1 = L1.p2.x * L1.p1.y - L1.p1.x * L1.p2.y;
348 
349 
350     A2 = L2.p2.y - L2.p1.y;
351     B2 = L2.p1.x - L2.p2.x;
352     C2 = L2.p2.x * L2.p1.y - L2.p1.x * L2.p2.y;
353 
354 
355     if (EQ(A1 * B2, B1 * A2))    {
356         if (EQ( (A1 + B1) * C2, (A2 + B2) * C1 )) {
357             return COLINE;
358         } else {
359             return PARALLEL;
360         }
361     } else {
362         P.x = (B2 * C1 - B1 * C2) / (A2 * B1 - A1 * B2);
363         P.y = (A1 * C2 - A2 * C1) / (A2 * B1 - A1 * B2);
364         return CROSS;
365     }
366 }
367 // 计算两条三维直线的交点,结果在参数P中返回
368 // 返回值说明了两条直线的位置关系 COLINE   -- 共线  PARALLEL -- 平行  CROSS    -- 相交  NONCOPLANAR -- 不公面
369 int CalCrossPoint(Line3D L1, Line3D L2, Point3D& P)
370 {
371     // todo
372     return 0;
373 }
374 // 计算点P到直线L的最近点
375 Point NearestPointToLine(Point P, Line L)
376 {
377     Point result;
378     double a, b, t;
379 
380     a = L.p2.x - L.p1.x;
381     b = L.p2.y - L.p1.y;
382     t = ( (P.x - L.p1.x) * a + (P.y - L.p1.y) * b ) / (a * a + b * b);
383 
384     result.x = L.p1.x + a * t;
385     result.y = L.p1.y + b * t;
386     return result;
387 }
388 // 计算点P到线段L的最近点
389 Point NearestPointToLineSeg(Point P, Line L)
390 {
391     Point result;
392     double a, b, t;
393 
394     a = L.p2.x - L.p1.x;
395     b = L.p2.y - L.p1.y;
396     t = ( (P.x - L.p1.x) * a + (P.y - L.p1.y) * b ) / (a * a + b * b);
397 
398     if ( GEQ(t, 0) && LEQ(t, 1) ) {
399         result.x = L.p1.x + a * t;
400         result.y = L.p1.y + b * t;
401     } else {
402         if ( Norm(P - L.p1) < Norm(P - L.p2) ) {
403             result = L.p1;
404         } else {
405             result = L.p2;
406         }
407     }
408     return result;
409 }
410 // 计算险段L1到线段L2的最短距离
411 double MinDistance(Line L1, Line L2)
412 {
413     double d1, d2, d3, d4;
414 
415 
416     if (LineSegIntersect(L1, L2)) {
417         return 0;
418     } else {
419         d1 = Norm( NearestPointToLineSeg(L1.p1, L2) - L1.p1 );
420         d2 = Norm( NearestPointToLineSeg(L1.p2, L2) - L1.p2 );
421         d3 = Norm( NearestPointToLineSeg(L2.p1, L1) - L2.p1 );
422         d4 = Norm( NearestPointToLineSeg(L2.p2, L1) - L2.p2 );
423 
424         return min( min(d1, d2), min(d3, d4) );
425     }
426 }
427 // 求二维两直线的夹角,
428 // 返回值是0~Pi之间的弧度
429 double Inclination(Line L1, Line L2)
430 {
431     Point u = L1.p2 - L1.p1;
432     Point v = L2.p2 - L2.p1;
433     return acos( (u & v) / (Norm(u)*Norm(v)) );
434 }
435 // 求三维两直线的夹角,
436 // 返回值是0~Pi之间的弧度
437 double Inclination(Line3D L1, Line3D L2)
438 {
439     Point3D u = L1.p2 - L1.p1;
440     Point3D v = L2.p2 - L2.p1;
441     return acos( (u & v) / (Norm(u)*Norm(v)) );
442 }
443 /////////////////////////////////////////////////////////////////////////////
444 
445 
446 /////////////////////////////////////////////////////////////////////////////
447 // 判断两个矩形是否相交
448 // 如果相邻不算相交
449 bool Intersect(Rect_2 r1, Rect_2 r2)
450 {
451     return ( max(r1.xl, r2.xl) < min(r1.xh, r2.xh) &&
452              max(r1.yl, r2.yl) < min(r1.yh, r2.yh) );
453 }
454 // 判断矩形r2是否可以放置在矩形r1内
455 // r2可以任意地旋转
456 //发现原来的给出的方法过不了OJ上的无归之室这题,
457 //所以用了自己的代码
458 bool IsContain(Rect r1, Rect r2)      //矩形的w>h
459  {
460      if(r1.w >r2.w && r1.h > r2.h) return true;
461      else
462      {
463         double r = sqrt(r2.w*r2.w + r2.h*r2.h) / 2.0;
464         double alpha = atan2(r2.h,r2.w);
465         double sita = asin((r1.h/2.0)/r);
466         double x = r * cos(sita - 2*alpha);
467         double y = r * sin(sita - 2*alpha);
468         if(x < r1.w/2.0 && y < r1.h/2.0 && x > 0 && y > -r1.h/2.0) return true;
469         else return false;
470      }
471 }
472 
473 
474 ////////////////////////////////////////////////////////////////////////
475 /**圆**/
476 
477 
478 Point Center(const Circle & C) //圆心
479 {
480     return C.c;
481 }
482 
483 double Area(const Circle &C)
484 {
485  return pi*C.r*C.r;
486 }
487 
488 double CommonArea(const Circle & A, const Circle & B) //两个圆的公共面积
489 {
490     double area = 0.0;
491     const Circle & M = (A.r > B.r) ? A : B;
492     const Circle & N = (A.r > B.r) ? B : A;
493     double D = Distance(Center(M), Center(N));
494     if ((D < M.r + N.r) && (D > M.r - N.r))
495     {
496         double cosM = (M.r * M.r + D * D - N.r * N.r) / (2.0 * M.r * D);
497         double cosN = (N.r * N.r + D * D - M.r * M.r) / (2.0 * N.r * D);
498         double alpha = 2.0 * acos(cosM);
499         double beta  = 2.0 * acos(cosN);
500         double TM = 0.5 * M.r * M.r * sin(alpha);
501         double TN = 0.5 * N.r * N.r * sin(beta);
502         double FM = (alpha / (2*pi)) * Area(M);
503         double FN = (beta / (2*pi)) * Area(N);
504         area = FM + FN - TM - TN;
505     }
506     else if (D <= M.r - N.r)
507     {
508         area = Area(N);
509     }
510     return area;
511 }
512 
513 bool IsInCircle(const Circle & C, const Rect_2 & rect)//判断圆是否在矩形内(不允许相切)
514 {
515     return (GT(C.c.x - C.r, rect.xl)
516   &&  LT(C.c.x + C.r, rect.xh)
517   &&  GT(C.c.y - C.r, rect.yl)
518   &&  LT(C.c.y + C.r, rect.yh));
519 }
520 
521 
522 //判断2圆的位置关系
523 //返回:
524 //BAOHAN   = 1;        // 大圆包含小圆
525 //NEIQIE   = 2;        // 内切
526 //XIANJIAO = 3;        // 相交
527 //WAIQIE   = 4;        // 外切
528 //XIANGLI  = 5;        // 相离
529 int CirCir(const Circle &c1, const Circle &c2)//判断2圆的位置关系
530 {
531  double dis = Distance(c1.c,c2.c);
532  if(LT(dis,fabs(c1.r-c2.r))) return BAOHAN;
533  if(EQ(dis,fabs(c1.r-c2.r))) return NEIQIE;
534  if(LT(dis,c1.r+c2.r) && GT(dis,fabs(c1.r-c2.r))) return XIANJIAO;
535  if(EQ(dis,c1.r+c2.r)) return WAIQIE;
536  return XIANGLI;
537 }
538 
539 
540 
541 ////////////////////////////////////////////////////////////////////////
542 /**多边形**/
543 
544 
545 bool cmp(Point A, Point B){
546     if(NEQ(A.x,B.x)) return LT(A.x,B.x);
547     return LT(A.y,B.y);
548 }
549 
550 //求凸包、逆时针顺序
551 //凸包上无连续三点共线
552 int ConvexHull(Point* p,int n,Point* ch){
553     sort(p,p+n,cmp);
554     int m = 0;
555     for(int i = 0;i < n;++i){
556         while(m > 1 && LEQ((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--;
557         ch[m++] = p[i];
558     }
559     int k = m;
560     for(int i = n-2;i >= 0;i--){
561         while(m > k && LEQ((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--;
562         ch[m++] = p[i];
563     }
564     if(n > 1) m--;
565     return m;
566 }
567 
568 //凸包上可以有连续三点共线
569 int ConvexHull_Colinear(Point* p,int n,Point* ch){
570     sort(p,p+n,cmp);
571     int m = 0;
572     for(int i = 0;i < n;++i){
573         while(m > 1 && LT((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--;
574         ch[m++] = p[i];
575     }
576     int k = m;
577     for(int i = n-2;i >= 0;i--){
578         while(m > k && LT((ch[m-1]-ch[m-2])*(p[i]-ch[m-2]),0)) m--;
579         ch[m++] = p[i];
580     }
581     if(n > 1) m--;
582     return m;
583 }
584 
585 //点是否在凸包内
586 //二分实现,复杂度 O(logn)。注意要是凸包,逆时针顺序
587 bool IsPointInConvexHull(Point p,Point* ch,int n){
588     int l = 1, r = n - 2;
589     while(l <= r){
590         int mid = (l + r) >> 1;
591         double t1 = (ch[mid]-ch[0])*(p-ch[0]);
592         double t2 = (ch[mid+1]-ch[0])*(p-ch[0]);
593         if(GEQ(t1,0) && LEQ(t2,0)){
594             if(GEQ((ch[mid+1]-ch[mid])*(p-ch[mid]),0))
595                 return true;
596             return false;
597         }
598         else if(LT(t1,0)) r = mid - 1;
599         else l = mid + 1;
600     }
601     return false;
602 }
603 
604 //点是否在凸包内
605 //用叉积顺次得到各个角度的符号,若全部同号则点在凸多边形内。否则不在凸多边形内。复杂度 O(n)。顺时针或逆时针都可以
606 //1: 在内部  0: 在外部  -1: 在多边形上
607 int IsPointInConvexHull2(Point p,Point* ch,int n){
608     int r = 0;
609     for(int i = 0;i < n;++i){
610         int t = dSign((p-ch[i])*(ch[(i+1)%n]-ch[i]));
611         if(t == 0){
612             if(IsPointOnLineSeg(p,Line(ch[i],ch[(i+1)%n]))) return -1;
613             else return 0;
614         }
615         if(r * t < 0) return 0;
616         r = t;
617     }
618     return 1;
619 }
620 
621 //点是否在多边形内(不必是凸包,多边形需是逆时针排列)
622 //转角法实现,代码参考《训练指南》
623 // 1: 在内部   0: 在外部   -1: 在多边形上
624 int IsPointInPolygon(Point p,Point* poly,int n){
625     int w = 0;
626     for(int i = 0;i < n;++i){
627         if(IsPointOnLineSeg(p,Line(poly[i],poly[(i+1)%n]))) return -1;
628         int k = dSign((poly[(i+1)%n]-poly[i])*(p-poly[i]));
629         int d1 = dSign(poly[i].y-p.y);
630         int d2 = dSign(poly[(i+1)%n].y-p.y);
631         if(k > 0 && d1 <= 0 && d2 > 0) w++;
632         if(k < 0 && d2 <= 0 && d1 > 0) w--;
633     }
634     if(w != 0) return 1;
635     return 0;
636 }
637 
638 //多边形是否是凸包
639 //复杂度O(n),多边形需是顺时针或逆时针排列
640 //n必须大于等于3。允许连续三点共线
641 bool IsPolygonConvex(Point* poly,int n){
642     int r = 0;
643     for(int i = 0;i < n;++i){
644         int t = dSign((poly[(i+1)%n]-poly[i])*(poly[(i+2)%n]-poly[(i+1)%n]));
645         if(r * t < 0) return 0;
646         if(t) r = t;
647     }
648     return 1;
649 }
650 
651 ////////////////////////////////////////////////////////////////////////
652 
653 int n;
654 double pr;
655 Point peg,vert[100010],cHull[100010];
656 
657 int main(){
658     ios::sync_with_stdio(false);
659     while(cin >> n && n >= 3){
660         cin >> pr >> peg.x >> peg.y;
661         for(int i = 0;i < n;++i) cin >> vert[i].x >> vert[i].y;
662         if(!IsPolygonConvex(vert,n)){
663             cout << "HOLE IS ILL-FORMED" << endl;
664             continue;
665         }
666         if(IsPointInConvexHull2(peg,vert,n) == 1){
667             bool fit = 1;
668             for(int i = 0;i < n;++i)
669                 if(LT(Distance(peg,Line(vert[i],vert[(i+1)%n])),pr)){
670                     fit = 0;
671                     break;
672                 }
673             if(fit) cout << "PEG WILL FIT" << endl;
674             else cout << "PEG WILL NOT FIT" << endl;
675         }
676         else cout << "PEG WILL NOT FIT" << endl;
677     }
678 
679     return 0;
680 }

 



posted @ 2017-09-03 22:54  doub7e  阅读(200)  评论(0编辑  收藏  举报