poj1584 A Round Peg in a Ground Hole 判断多边形凹凸,点到线的距离【基础计算几何】

大致思路:首先对于所给的洞的点,判断是否是凸多边形,图形的输入和输出可以是顺时针或者逆时针,而且允许多点共线

 

Debug 了好几个小时,发现如下问题

判断三点是否共线,可用斜率公式判断

POINT point_A, point_B, point_C;

        if(point_A.x == point_B.x || point_B.x == point_C.x){

            if(point_A.x == point_B.x && point_B.x == point_C.x)

                continue;

        }else{

            if((point_B.y - point_A.y) / (point_B.x - point_A.x) \

                == (point_C.y - point_B.y) / (point_C.x - point_B.x))

                continue;

        }

其次,判断圆是否和多边形相切的时候,应用:

if(Ptol(point, line2) - rr >= 0){

而不是:

 if(Ptol(point, line2) - rr >= eps){//eps = 1e-9

否则会出错。

 

贴代码了QAQ

//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler

#include <stdio.h>

#include <iostream>

#include <cstring>

#include <cmath>

#include <stack>

#include <queue>

#include <vector>

#include <algorithm>

#define ll long long

#define Max(a,b) (((a) > (b)) ? (a) : (b))

#define Min(a,b) (((a) < (b)) ? (a) : (b))

#define Abs(x) (((x) > 0) ? (x) : (-(x)))

using namespace std;



const int INF = 0x3f3f3f3f;

const int MAXN = 220;

const double eps = 1e-9;



int gcd(int a,int b){

    return b == 0 ? a : gcd(b, a % b);

}

struct POINT{

    double x;

    double y;

    POINT() : x(0), y(0) {};

    POINT(double _x_, double _y_) : x(_x_), y(_y_) {};

};



struct SEG{

    POINT a;

    POINT b;

    SEG() {};

    SEG(POINT _a_, POINT _b_) : a(_a_), b(_b_) {};

};



struct LINE{

    POINT a;

    POINT b;

    LINE() {};

    LINE(POINT _a_, POINT _b_) : a(_a_), b(_b_) {};

};



struct LINE2{

    double A, B, C;

    LINE2 () {};

    LINE2(double _A_, double _B_, double _C_): A(_A_), B(_B_), C(_C_) {};

};



LINE2 Line2line(const LINE & L){

    LINE2 L2;

    L2.A = L.b.y - L.a.y;

    L2.B = L.a.x - L.b.x;

    L2.C = L.b.x * L.a.y - L.a.x * L.b.y;

    return L2;

}



struct POLY{

    int n;

    double * x;

    double * y;

    POLY() : n(0), x(NULL), y(NULL) {};

    POLY(int _n_, const double * _x_, const double * _y_){

        n = _n_;

        x = new double[n + 1];

        memcpy(x, _x_, n * sizeof(double));

        x[n] = _x_[0];

        y = new double[n + 1];

        memcpy(y, _y_, n * sizeof(double));

        y[n] = _y_[0];

    }

};



POINT vertex(const POLY & poly, int idx){

    idx %= poly.n;

    return POINT(poly.x[idx], poly.y[idx]);

}



SEG Edge(const POLY & poly, int idx){

    idx %= poly.n;

    return SEG(POINT(poly.x[idx], poly.y[idx]),

        POINT(poly.x[idx + 1], poly.y[idx + 1]));

}



void Coefficient(const LINE & L, double & A, double & B, double & C){

    A = L.b.y - L.a.y;

    B = L.a.x - L.b.x;

    C = L.b.x * L.a.y - L.a.x * L.b.y;

}



double Ptol(const POINT p, const LINE2 L){

    return Abs(L.A * p.x + L.B * p.y + L.C) / sqrt(L.A * L.A + L.B * L.B);

}



bool IsEqual(double a, double b){

    return (Abs(a - b) < eps);

}



bool IsEqual(const POINT & a, const POINT & b){

    return (IsEqual(a.x, b.x) && IsEqual(a.y, b.y));

}



bool IsEqual(const LINE & A, const LINE & B){

    double A1, B1, C1;

    double A2, B2, C2;

    Coefficient(A, A1, B1, C1);

    Coefficient(B, A2, B2, C2);

    return IsEqual(A1 * B2, A2 * B1) &&

        IsEqual(A1 * C2, A2 * C1) &&

        IsEqual(B1 * C2, B2 * C1);

}



double Cross(const POINT & a, const POINT & b, const POINT &o){

    return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);

}



bool IsParallel(const LINE & A, const LINE & B){

    double A1, B1, C1;

    double A2, B2, C2;

    Coefficient(A, A1, B1, C1);

    Coefficient(B, A2, B2, C2);

    /*

    return (A1 * B2 == A2 * B1) &&

        ((A1 * C2 != A2 * C1) || (B1 * C2 != B2 * C1));

    */

    return (A1 * B2 == A2 * B1);

}



bool IsIntersect(const LINE & A, const LINE & B){

    return !IsParallel(A, B);

}



bool IsIntersect(const SEG & u, const SEG & v){

    return (Cross(v.a, u.b, u.a) * Cross(u.b, v.b, u.a) >= 0) &&

        (Cross(u.a, v.b, v.a) * Cross(v.b, u.b, v.a) >= 0) &&

        (Max(u.a.x, u.b.x) >= Min(v.a.x, v.b.x)) &&

        (Max(v.a.x, v.b.x) >= Min(u.a.x, u.b.x)) &&

        (Max(u.a.y, u.b.y) >= Min(v.a.y, v.b.y)) &&

        (Max(v.a.y, v.b.y) >= Min(u.a.y, u.b.y));

}



bool IsOnSeg(const SEG & seg, const POINT & p){

    return (IsEqual(p, seg.a) || IsEqual(p, seg.b)) ||

        (((p.x - seg.a.x) * (p.x - seg.b.x) < 0 ||

        (p.y - seg.a.y) * (p.y - seg.b.y) < 0) &&

        (IsEqual(Cross(seg.b, p, seg.a), 0)));

}



bool IsOnPoly(const POLY & poly, const POINT & p){

    for(int i = 0; i < poly.n; ++i){

        if(IsOnSeg(Edge(poly, i), p)){

            return true;

        }

    }

    return false;

}



bool IsInPoly(const POLY & poly, const POINT & p){

    SEG L(p, POINT(INF, p.y));

    int count = 0;

    for(int i = 0; i < poly.n; ++i){

        SEG S = Edge(poly, i);

        if(IsOnSeg(S, p)){

            return true;

        }

        if(!IsEqual(S.a.y, S.b.y)){

            POINT & q = (S.a.y > S.b.y) ? (S.a) : (S.b);

            if(IsOnSeg(L, q)){

                ++count;

            } else if(!IsOnSeg(L, S.a) && !IsOnSeg(L, S.b) && IsIntersect(S, L)){

                ++count;

            }

        }

    }

    return (count % 2 != 0);

}



POINT InCenter(const POLY & poly){

    double S, Si, Ax, Ay;

    POINT p;

    Si = (poly.x[poly.n - 1] * poly.y[0] - poly.x[0] * poly.y[poly.n - 1]);

    S = Si;

    Ax = Si * (poly.x[0] + poly.x[poly.n - 1]);

    Ay = Si * (poly.y[0] + poly.y[poly.n - 1]);

    for(int i = 1; i < poly.n; ++i){

        Si = (poly.x[i - 1] * poly.y[i] - poly.x[i] * poly.y[i - 1]);

        Ax += Si * (poly.x[i - 1] + poly.x[i]);

        Ay += Si * (poly.y[i - 1] + poly.y[i]);

        S += Si;

    }

    S = S * 3;

    return POINT(Ax/S, Ay/S);

}



double Area(const POLY & poly){

    if(poly.n < 3)  return double(0);

    double s = poly.y[0] * (poly.x[poly.n - 1] - poly.x[1]);

    for(int i = 1; i < poly.n; ++i){

        s += poly.y[i] * (poly.x[i - 1] - poly.x[(i + 1) % poly.n]);

    }

    return s / 2;

}



int PointInedge(const POLY & poly){

    int ans = 0;

    for(int i = 0; i < poly.n; ++i){

        double xx = Abs(poly.x[i] - poly.x[i + 1]);

        double yy = Abs(poly.y[i] - poly.y[i + 1]);

        if(xx == 0 && yy == 0)

            ans += 0;

        else if(xx == 0)

            ans += yy - 1;

        else if(yy == 0)

            ans += xx- 1 ;

        else

            ans += gcd(xx, yy) - 1;

    }

    return ans + poly.n;

}



bool IsConvexPolygon(const POLY & poly){

    double ans ,cnt = 1.0;

    bool flag ,real = false;

    for(int i = 0; i < poly.n; ++i){

        ans = (poly.x[i] - poly.x[(i + 2) % poly.n])\

            * (poly.y[(i + 1) % poly.n] - poly.y[(i + 2) % poly.n])\

            - (poly.x[(i + 1) % poly.n] - poly.x[(i + 2) % poly.n])\

            * (poly.y[i] - poly.y[(i + 2) % poly.n]);



        POINT point_A, point_B, point_C;

        if(point_A.x == point_B.x || point_B.x == point_C.x){

            if(point_A.x == point_B.x && point_B.x == point_C.x)

                continue;

        }else{

            if((point_B.y - point_A.y) / (point_B.x - point_A.x) \

                == (point_C.y - point_B.y) / (point_C.x - point_B.x))

                continue;

        }

        if(real && cnt * ans < eps) return false;

        cnt = ans;

        real = true;

    }

    return true;

}



double x[20011], y[20011];

int main(){

    int i, j, k;

    int t, n, m;

    double rr, xx, yy;

    while(EOF != scanf("%d",&n)){

        if(n < 3)   break;

        POINT point;

        scanf("%lf%lf%lf",&rr,&point.x,&point.y);

        for(i = 0; i < n; ++i)

            scanf("%lf%lf",&x[i],&y[i]);

        POLY poly(n, x, y);



        if(!IsConvexPolygon(poly))

            printf("HOLE IS ILL-FORMED\n");

        else{

            if(!IsInPoly(poly, point)){



                printf("PEG WILL NOT FIT\n");

            }

            else{

                for(i = 0; i < n; ++i){

                    SEG seg = Edge(poly, i);

                    LINE line;

                    LINE2 line2;

                    line.a = seg.a;

                    line.b = seg.b;

                    line2 = Line2line(line);



                    if(Ptol(point, line2) - rr >= 0){

                        continue;

                    }

                    else{

                        printf("PEG WILL NOT FIT\n");

                        break;

                    }

                }

                if(i == n){

                    printf("PEG WILL FIT\n");

                }

            }

        }

    }

    return 0;

}

 

你可能感兴趣的:(round)