- 题意: 给出一个多边形和一个圆,先判断多边形是否为凸多边形,在判断圆是否在多边形内
- 思路: 整理一下板子。
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 1e3+10;
const double eps = 1e-8;
inline int sgn(double x){
if(fabs(x)<eps) return 0;
return x<0? -1:1;
}
struct point{
double x,y;
point(double a=0,double b=0){
x = a, y = b;
}
point operator -(const point &b)const{
return point(x-b.x,y-b.y);
}
bool operator <(const point &b)const{
return x<b.x-eps;
}
bool operator == (const point &b)const{
return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
}
void transxy(double b){
double tx = x, ty = y;
x = tx*cos(b) - ty*sin(b);
y = tx*sin(b) + ty*cos(b);
}
double norm(){
return sqrt(x*x+y*y);
}
};
inline double det(const point &a,const point &b){
return a.x*b.y - a.y*b.x;
}
inline double dot(const point &a,const point &b){
return a.x*b.x+ a.y*b.y;
}
inline double dist(const point &a,const point &b){
return (a-b).norm();
}
double area(point a,point b,point c){
return det(b-a,c-b);
}
struct line{
point s,e;
line(){}
line(point s,point e):s(s),e(e){}
};
inline bool parallel(line &l1,line &l2){
return !sgn(det(l1.e - l1.s,l2.e-l2.s));
}
inline bool point_on_seg(point &p,line &a){
return sgn(det(p-a.s,p-a.e))==0 && sgn(dot(p-a.s,p-a.e))<=0;
}
// 线段与线段相交
inline bool cross(line l1,line l2){
line vec = line(l1.s,l1.e-l1.s); // l1 的向量9
if(parallel(l1,l2)) // 平行(重合),则点在线上才相交
return point_on_seg(l1.s,l2) || point_on_seg(l1.e,l2)
|| point_on_seg(l2.s,l1) || point_on_seg(l2.e,l1);
if(sgn(det(l2.s-vec.s,vec.e)*det(vec.e,l2.e-vec.s))==-1)
return false;
if(sgn(det(l2.s-l1.s,l2.e-l1.s)*det(l2.s-l1.e,l2.e-l1.e))==1)
return false;
return true;
}
// 线段与直线相交
// 手写 uncheck
bool segcorseg(line l1,line l2){
// 两端叉积符号不同,则在不同侧,说明相交
// = 0 表示端点在线上
return sgn(det(l1.a - l2.a, l1.b - l2.a)) * sgn(det(l1.a - l2.b , l1.b - l2.b)) <= 0
|| sgn(det(l2.a - l1.a,l2.b - l1.a)) * sgn(det(l2.a - l1.b, l2.b - l1.b)) <= 0;
}
// 极角排序
point start;
bool cmp(const point &a,const point &b){
double x = det(a-start,b-start);
if(sgn(x)==0) return dist(start,a) < dist(start,b);
else return x>0;
}
struct polygon{
int n;
point a[N];
polygon(){}
bool isTu(){
// 凸多边形判断
// 相邻三点构成三角形 叉积符号相同
bool s[3]; // -1 0 1 是否存在,
s[0] = s[1] = s[2] = 0;
for(int i=0;i<n;++i){
s[sgn(area(a[i],a[(i+1)%n],a[(i+2)%n]))+1] = 1;
if(s[0] && s[2]) return false; // 有正又有负不行
}
return true;
}
bool inPoly(point p){
// 点在多边形内
// 先以a[0]为源点 进行极角排序
start = a[0];
sort(a,a+n,cmp);
int cnt = 0 ;
line ray,side; // 点所在平行y轴射线,当前多边形的边
ray.s = p; ray.e.y = p.y; ray.e.x = -1e9;
for(int i=0;i<n;++i){
side.s = a[i];
side.e = a[(i+1)%n];
if(point_on_seg(p,side)) return 1; // 如果点在边界上,也算在多边形内
if(sgn(side.s.y-side.e.y)==0) continue; // 平行 不计算
if(point_on_seg(side.s,ray)){ // 起点在射线上
if(sgn(side.s.y - side.e.y) > 0) cnt++; // 小于等于0 则不会在多边形内
}
else if(point_on_seg(side.e,ray)){
if(sgn(side.e.y - side.s.y) > 0) cnt++;
}
else if(cross(ray,side)) // 线段相交
cnt++;
}
return cnt%2; // 相交点数为奇数,在多边形内
}
}poly;
int main(){
// freopen("2.out","w",stdout);
int n,pos; point center; double r;
while(~scanf("%d",&n) && n>2){
scanf("%lf%lf%lf",&r,¢er.x,¢er.y);
poly.n = n; pos = 0;
for(int i=0;i<n;++i){
scanf("%lf%lf",&poly.a[i].x,&poly.a[i].y);
if(poly.a[i].y < poly.a[pos].y || (sgn(poly.a[i].y-poly.a[pos].y)==0 && poly.a[i].x < poly.a[pos].x))
pos = i;
}
if(poly.isTu()){
// 及左下角点为源点
swap(poly.a[0],poly.a[pos]);
if(!poly.inPoly(center)){
puts("PEG WILL NOT FIT");
continue;
}
double d;
int no = 0;
for(int i=0;i<n;++i){
// 源点到这条线的距离
d = fabs(det(center-poly.a[i],poly.a[(i+1)%n]-poly.a[i]))/dist(poly.a[i],poly.a[(i+1)%n]);
// r > d 包不住
if(sgn(d-r)==-1){
no = 1;
break;
}
}
if(no) puts("PEG WILL NOT FIT");
else puts("PEG WILL FIT");
}else{
puts("HOLE IS ILL-FORMED");
}
}
return 0;
}