码迷,mamicode.com
首页 > 其他好文 > 详细

A Round Peg in a Ground Hole - POJ 1584 (判断凸多边形&判断点在多边形内&判断圆在多边形内)

时间:2015-09-11 00:02:58      阅读:242      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:首先给一个圆的半径和圆心,然后给一个多边形的所有点(多边形按照顺时针或者逆时针给的),求,这个多边形是否是凸多边形,如果是凸多边形在判断这个圆是否在这个凸多边形内。
 
分析:判断凸多边形可以使用相邻的三个点叉积判断,因为不知道顺时针还是逆时针,所以叉积如果有有整数和负数,那么一定不是凸多边形(注意允许多多点在一条线段上)。判断圆在凸多边形首先要判断圆心是否在多边形内,如果在多边形内,再次判断圆心到达到变形每条边的最短距离,如果小于半径就是不合法。ps:一道好题,通过这个题学会了不少东西。
 
代码如下:
=======================================================================================================================================
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;

const int MAXN = 1e3+7;
const double EPS = 1e-8;
const double oo = 1e10+7;

struct Point
{
    double x, y;
    Point(double x=0, double y=0):x(x),y(y){}
    Point operator - (const Point &tmp)const{
        return Point(x-tmp.x, y-tmp.y);
    }
    double operator ^(const Point &tmp)const{
        return x*tmp.y - y*tmp.x;
    }
    double operator *(const Point &tmp)const{
        return x*tmp.x + y*tmp.y;
    }
};
double Dist(Point a, Point b)
{///两点间的距离
    return sqrt((a-b)*(a-b));
}
int Sign(double t)
{
    if(t > EPS)return 1;
    if(fabs(t) < EPS)return 0;
    return -1;///负数
}
struct Segment
{
    Point S, E;
    Segment(Point S=0, Point E=0):S(S), E(E){}
    bool OnSeg(const Point &p)
    {///点是否在线段上
        if(Sign( (S-E)^(p-E) ) == 0)///共线
        if(Sign( (p.x-S.x)*(p.x-E.x) ) <= 0)///位于线段的中间或者端点
        if(Sign( (p.y-S.y)*(p.y-E.y) ) <= 0)
            return true;
        return false;
    }
    bool Inter(const Segment &tmp)
    {///只考虑完全相交的情况
        return Sign((S-E)^(tmp.S-E)) * Sign((S-E)^(tmp.E-E)) == -1;
    }
    Point NearPoint(const Point &p)
    {///点到线段最近的点
        Point res;
        double r = ((E-S)*(p-S)) / ((E-S)*(E-S));

        if(r > EPS && (1.0 - r) > EPS )
        {///点在线段的投影在线段上
            res.x = S.x + r * (E.x-S.x);
            res.y = S.y + r * (E.y-S.y);
        }
        else
        {///求离最近的端点
            if(Dist(p, S) < Dist(p, E))
                res = S;
            else
                res = E;
        }

        return res;
    }
};
struct Poly
{
    int N;
    Point vertex[MAXN];

    bool IsConvex()
    {///判断是否是凸多边形,可以共线
        int vis[3] = {0};
        for(int i=0; i<N; i++)
        {///如果同时出现整数和负数,说明存在凹的
            int k = Sign((vertex[(i+1)%N]-vertex[i])^(vertex[(i+2)%N]-vertex[i]));
            vis[k+1] = 1;

            if(vis[0] && vis[2])
                return false;
        }
        return true;
    }
    int InPoly(const Point &Q)
    {///判断点Q是否在多边形内,射线法,奇数在内,偶数在外
    ///在圆上返回0, 圆外-1, 圆内 1
        Segment ray(Point(-oo, Q.y), Q);///构造射线的最远处
        int cnt=0;///统计相交的边数

        for(int i=0; i<N; i++)
        {
            Segment edge(vertex[i], vertex[(i+1)%N]);

            if(edge.OnSeg(Q) == true)
                return 0;///点在边上

            if(ray.OnSeg(vertex[i]) == true)
            {///如果相交连接点,那么取y值小的点
                if(vertex[(i+1)%N].y - vertex[i].y > EPS)
                    cnt++;
            }
            else if(ray.OnSeg(vertex[(i+1)%N]) == true)
            {
                if(vertex[i].y - vertex[(i+1)%N].y > EPS)
                    cnt++;
            }
            else if(ray.Inter(edge) && edge.Inter(ray))
                cnt++;
        }

        if(cnt % 2)
            return 1;
        else
            return -1;
    }
};
struct Circle
{
    Point center;///圆心
    double R;///半径
};

bool Find(Poly &a, Circle &c)
{///判断圆是否在多边形内
    if(a.InPoly(c.center) == -1)
        return false;///如果圆心在多边形外面

    for(int i=0; i<a.N; i++)
    {
        Segment edge(a.vertex[i], a.vertex[(i+1)%a.N]);
        double len = Dist(c.center, edge.NearPoint(c.center));

        if(Sign(len-c.R) < 0)
            return false;
    }

    return true;
}

int main()
{
    Poly a;///定义多边形
    Circle c;///定义圆

    while(scanf("%d", &a.N) != EOF && a.N > 2)
    {
        scanf("%lf%lf%lf", &c.R, &c.center.x, &c.center.y);
        for(int i=0; i<a.N; i++)
            scanf("%lf%lf", &a.vertex[i].x, &a.vertex[i].y);

        if(a.IsConvex() == false)
            printf("HOLE IS ILL-FORMED\n");
        else if(Find(a, c) == false)
            printf("PEG WILL NOT FIT\n");
        else
            printf("PEG WILL FIT\n");
    }

    return 0;
}

 

A Round Peg in a Ground Hole - POJ 1584 (判断凸多边形&判断点在多边形内&判断圆在多边形内)

标签:

原文地址:http://www.cnblogs.com/liuxin13/p/4799667.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!