計算幾何模板綜合第二彈 圓

#include <bits/stdc++.h>
using namespace std;
const double eps=-1e8;
const double pi=acos(-1);
const int maxn=1005;
int cmp(double x)
{
    if(abs(x)<eps)
        return 0;
    if(x>0)
        return 1;
    return -1;
}
inline double sqr(double x)
{
    return x*x;
}
struct point
{
    double x,y;
    point(){}
    point(double a,double b):x(a),y(b){}
    void input()
    {
        scanf("%lf%lf",&x,&y);
    }
    friend point operator +(const point &a,const point &b)
    {
        return point(a.x+b.x,a.y+b.y);
    }
    friend point operator -(const point &a,const point &b)
    {
        return point(a.x-b.x,a.y-b.y);
    }
    friend bool operator ==(const point &a,const point &b)
    {
        return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;
    }
    friend point operator *(const point &a,const double &b)
    {
        return point(a.x*b,a.y*b);
    }
    friend point operator *(const double &a,const point &b)
    {
        return point(a*b.x,a*b.y);
    }
    friend point operator /(const point &a,const double &b)
    {
        return point(a.x/b,a.y/b);
    }
    double norm()
    {
        return sqrt(sqr(x)+sqr(y));
    }
};
double det(const point &a,const point &b)//計算兩個向量的叉積
{
    return a.x*b.y-a.y*b.x;
}
double dot(const point &a,const point &b)//計算兩個向量的點積
{
    return a.x*b.x+a.y*b.y;
}
double dist(const point &a,const point &b)
{
    return (a-b).norm();
}
point rotate_point(const point &p,double A)//向量op繞原點逆時針旋轉弧度A
{
    double tx=p.x,ty=p.y;
    return point(tx*cos(A)-ty*sin(A),tx*sin(A)+ty*cos(A));
}
double abs(const point &o)
{
    return sqrt(dot(o,o));
}
double mysqrt(double n)
{
    return sqrt(max(0.0,n));
}
void circle_cross_line(point a,point b,point o,double r,point res[],int &num)//求圓與線段(直線)的交點
{
    double x0=o.x,y0=o.y;
    double x1=a.x,y1=a.y;
    double x2=b.x,y2=b.y;
    double dx=x2-x1,dy=y2-y1;
    double A=dx*dx+dy*dy;
    double B=2*dx*(x1-x0)+2*dy*(y1-y0);
    double C=sqr(x1-x0)+sqr(y1-y0)-sqr(r);
    double delta=B*B-4*A*C;
    num=0;
    if(cmp(delta)>=0)
    {
        double t1=(-B-mysqrt(delta))/(2*A);
        double t2=(-B+mysqrt(delta))/(2*A);
        if(cmp(t1-1)<=0&&cmp(t1)>=0)
            res[num++]=point(x1+t1*dx,y1+t1*dy);
        if(cmp(t2-1)<=0&&cmp(t2)>=0)
            res[num++]=point(x1+t2*dx,y1+t2*dy);
    }
}
point crosspt(const point &a,const point &b,const point &p,const point &q)
{
    double a1=det(b-a,p-a);
    double a2=det(b-a,q-a);
    return (p*a2-q*a1)/(a2-a1);
}
point res[maxn];//逆時針存入多邊形的所有點
double r;//圓的半徑
int n;//多邊形點的個數
double sector_area(const point &a,const point &b)
{
    double theta=atan2(a.y,a.x)-atan2(b.y,b.x);
    while(theta<=0) theta+=2*pi;
    while(theta>2*pi) theta-=2*pi;
    theta=min(theta,2*pi-theta);
    return r*r*theta/2;
}
double calc(const point &a,const point &b)
{
    point p[2];
    int num=0;
    int ina=cmp(abs(a)-r)<0;
    int inb=cmp(abs(b)-r)<0;
    if(ina)
    {
        if(inb)
            return fabs(det(a,b))/2.0;
        else
        {
            circle_cross_line(a,b,point(0,0),r,p,num);
            return sector_area(b,p[0])+fabs(det(a,p[0]))/2.0;
        }
    }
    else
    {
        if(inb)
        {
            circle_cross_line(a,b,point(0,0),r,p,num);
            return sector_area(p[0],a)+fabs(det(p[0],b))/2.0;
        }
        else
        {
            circle_cross_line(a,b,point(0,0),r,p,num);
            if(num==2)
                return sector_area(a,p[0])+sector_area(p[1],b)+fabs(det(p[0],p[1]))/2.0;
            else return sector_area(a,b);
        }
    }
}
double area()//圓與多邊形的交的面積
{
    double ret=0;
    for(int i=0;i<n;i++)
    {
        int sgn=cmp(det(res[i],res[i+1]));
        if(sgn!=0)
        {
            ret+=sgn*calc(res[i],res[i+1]);
        }
    }
    return ret;
}//需要保證res[n]=res[0]




