POJ 3449 Geometric Shapes (多边形)

  • 题意: 给出一个多边形和一个圆,先判断多边形是否为凸多边形,在判断圆是否在多边形内
  • 思路: 整理一下板子。

#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,&center.x,&center.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;
}

猜你喜欢

转载自www.cnblogs.com/xxrlz/p/11647329.html