POJ 1584 A Round Peg in a Ground Hole(凸包判定,多邊形計算與判定)

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


題目大意:

        給定n個連續的點,以及一個圓的圓心和半徑,問圓是否在多邊形內部,如果順序給定的點不能組成凸多邊形,則輸出“Hole IS ILL-FORMED”,如果圓在多邊形內部則輸出“PEG WILL FIT”,否則輸出“PEG WILL NOT FIT”。

解題思路:

        1.先跑一遍凸包,如果給定的點全在凸包上說明給定的點可以組成凸多邊形,否則則不能組成凸多邊形,輸出“HOLE IS ILL-FORMED”

        2.經過步驟1後,判斷給定圓心是否在凸多邊形內,用環顧角來判斷,依次順序枚舉相鄰的點組成邊,與給定的圓心形成夾角,可以運用公式,(不好寫公式,編輯不出來,看代碼吧。。。),如果環顧角之和爲+360或-360(要寫成弧度即2PI),則圓心在多邊形內部,否則說明在多邊形上或外部,輸出“PEG WILL NOT FIT”

        3.經過上述步驟後,確定了給定點可以組成凸多邊形且圓心在多邊形內部,然後就是判定圓是不是在多邊形內部,那就依次枚舉圓心到每條邊的距離,如果都大於等於圓的半徑,則圓在多邊形內部,輸出“PEG WILL FIT”,否則輸出“PEG WILL NOT FIT”,同樣,點到線段的計算公式見代碼。。 = =


#include <iostream>
#include <fstream>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
#include <bitset>
#include <ctime>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <list>

#define STD_REOPEN() freopen("../in.in","r",stdin)
#define STREAM_REOPEN fstream cin("../in.in")
#define INF 0x3f3f3f3f
#define _INF 63
#define eps 1e-8
#define MAX_V 100010
#define MAX_P 110
#define MAX_E 10010
#define MAX 32000
#define MOD_P 3221225473
#define MOD 9901

using namespace std;

struct Point
{
	double x,y;
	Point(){}
	Point(double a,double b):x(a),y(b){}
	Point operator - (const Point a)const	//求向量
	{
		return Point(x-a.x,y-a.y);
	}
	double operator * (const Point a)const	//點乘
	{
		return x*a.x+y*a.y;
	}
	double operator ^ (const Point a)const	//叉乘
	{
		return (x*a.y)-(y*a.x);
	}
	double operator & (const Point a)const	//兩點間距離
	{
		return sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y));
	}
	bool operator < (const Point a)const
	{
		if(y==a.y)
			return x<a.x;
		return y<a.y;
	}
}s[1010];

double rx,ry,r;
const double PI=acos(-1.0);

int dcmp(double x)
{
	return fabs(x)<eps?0:(x<0?-1:1);
}
double getAngle(Point p,Point a,Point b)	//獲取點p到線段ab兩端點形成的夾角
{
	return acos((Point(a-p)*Point(b-p))/((p&a)*(p&b)));
}
double getDistance(Point p,Point a,Point b)	//求點p到線段ab的距離
{
	if(dcmp((p-a)*(b-a))<0)
		return p&a;
	if(dcmp((p-b)*(a-b))<0)
		return p&b;
	return fabs(((a-p)^(b-p))/(a&b));
}
int GrahamScan(int n)	//求凸包,返回01表示無法形成凸多邊形,0表示圓心在凸多邊形之外或圓不在多邊形之內,1表示圓在多邊形內
{
	sort(s,s+n);
	Point res[1010];
	int top=0;
	for(int i=0;i<n;i++)
	{
		while(top>=2&&(Point(res[top-1]-res[top-2])^Point(s[i]-res[top-2]))<0)
			top--;
		res[top++]=s[i];
	}
	int len=top+1;
	for(int i=n-2;i>=0;i--)
	{
		while(top>=len&&(Point(res[top-1]-res[top-2])^Point(s[i]-res[top-2]))<0)
			top--;
		res[top++]=s[i];
	}
	if(top-1<n)	//凸包內頂點數(這裏起始點有重複)小於總點數,返回-1
		return -1;
	double cnt=0;
	for(int i=0;i<top-1;i++)
		cnt+=getAngle(Point(rx,ry),res[i],res[i+1]);
	//cout<<cnt<<endl;
	if(!(dcmp(cnt-2*PI)==0||dcmp(cnt+2*PI)==0))	//環顧角絕對值不等於2PI
		return 0;
	bool isOK=true;
	for(int i=0;i<top-1;i++)
		if(dcmp(getDistance(Point(rx,ry),res[i],res[i+1])-r)<0)	//圓心到邊的距離小於半徑
		{
			isOK=false;
			break;
		}
	return isOK?1:0;
}

int main()
{
	//STD_REOPEN();
	int n;
	while(scanf("%d",&n),n>=3)
	{
		scanf("%lf %lf %lf",&r,&rx,&ry);
		for(int i=0;i<n;i++)
			scanf("%lf %lf",&s[i].x,&s[i].y);
		int ans=GrahamScan(n);
		if(ans==-1)
			printf("HOLE IS ILL-FORMED\n");
		else if(ans==0)
			printf("PEG WILL NOT FIT\n");
		else
			printf("PEG WILL FIT\n");
	}

    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章