void circle_center(point p0,point p1,point p2,point &cp)
{
    double a1=p1.x-p0.x,b1=p1.y-p0.y,c1=(a1*a1+b1*b1)/2;
    double a2=p2.x-p0.x,b2=p2.y-p0.y,c2=(a2*a2+b2*b2)/2;
    double d=a1*b2-a2*b1;
    cp.x=p0.x+(c1*b2-c2*b1)/d;
    cp.y=p0.y+(a1*c2-a2*c1)/d;
}
void circle_center(point p0,point p1,point &cp)
{
    cp.x=(p0.x+p1.x)/2;
    cp.y=(p0.y+p1.y)/2;
}
point center;//最小覆蓋圓的圓心
double radius;//最小覆蓋圓的半徑
bool point_in(const point &p)
{
    return cmp((p-center).norm()-radius)<0;
}
void min_circle_cover(point a[],int n)//O(n)求一個半徑最小的圓覆蓋住所有的點
{
    radius=0;
    center=a[0];
    for(int i=1;i<n;i++)
    {
        if(!point_in(a[i]))
        {
            center=a[i];
            radius=0;
            for(int j=0;j<i;j++)
            {
                if(!point_in(a[j]))
                {
                    circle_center(a[i],a[j],center);
                    radius=(a[j]-center).norm();
                    for(int k=0;k<j;k++)
                    {
                        if(!point_in(a[k]))
                        {
                            circle_center(a[i],a[j],a[k],center);
                            radius=(a[k]-center).norm();
                        }
                    }
                }
            }
        }
    }
}




point rotate(const point &p,double cost,double sint)//將向量p旋轉一定弧度得到的向量(cost和sint爲弧度的cos和sin值)
{
    double x=p.x,y=p.y;
    return point(x*cost-y*sint,x*sint+y*cost);
}
pair<point,point> crosspoint(point ap,double ar,point bp,double br)
{
    double d=(ap-bp).norm();
    double cost=(ar*ar+d*d-br*br)/(2*ar*d);
    double sint=sqrt(1.0-cost*cost);
    point v=(bp-ap)/(bp-ap).norm()*ar;
    return make_pair(ap+rotate(v,cost,-sint),ap+rotate(v,cost,sint));
}//需要確定兩圓存在交點



namespace getunion
{
const int maxN=maxn*maxn+3*maxn;
struct Tcir
{
    double r;
    point o;
    void read()
    {
        scanf("%lf%lf%lf",&o.x,&o.y,&r);
    }
};
struct Tinterval
{
    double x,y,Area,mid;
    int type;
    Tcir owner;
    void area(double l,double r)
    {
        double len=sqrt(sqr(l-r)+sqr(x-y));
        double d=sqrt(sqr(owner.r)-sqr(len)/4.0);
        double angle=atan(len/2.0/d);
        Area=fabs(angle*sqr(owner.r)-d*len/2.0);
    }
}inter[maxn];
double x[maxN],l,r;
int n,N,Nn;
bool cmpR(const Tcir &a,const Tcir &b)
{
    return a.r>b.r;
}
void Get(Tcir owner,double x,double &l,double &r)
{
    double y=fabs(owner.o.x-x);
    double d=sqrt(fabs(sqr(owner.r)-sqr(y)));
    l=owner.o.y+d;
    r=owner.o.y-d;
}
void Get_interval(Tcir owner,double l,double r)
{
    Get(owner,l,inter[Nn].x,inter[Nn+1].x);
    Get(owner,r,inter[Nn].y,inter[Nn+1].y);
    Get(owner,(l+r)/2.0,inter[Nn].mid,inter[Nn+1].mid);
    inter[Nn].owner=inter[Nn+1].owner=owner;
    inter[Nn].area(l,r);inter[Nn+1].area(l,r);
    inter[Nn].type=1;inter[Nn+1].type=-1;
    Nn+=2;
}
bool comp(const Tinterval &a,const Tinterval &b)
{
    return a.mid>b.mid+eps;
}
void Add(double xx)
{
    x[N++]=xx;
}
double dist2(const point &a,const point &b)
{
    return sqr(dist(a,b));
}
double getunion(int n,Tcir a[])//複雜度O(n^3logn)求圓的面積並(離散化思想)
{
    int p=0;
    sort(a,a+n,cmpR);
    for(int i=0;i<n;i++)
    {
        bool f1=true;
        for(int j=0;j<i;j++)
        {
            if(dist2(a[i].o,a[j].o)<=sqr(a[i].r-a[j].r)+1e-12)
            {
                f1=false;
                break;
            }
        }
        if(f1)
            a[p++]=a[i];
    }
    n=p;
    N=0;
    for(int i=0;i<n;i++)
    {
        Add(a[i].o.x-a[i].r);
        Add(a[i].o.x+a[i].r);
        Add(a[i].o.x);
        for(int j=i+1;j<n;j++)
        {
            if(dist2(a[i].o,a[j].o)<=sqr(a[i].r+a[j].r)+eps)
            {
                pair<point,point> cross=crosspoint(a[i].o,a[i].r,a[j].o,a[j].r);
                Add(cross.first.x);
                Add(cross.second.x);
            }
        }
    }
    sort(x,x+N);
    p=0;
    for(int i=0;i<N;i++)
    {
        if(!i||fabs(x[i]-x[i-1])>eps)
            x[p++]=x[i];
    }
    N=p;
    double ans=0;
    for(int i=0;i+1<N;i++)
    {
        l=x[i],r=x[i+1];
        Nn=0;
        for(int j=0;j<n;j++)
        {
            if(fabs(a[j].o.x-l)<a[j].r+eps&&fabs(a[j].o.x-r)<a[j].r+eps)
                Get_interval(a[j],l,r);
        }
        if(Nn)
        {
            sort(inter,inter+Nn,comp);
            int cnt=0;
            for(int i=0;i<Nn;i++)
            {
                if(cnt>0)
                {
                    ans+=(fabs(inter[i-1].x-inter[i].x)+fabs(inter[i-1].y-inter[i].y))*(r-l)/2.0;
                    ans+=inter[i-1].type*inter[i-1].Area;
                    ans-=inter[i].type*inter[i].Area;
                }
                cnt+=inter[i].type;
            }
        }
    }
    return ans;
}    }




