二维几何——多圆类:

主要计算面积并、面积交,覆盖多次面积:


const int maxn=1010;
struct circles
{
    circle c[maxn];
    double ans[maxn];//ans[i] 表示被覆盖了i次的面积
    double pre[maxn];
    int n;
    circles(){ n=0;}

    void add(circle cc)
    {
        c[n++]=cc;
    }

    //x包含在y中
    bool inner(circle x,circle y)
    {
        if(x.rel_of_circle(y)!=1) return 0;
        return sgn(x.r-y.r)<=0?1:0;
    }

    //圆的面积并去掉内含的圆
    void init_or(void)
    {
        bool mark[maxn];
        memset(mark,false,sizeof(mark));
        int i,j,k=0;
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                if(i!=j&&!mark[j])
                {
                    if((c[i]==c[j])||inner(c[i],c[j])) break;
                }
            }
            if(j<n) mark[i]=true;
        }
        for(int i=0;i<n;i++)
            if(!mark[i]) c[k++]=c[i];
        n=k;
    }


    //圆的面积交去掉内含的圆
    void init_add(void)
    {
        bool mark[maxn];
        memset(mark,false,sizeof(mark));
        int i,j,k=0;
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                if(i!=j&&!mark[j])
                {
                    if((c[i]==c[j])||inner(c[j],c[i])) break;
                }
            }
            if(j<n) mark[i]=true;
        }
        for(int i=0;i<n;i++)
            if(!mark[i]) c[k++]=c[i];
        n=k;
    }
    //半径为 r 的圆,弧度为 th 对应的弓形的面积
    double area_arc(double th,double r)
    {
        return 0.5*r*r*(th-sin(th));
    }
    //求 n 个圆并的面积,需要加上 init_or() 去掉重复圆(否则 WA)
    //求被覆盖 k 次的面积,不能加 init_or()
    //对于求覆盖多少次面积的问题,不能解决相同圆,而且不能 init_or()
    //求多圆面积并,需要 init_or(), 其中一个目的就是去掉相同圆
    void get_area(void)
    {
        for(int i=0;i<maxn;i++)
            ans[i]=0.0;
        vector<pair<double,int> >v;
        for(int i=0;i<n;i++)
        {
            v.clear();
            v.push_back(make_pair(-pi,1));
            v.push_back(make_pair(pi,-1));
            for(int j=0;j<n;j++)
            {
                if(i!=j)
                {
                    Point q=(c[j].p-c[i].p);
                    double ab=q.len(),ac=c[i].r,bc=c[j].r;
                    if(sgn(ab+ac-bc)<=0)
                    {
                        v.push_back(make_pair(-pi,1));
                        v.push_back(make_pair(pi,-1));
                        continue;
                    }
                    if(sgn(ab+bc-ac)<=0) continue;
                    if(sgn(ab-ac-bc)>0) continue;
                    double th=atan2(q.y,q.x),fai=acos((ac*ac+ab*ab-bc*bc)/(2.0*ac*ab));
                    double a0=th-fai;
                    if(sgn(a0+pi)<0) a0+=2*pi;
                    double a1=th+fai;
                    if(sgn(a1-pi)>0) a1-=2*pi;
                    if(sgn(a0-a1)>0)
                    {
                        v.push_back(make_pair(a0,1));
                        v.push_back(make_pair(pi,-1));
                        v.push_back(make_pair(-pi,1));
                        v.push_back(make_pair(a1,-1));
                    }
                    else
                    {
                        v.push_back(make_pair(a0,1));
                        v.push_back(make_pair(a1,-1));
                    }
                }
            }
            sort(v.begin(),v.end());
            int cur=0;
            for(int j=0;j<v.size();j++)
            {
                if(cur&&sgn(v[j].first-pre[cur]))
                {
                    ans[cur]+=area_arc(v[j].first-pre[cur],c[i].r);
                    ans[cur]+=0.5*(Point(c[i].p.x+c[i].r*cos(pre[cur]),c[i].p.y+c[i].r*sin(pre[cur]))^Point(c[i].p.x+c[i].r*cos(v[j].first),c[i].p.y+c[i].r*sin(v[j].first)));

                }
                cur+=v[j].second;
                pre[cur]=v[j].first;
            }
        }
        for(int i=1;i<n;i++)
            ans[i]-=ans[i+1];
    }

};



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值