UVA 634 || Polygon(转角法,点在凸包内

该博客介绍了如何使用转角法判断一个点是否属于多边形,包括转角法的原理和代码实现。通过计算多边形各边转角之和,若为2π则点在内,π则在边界,0则在外。文章以UVA 634问题为例,解析了具体应用,并提供了辅助理解的图像。
摘要由CSDN通过智能技术生成

题目大意:T when P belongs to the polygon or F otherwise 

如果点P属于多边形那么输出T,反之输出F。


刚刚入门计算几何。都是自己摸索出来的,如果理解有偏差,望指点。


转角法。


我们把多边形每条边的转角加起来,如果是2pi,那么点在多边形内。

如果是Ipi,那么点在多边形的边界上。

如果是0,那么点在多边形外部。

如上图图一 转角为 <bac + < cad + < dab = 2pi

图二转角为 <feg + <geh + <hef = 0


转角法的代码实现为假设一条向右的射线。统计多边形穿过这条射线正反多少次。

逆时针加1,顺时针减1。


红色字体为大白上面的原话,我琢磨了一个下午一直卡壳。。

然后终于有了自己的见解。


例如题目的第二个例子。

具体看代码,图片已经附上帮组理解。



#include<iostream>
#include<cstdio>
#include<cmath>
#define FOR(i,m,n) for( int i = m; i<n;++i)
using namespace std;
//------------ 点结构,向量  ------------
struct NODE
{
    double y,x;
    NODE(double x= 0,double y= 0):x(x),y(y){};

};
typedef NODE vec;
vec operator - (NODE a,NODE b)
{
    return vec(a.x - b.x,a.y -b.y );
}
//------------- dcmp -------------
const double eps = 1e-10;
int  dcmp(double x)
{
    if( fabs(x) < eps )
        return  0;
    else
        return x < 0?-1:1;
}
//----------------------------
NODE point[1000+5];
NODE p;
//-------- X积 -------------
double cross( NODE a,NODE b,NODE c)
{
    vec A (b.x - a.x,b.y- a.y);
    vec B (c.x - a.x,c.y - a.y);
    return A.x*B.y - A.y*B.x;
}
//--------- 点积 ----------
double dot(NODE a,NODE b,NODE c )
{
    vec A (b.x - a.x,b.y- a.y);
    vec B (c.x - a.x,c.y - a.y);
    return A.x*B.x + A.y*B.y;
}
bool onsegment(NODE p,NODE a,NODE b)
{
    return dcmp( cross( p,a,b)) == 0 && dcmp(dot(p,a,b))< 0;

    /*
         X积 == 0 --》 三点共线
         点积 < 0 -->  点p属于线段ab
    */

}
int ispointinpoly(int n)
{
    int wn =0;// wingding number
    FOR(i,0,n)
    {
        if(onsegment(p,point[i],point[i+1]) )return -1;//onsegment
        int k = dcmp( cross(point[i],point[i+1],p ) );
        int d1 = dcmp(point[i].y - p.y);
        int d2 = dcmp(point[i+1].y - p.y);
        //printf("      i=%2d    k=%2d d1=%2d d2=%2d  ",i,k,d1,d2)
        
        //p点引出一条向右的射线
        if( k >0 && d1<=0 && d2>0)wn++;//射线逆时针穿过 i到i+1这两点间的线段 wn加一
        if( k <0 && d2<=0 && d1>0)wn--;//顺时针则减一
        //printf("wn=%2d\n",wn);n

    }
    if( wn!= 0)return 1;//indise
    return 0;//outside
}
int main()
{
    int n;
    while( cin>>n && n )
    {
        FOR(i,0,n)
        {
            scanf("%lf %lf",&point[i].x,&point[i].y);
        }
        point[n] = point[0];//point[i+1]
        cin>>p.x>>p.y;
        if( ispointinpoly(n)==0 )puts("F");
        else puts("T");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值