計算幾何 求簡單多邊形的內核(是否是星形多邊形)

星形多邊形是什麼呢?其實就是在多邊形內部存在一個點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");
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章