namespace fenge
{
struct Circle
{
    point p;
    double r;
    bool operator<(const Circle &o)const
    {
        if(cmp(r-o.r)!=0)
            return cmp(r-o.r)==-1;
        if(cmp(p.x-o.p.x)!=0)
        {
            return cmp(p.x-o.p.x)==-1;
        }
        return cmp(p.y-o.p.y)==-1;
    }
    bool operator==(const Circle &o)const
    {
        return cmp(r-o.r)==0&&cmp(p.x-o.p.x==0)&&cmp(p.y-o.p.y)==0;
    }
};
inline pair<point,point> crosspoint(const Circle &a,const Circle &b)
{
    return crosspoint(a.p,a.r,b.p,b.r);
}
Circle c[maxn],tc[maxn];
int n,m;
struct Node
{
    point p;
    double a;
    int d;
    Node(const point &p,double a,int d):p(p),a(a),d(d){}
    bool operator<(const Node &o)const
    {
        return a<o.a;
    }
};
double arg(point p)
{
    return arg(complex<double>(p.x,p.y));
}
double solve()////複雜度O(m^2logm)求圓的面積並(分割的思想)
{
    sort(tc,tc+m);
    m=unique(tc,tc+m)-tc;
    for(int i=m-1;i>=0;i--)
    {
        bool ok=true;
        for(int j=i+1;j<m;j++)
        {
            double d=(tc[i].p,tc[j].p).norm();
            if(cmp(d-abs(tc[i].r-tc[j].r))<=0)
            {
                ok=false;
                break;
            }
        }
        if(ok)
            c[n++]=tc[i];
    }
    double ans=0;
    for(int i=0;i<n;i++)
    {
        vector<Node> event;
        point boundary=c[i].p+point(-c[i].r,0);
        event.push_back(Node(boundary,-pi,0));
        event.push_back(Node(boundary,pi,0));
        for(int j=0;j<n;j++)
        {
            if(i==j) continue;
            double d=(c[i].p-c[j].p).norm();
            if(cmp(d-(c[i].r+c[j].r))<0)
            {
                pair<point,point> ret=crosspoint(c[i],c[j]);
                double x=arg(ret.first-c[i].p);
                double y=arg(ret.second-c[i].p);
                if(cmp(x-y)>0)
                {
                    event.push_back(Node(ret.first,x,1));
                    event.push_back(Node(boundary,pi,-1));
                    event.push_back(Node(boundary,-pi,1));
                    event.push_back(Node(ret.second,y,-1));
                }
                else
                {
                    event.push_back(Node(ret.first,x,1));
                    event.push_back(Node(ret.second,y,-1));
                }
            }
        }
        sort(event.begin(),event.end());
        int sum=event[0].d;
        for(int j=1;j<(int)event.size();j++)
        {
            if(sum==0)
            {
                ans+=det(event[j-1].p,event[j].p)/2;
                double x=event[j-1].a;
                double y=event[j].a;
                double area=c[i].r*c[i].r*(y-x)/2;
                point v1=event[j-1].p-c[i].p;
                point v2=event[j].p-c[i].p;
                area-=det(v1,v2)/2;
                ans+=area;
            }
            sum+=event[j].d;
        }
    }
    return ans;
}  }

 

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