计算几何 求简单多边形的内核(是否是星形多边形)

星形多边形是什么呢?其实就是在多边形内部存在一个点A,这个点与多边形内任意一点的连线都在多边形内部,就叫做星形多边形,这一个点A就叫做多边形的内核。

我是在看计算几何这本书的时候发现的,当时不是很懂书上的定义。

那我们如何判断多边形是否是星形多边形呢,通常的方法是按照顺序用相邻的两个点所连成的直线去切这个多边形,按照顺序又分为是顺时针和逆时针。比如这条线是ax+by+c=0,全部的点在一个集合p内

如果是顺时针的话,这条线切多边形,相交的点是ax+by+c=0的解,那可能会有ax+by+c>0的点和ax+by+c<0的点。因为是顺时针所以ax+by+c>0的点在这条线的右边,所以一个点在直线右边的话,那么带入值就会大于等于0 说明这个点还在切割后的多边形内,将其保留。如果ax+by+c<0说明这个点已经被切割在外了,就删去这个点。注意这里直线去切多边形,也就是直线与直线相交可能会形成新的点,也就是切割后形成新的多边形有新的点。我们就要计算新的点然后加入内部点集合p中。一直重复切割的步骤,知道最后不能切为止,如果有剩下的点,那这个点就是多边形的内核,这个多边形就是星形多边形

可以看这个图来帮助理解一下http://www.cnblogs.com/ka200812/archive/2012/01/20/2328316.html

poj两个例题,真的是红果果的例题哇 ++(*=   。=*)++

poj 3335 顺时针给点,问是不是星形多边形

http://poj.org/problem?id=3335

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

struct node
{
    double x,y;
};
node point[105];//记录最开始的多边形
node q[105]; //临时保存新切割的多边形
node p[105]; //保存新切割出的多边形
int n,m;//n的原先的点数,m是新切割出的多边形的点数
double a,b,c;
void getline(node p1,node p2)//得到ax+by+c=0的a,b,c
{
    a=p2.y-p1.y;            //a=y2-y1
    b=p1.x-p2.x;            //b=x1-x2
    c=p2.x*p1.y-p1.x*p2.y;  //c=x2*y1-x1*y
}

node cutpoint(node p1,node p2)//得到p1 p2与ax+by+c=0的交点
{
    double u=fabs(a*p1.x+b*p1.y+c);
    double v=fabs(a*p2.x+b*p2.y+c);
    node ans;
    ans.x=(p1.x*v+p2.x*u)/(u+v);
    ans.y=(p1.y*v+p2.y*u)/(u+v);

    return ans;
}

void cut()//对现有相邻的点连线切割
{
    int cutnum=0;
    for(int i=1;i<=m;i++)
    {
        if(a*p[i].x+b*p[i].y+c>=0)//此点在新图形中 顺时针>=0 逆时针<=0
            q[++cutnum]=p[i];//所以一个点在直线右边的话,那么带入值就会大于等于0 说明这个点还在切割后的多边形内,将其保留
        else//该点不在多边形内,但是它和它相邻的点构成直线与
        {
            if(a*p[i-1].x+b*p[i-1].y+c>0)
                q[++cutnum]=cutpoint(p[i-1],p[i]);//ax+by+c==0所构成的交点在新切割出的多边形内,所以保留交点

            if(a*p[i+1].x+b*p[i+1].y+c>0)
                q[++cutnum]=cutpoint(p[i],p[i+1]);
        }
    }
    for(int i=1;i<=cutnum;i++)//更新多边形内部点集合p
        p[i]=q[i];
    p[cutnum+1]=p[1];
    p[0]=q[cutnum];
    m=cutnum;//更新点数
}

void solve()
{
    for(int i=1;i<=n;i++)
        p[i]=point[i];
    point[n+1]=point[1];
    p[n+1]=p[1];
    p[0]=p[n];
    m=n;
    for(int i=1;i<=n;i++)
    {
        getline(point[i],point[i+1]);//根据point[i]和point[i+1]确定直线ax+by+c==0
        cut();//用直线ax+by+c==0切割多边形
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&point[i].x,&point[i].y);
        solve();
        if(m)//如果最后有剩下的点 也就是内核
            printf("YES\n");
        else
            printf("NO\n");
    }
}

poj 3130 逆时针给点,问是不是星形多边形

http://poj.org/problem?id=3130

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1005;
struct node
{
    double x,y;
};
node point[maxn];
node q[maxn];//临时保存新生成的点
node p[maxn];//保存新图的点
double a,b,c;
int ans;
int n,m;

void getline(node p1,node p2)//得到ax+by+c=0的a,b,c
{
    a=p2.y-p1.y;
    b=p1.x-p2.x;
    c=p2.x*p1.y-p1.x*p2.y;
}

node cutpoint(node p1,node p2)//得到p1 p2与ax+by+c=0的交点
{
    double u=fabs(a*p1.x+b*p1.y+c);
    double v=fabs(a*p2.x+b*p2.y+c);
    node ans;
    ans.x=(p1.x*v+p2.x*u)/(u+v);
    ans.y=(p1.y*v+p2.y*u)/(u+v);
    return ans;
}


void cut()//对现有相邻的点连线后是否在新图形中
{
    int cutnum=0;
    for(int i=1;i<=ans;i++)
    {
        if(a*p[i].x+b*p[i].y+c<=0)//此点在新图形中 顺时针>=0 逆时针<=0
            q[++cutnum]=p[i];
        else
        {
            if(a*p[i-1].x+b*p[i-1].y+c<0)//与此点相邻的前一个点在内
                q[++cutnum]=cutpoint(p[i-1],p[i]);//交点成为新图形的一个顶点 求两直线交点

            if(a*p[i+1].x+b*p[i+1].y+c<0)
                q[++cutnum]=cutpoint(p[i+1],p[i]);
        }
    }
    for(int i=1;i<=cutnum;i++)
        p[i]=q[i];
    p[cutnum+1]=q[1];
    p[0]=q[cutnum];
    ans=cutnum;
}

void solve()
{
    for(int i=1;i<=n;i++)
        p[i]=point[i];
    point[n+1]=point[1];
    p[n+1]=p[1];
    //p[0]=p[n];
    ans=n;

    for(int i=1;i<=n;i++)
    {
        getline(point[i],point[i+1]);
        cut();
    }
}

int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&point[i].x,&point[i].y);
        solve();
        if(ans)
            printf("1\n");
        else
            printf("0\n");
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值