POJ - 1584 A Round Peg in a Ground Hole (是否爲凸多邊形+點是否在多邊形內+圓是否在多邊形內)

鏈接:https://cn.vjudge.net/problem/POJ-1584

題意:判斷多邊形是否爲凸多邊形以及圓是否在多邊形內。

思路:模板。詳情看註釋。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 1e3+10;
const double eps = 1e-8;
int sgn(double x)
{
	if(fabs(x)<eps) return 0;
	else if(x>0) return 1;
	else return -1;
}
struct Point
{
	double x,y;
	Point(){}
	Point(double x,double y):x(x),y(y){}
	Point operator -(const Point& a)const
	{
		return Point(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 x*a.x+y*a.y;
	}
}ps[N],peg;
struct Line
{
	Point s,e;
	Line(){}
	Line(Point ss,Point ee)
	{
		s=ss,e=ee;
	}	
};
int n,pos,top;
bool no;
double pr,x,y;
//兩點距離 
double dis(Point a,Point b)
{
	return sqrt((b-a)*(b-a));
}
//以0爲標準,極角排序 
bool cmp(const Point& a,const Point& b)
{
	x=(a-ps[0])^(b-ps[0]);
	if(sgn(x)==0)
	{
		return dis(ps[0],a)<dis(ps[0],b);
	}
	else if(x>0) return 1;
	else return 0;
}
//是否爲凸多邊形
//可有共線邊 
bool isconv()
{
	bool s[3];
	s[0]=s[1]=s[2]=0;
	for(int i=0;i<n;i++)
	{
		s[sgn( (ps[(i+1)%n]-ps[i])^(ps[(i+2)%n]-ps[i]) )+1]=1;	
		if(s[0]&&s[2]) return 0;
	}	
	return 1;
}
//點是否在線段上 
bool OnSeg(Point P,Line L)
{
    return
    sgn((L.s-P)^(L.e-P)) == 0 &&
    sgn((P.x - L.s.x) * (P.x - L.e.x)) <= 0 &&
    sgn((P.y - L.s.y) * (P.y - L.e.y)) <= 0;
}
//線段是否相交 
bool inter(Line l1,Line l2)
{
    return
    max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&
    max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&
    max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&
    max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&
    sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0 &&
    sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e)) <= 0;
}
//點是否在多邊形內
//引射線判斷法
//返回值
//-1:點在凸多邊形外
//0:點在凸多邊形邊界上
//1:點在凸多邊形內 
int inPoly(Point p,Point poly[],int n)
{
    int cnt;
    Line ray,side;
    cnt = 0;
    ray.s = p;
    ray.e.y = p.y;
    ray.e.x = -100000000000.0;//-INF,注意取值防止越界
    for(int i = 0;i < n;i++)
    {
        side.s = poly[i];
        side.e = poly[(i+1)%n];

        if(OnSeg(p,side))return 0;

        //如果平行軸則不考慮
        if(sgn(side.s.y - side.e.y) == 0)
            continue;

        if(OnSeg(side.s,ray))
        {
            if(sgn(side.s.y - side.e.y) > 0)cnt++;
        }
        else if(OnSeg(side.e,ray))
        {
            if(sgn(side.e.y - side.s.y) > 0)cnt++;
        }
        else if(inter(ray,side))
            cnt++;
    }
    if(cnt % 2 == 1)return 1;
    else return -1;
} 
bool inconv()
{
	for(int i=0;i<n;i++)
		if(sgn((ps[i]-peg)^(ps[(i+1)%n]-peg))<=0) return 0;	
	return 1;		
}
//判斷點是否在凸多邊形內
//這個題不能用,不知道爲啥。 
int inConvexPoly(Point a,Point p[],int n)
{
    for(int i = 0;i < n;i++)
    {
        if(sgn((p[i]-a)^(p[(i+1)%n]-a)) < 0)return -1;
        else if(OnSeg(a,Line(p[i],p[(i+1)%n])))return 0;
    }
    return 1;
}
int main(void)
{
	while(~scanf("%d",&n)&&(n>=3))
	{
		no=0;
		scanf("%lf%lf%lf",&pr,&peg.x,&peg.y);	
		pos=0;
		for(int i=0;i<n;i++)
		{
			scanf("%lf%lf",&ps[i].x,&ps[i].y);
			if(ps[i].y<ps[pos].y || (ps[i].y==ps[pos].y&&ps[i].x<ps[pos].x))
				pos=i;
		}
		
		if(!isconv())
		{
			puts("HOLE IS ILL-FORMED");
			continue;
		}
		
		swap(ps[0],ps[pos]);	
		sort(ps+1,ps+n,cmp);		
		if(inPoly(peg,ps,n)<0)	
		{
			puts("PEG WILL NOT FIT");
			continue;	
		}
		//以下兩種判斷點是否在凸多邊形內的方法
		//對於此題都不行 
		/*
		if(inConvexPoly(peg,ps,n)<=0)
		{
			puts("PEG WILL NOT FIT");
			continue;	
		}*/
		/*
		if(!inconv())	
		{
			puts("PEG WILL NOT FIT");
			continue;	
		}*/
		double d;	
		for(int i=0;i<n;i++)
		{
			d=fabs((peg-ps[i])^(ps[(i+1)%n]-ps[i]))/dis(ps[i],ps[(i+1)%n]);
			if(sgn(d-pr)<0)
			{
				no=1;
				break;
			}					
		}
		if(no)
			puts("PEG WILL NOT FIT");
		else puts("PEG WILL FIT");		
		
	}
	return 0;
}

 

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