• 计算几何总结


    基础的东西

    一些定义

    typedef double db;
    struct poi{
        db x,y;
        poi(db X=0,db Y=0) {x=X,y=Y;}
        db len() { return sqrt(x*x+y*y); }
    };
    poi operator + (poi a,poi b) {return poi(a.x+b.x,a.y+b.y);}
    poi operator - (poi a,poi b) {return poi(a.x-b.x,a.y-b.y);}
    poi operator * (poi a,db p) {return poi(a.x*p,a.y*p);}
    poi operator / (poi a,db p) {return poi(a.x/p,a.y/p);}

    判断正负0

    //判断正负0
    int sign(db x)
    {
        if(fabs(x)<eps) return 0;
        if(x>0) return 1;
        return -1;
    }

     向量旋转

    poi rotate(db c){return (poi){x*cos(c)-y*sin(c),x*sin(c)+y*cos(c)};}
        //逆时针旋转-pi~pi

    判断线段和直线是否相交 2984. 线段

    //跨立实验:判断一条线段的两端是否在另一条线段的两侧(两个端点与另一线段的叉积乘积为负)。需要正反判断两侧。
    int panxdj(poi a,poi b,poi c,poi d)//ab线段,cd直线
    {
        if(sign(c.x-d.x)==0&&sign(c.y-d.y)==0) return 0;//直线不能是一个点
        if(sign(cross(a-c,d-c)*cross(b-c,d-c))>0) return 0;
        return 1;
    }

    判断点在直线上

    int cxd(poi a,poi b,poi p)
    //p-a x p-b ==0 && p-a * p-b <=0
    {
        if(sign(cross(p-a,p-b))==0&&sign(dot(p-a,p-b))<=0) return 1;
        return 0;
    }

    射线法判断点在多边形内

    db dbarea()
    {
        db res=0;
        for(int i=1;i<=n;i++)
        res+=cross(a[i],a[i+1]);
        return res;
    }
    
    int cdb(poi p)
    {
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            if(cxd(a[i],a[i+1],p)) return 1;
            int d1=sign(a[i].y-p.y),d2=sign(a[i+1].y-p.y);
            int det=sign(cross(a[i]-p,a[i+1]-p));//cross
            if((det>=0&&d1<0&&d2>=0)||(det<=0&&d1>=0&&d2<0)) cnt++;
        }
        return cnt&1;
    }
    
    
    for(int i=1;i<=n;i++)
    scanf("%lf %lf",&a[i].x,&a[i].y);
    a[n+1]=a[1];
    if(sign(dbarea())<0)
    {
        reverse(a+1,a+n+1);
        a[n+1]=a[1];
    }

    判断两直线关系 

    先判重合,再判平行,再求交点

    db cross(poi a,poi b)
    {
        return a.x*b.y-b.x*a.y;
    }
    poi zhixianjd(poi a,poi b,poi c,poi d)
    {
        poi p;
        db s1=cross(c-a,d-a),s2=cross(d-b,c-b);//s1 ac*ad s2 bd*bc
        p=s1/(s1+s2)*(b-a)+a;
        return p;
    }
    int pandianxian(poi a,poi b,poi p)
    {
        if(sign(cross(p-a,p-b))==0) return 1;
        return 0;
    }
    if(pandianxian(a,b,c)&&pandianxian(a,b,d))
    {
        cout<<"LINE"<<endl;
        continue;
    }
    if(sign(cross(b-a,d-c))==0)
    {
        cout<<"NONE"<<endl;
        continue;
    }
    poi p=zhixianjd(a,b,c,d);

     求凸包

    poi dian[N];
    int cmp(poi l,poi r)
    {
        int det=sing(cross(l-dian[1],r-dian[1]));
        if(det) return det>0;
        return (l-dian[1]).len()<(r-dian[1]).len();
    }
    int n,m;
    poi p[N];
    void graham()
    {
        int k=1;
        for(int i=2;i<=n;i++)
        if(dian[i].x<dian[k].x||(sing(dian[i].x-dian[k].x)==0&&dian[i].y<dian[k].y)) k=i;
        if(k^1) swap(dian[1],dian[k]);
        sort(dian+2,dian+n+1,cmp);
        //for(int i=1;i<=n;i++) cout<<dian[i].x<<" "<<dian[i].y<<endl;
        m=1;
        p[1]=dian[1];
        for(int i=2;i<=n;i++)
        {
            while(m-1&&sing(cross(p[m]-dian[i],p[m-1]-p[m]))>=0) m--;
            p[++m]=dian[i];
        }
    }

    半平面交

    int l=1,r=1;
    int cmp(qw l,qw r)
    {
        db t1=atan2(l.b.y-l.a.y,l.b.x-l.a.x),t2=atan2(r.b.y-r.a.y,r.b.x-r.a.x);
        if(sing(t1-t2)!=0) return t1<t2;
        return sing(cross(l.b-l.a,r.a-l.a))<0;//r.a
    }
    db ang(qw xian)
    {
        return atan2(xian.b.y-xian.a.y,xian.b.x-xian.a.x);
    }
    void bpingj()
    {
        sort(line+1,line+n+1,cmp);
        q[1]=line[1];
        for(int i=2;i<=n;i++)
        {
            poi a=line[i].a,b=line[i].b;
            if(sing(ang(line[i])-ang(line[i-1]))==0) continue;
            while(l<r&&sing(cross(b-a,jd[r]-a))<=0) r--;
            while(l<r&&sing(cross(b-a,jd[l+1]-a))<=0) l++;
            q[++r]=line[i];
            if(l<r) jd[r]=zhixianjd(q[r-1].a,q[r-1].b,a,b);
        }
        while(l<r&&sing(cross(q[l].b-q[l].a,jd[r]-q[l].a))<=0) r--;
        jd[r+1]=zhixianjd(q[l].a,q[l].b,q[r].a,q[r].b);
        r++;
    }

    最小圆覆盖

    cir get_cir(poi i,poi j,poi k)
    {
        poi p1,p2;
        p1=(i+j)/2+(j-i).rotate(pi/2);
        p2=(i+k)/2+(k-i).rotate(pi/2);
        poi jd=zhixianjd((i+j)/2,p1,(i+k)/2,p2);
        cir c;
        c.a=jd;
        c.r=(jd-i).len();//i
        return c;
    }
        
    random_shuffle(dian+1,dian+n+1);
    cir c=(cir){dian[1],0};
    for(int i=2;i<=n;i++)
    if(sing((dian[i]-c.a).len()-c.r)==1)
    {
        c=(cir){dian[i],0};
        for(int j=1;j<i;j++)
        if(sing((dian[j]-c.a).len()-c.r)==1)
        {
            c=(cir){(dian[i]+dian[j])/2,(dian[i]-dian[j]).len()/2};
            for(int k=1;k<j;k++)
            if(sing((dian[k]-c.a).len()-c.r)==1)
            {
                 c=get_cir(dian[i],dian[j],dian[k]);
            }
        }
    }

    三维凸包

    #include<bits/stdc++.h>
    using namespace std;
    const int N=405;
    typedef double db;
    const db eps=1e-12;
    struct poi{
        db x,y,z;
        poi(db X=0,db Y=0,db Z=0){x=X,y=Y,z=Z;}
        db len(){return sqrt(x*x+y*y+z*z);}
        db rand_eps(){return ((db)rand()/RAND_MAX-0.5)*eps;}
        void shake() { x+=rand_eps(),y+=rand_eps(),z+=rand_eps(); }
    }dian[N];
    poi operator + (poi a,poi b){return (poi){a.x+b.x,a.y+b.y,a.z+b.z};}
    poi operator - (poi a,poi b){return (poi){a.x-b.x,a.y-b.y,a.z-b.z};}
    db dot(poi a,poi b)
    {
        return a.x*b.x+a.y*b.y+a.z*b.z;
    }
    poi cross(poi a,poi b)
    {
        return (poi){a.y*b.z-b.y*a.z,a.z*b.x-b.z*a.x,a.x*b.y-b.x*a.y};
    }
    struct plane{
        int v[3];
        poi a,b,c;
        poi normal()//求法向量
        {
            return cross(c-a,b-a);
        }
        db area()//求面积
        {
            return normal().len()/2;
        }
        int above(poi p)
        {
            return dot(p-a,normal())>=0;
        }
    }pl[N],lb[N];
    bool g[N][N];
    int n,m;
    void get_tubao3()
    {
        pl[++m]=(plane){1,2,3,dian[1],dian[2],dian[3]};
        pl[++m]=(plane){3,2,1,dian[3],dian[2],dian[1]};
        for(int i=4;i<=n;i++)
        {
            int cnt=0;
            for(int j=1;j<=m;j++)
            {
                int t=pl[j].above(dian[i]);
                if(!t) lb[++cnt]=pl[j];
                for(int k=0;k<3;k++)
                g[pl[j].v[k]][pl[j].v[(k+1)%3]]=t;
            }
            for(int j=1;j<=m;j++)
            for(int k=0;k<3;k++)//不要写xxx+xxx==1 这样的话面就重复了,一开始加两个一样的面是为了让4一定有面做底,另一个面和4一起组成另外三个面
            if(g[pl[j].v[k]][pl[j].v[(k+1)%3]]&&!g[pl[j].v[(k+1)%3]][pl[j].v[k]])
                lb[++cnt]={pl[j].v[k],pl[j].v[(k+1)%3],i,dian[pl[j].v[k]],dian[pl[j].v[(k+1)%3]],dian[i]};
            m=cnt;
            for(int j=1;j<=cnt;j++) pl[j]=lb[j];
        }
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        scanf("%lf %lf %lf",&dian[i].x,&dian[i].y,&dian[i].z);
        for(int i=1;i<=n;i++) dian[i].shake();
        get_tubao3();
        db res=0;
        for(int i=1;i<=m;i++) res+=pl[i].area();
        printf("%.6lf",res);
        return 0;
    }

    旋转卡壳

        db res=0;
        for(int i=1,j=3;i<=m;i++)
        {
            poi a=p[i],b=p[i%m+1];
            while(sing(fabs(cross(a-b,a-p[j%m+1]))-fabs(cross(a-b,a-p[j])))>0) j=j%m+1;
            res=max(res,(p[j]-a).len());
            res=max(res,(p[j]-b).len());
        }

    扫描线

    区间合并

            ll num=0;
            int st=la[1].x,ed=la[1].y;
            for(int j=2;j<=cnt;j++)
            if(la[j].x<=ed) ed=max(ed,la[j].y);
            else res+=1ll*(ed-st)*(r-l+1),st=la[j].x,ed=la[j].y;
            num+=1ll*(ed-st)*(r-l+1);

    自适应辛普森积分

    db spi(db a,db b)
    {
        return (f(a)+4*f((a+b)/2)+f(b))*(b-a)/6;
    }
    db xps(db a,db b)
    {
        db s=spi(a,b),l=spi(a,(a+b)/2),r=spi((a+b)/2,b);
        if(fabs(s-l-r)<=eps) return s;
        return xps(a,(a+b)/2)+xps((a+b)/2,b);
    }

    f是自己定义的函数

  • 相关阅读:
    php无刷新上传图片和文件
    wamp(win1064位家庭版+apache2.4.20+php5.5.37+mysql5.5.50)环境搭建
    linux下常见解压缩命令
    nginx虚拟主机配置小结
    Nginx下配置ThinkPHP的URL Rewrite模式和pathinfo模式支持
    iframe 高度自适应/以及在ie8中空白问题
    小程序-调用公共js对象方法/ app.js
    小程序-tabbar相关样式设置
    微信小程序连接无法跳转/ can not navigate to tabBar page错误
    微信小程序-tabBar无法显示问题解析
  • 原文地址:https://www.cnblogs.com/xsm098/p/14819143.html
Copyright © 2020-2023  润新知