zoukankan      html  css  js  c++  java
  • [模板]多边形面积交

    1.必须逆时针给出多边形顶点

    2.面积并 = 面积和 - 面积交 

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 300;
    const double eps = 1e-8;
    int dcmp(double x){         //精度误差比较
        if(x > eps) return 1;
        return x < -eps ? -1 : 0;
    }
    struct Point{double x, y;}; //点结构体
    double cross(Point a,Point b,Point c){return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);}//叉积
    Point intersection(Point a,Point b,Point c,Point d){//传入四点即两直线,输出交点
        Point p = a;
        double t =((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))/((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x));
        p.x +=(b.x-a.x)*t;
        p.y +=(b.y-a.y)*t;
        return p;//输出交点,证明用数学方法易证
    }
    double PolygonArea(Point p[], int n){//计算多边形面积,三角剖分
        if(n < 3) return 0.0;
        double s = p[0].y * (p[n - 1].x - p[1].x);
        p[n] = p[0];
        for(int i = 1; i < n; ++ i)
            s += p[i].y * (p[i - 1].x - p[i + 1].x);
        return fabs(s * 0.5);//叉乘出来是平行四边形面积故/2,且顺逆方向不定,故取ABS变正
    }
    double CPIA(Point a[], Point b[], int na, int nb){//传入两个三角形,求相交部分的凸包
        Point p[20], tmp[20];           //复制点集与临时点集(P其实可以用B来做
        int tn, sflag, eflag;           //每轮相交凸包的点,叉乘符号
        a[na] = a[0], b[nb] = b[0];     //末点用初点复制方便首末点连边
        memcpy(p,b,sizeof(Point)*(nb + 1));         //把B复制到P
        for(int i=0;i<na&&nb>2;i++){                //扫一次A
            sflag=dcmp(cross(a[i+1],p[0],a[i]));    //取A两点与B第一点求叉乘符号
            for(int j=tn=0;j<nb;j++,sflag=eflag){   //扫一次B,更新TMP,TN是点数
                if(sflag>=0)tmp[tn++]=p[j];         //叉乘为正就是B数组的那个点压入
                eflag=dcmp(cross(a[i+1],p[j+1],a[i]));//求叉乘符号
                if((sflag^eflag)==-2)               //1异或-1等于-2
                tmp[tn++]=intersection(a[i],a[i+1],p[j],p[j+1]);//求交点
            }
            memcpy(p, tmp, sizeof(Point) * tn);     //把TMP复制到P
            nb = tn, p[nb] = p[0];//TN即TMP点数记到NB
        }//其实该是NP表示P数组个数,这里省了个变量就用NB表示,下面第二行做参数而已
        if(nb < 3) return 0.0;      //相交部分凸包不够三个点,面积就是0
        return PolygonArea(p, nb);  //求出相交凸包部分的面积
    }
    double SPIA(Point a[], Point b[], int na, int nb){//传入两个多边形的点
        int i,j;                            //循环变量
        Point t1[4],t2[4];                  //其实T13与T23没用上
        double res=0,num1,num2;             //答案初始化,及叉乘符号
        a[na]=t1[0]=a[0],b[nb]=t2[0]=b[0];  //初始化T1,T2和ANA,BNB
        for(i=2;i<na;i++){                  //扫一次第一个多边形全部点
            t1[1]=a[i-1],t1[2]=a[i];        //每次在第一个多边形取两个点赋给T11,T12
            num1=dcmp(cross(t1[1],t1[2],t1[0]));//求出叉乘符号
            if(num1<0)swap(t1[1],t1[2]);    //小于0则改变T11,T12可使叉乘符号变正,实即改变T1三个点的顺逆
            for(j=2;j<nb;j++){              //扫一次第二个多边形全部点
                t2[1]=b[j-1],t2[2]=b[j];    //然后再在第二个多边形取两个点赋给T21,T22
                num2=dcmp(cross(t2[1],t2[2],t2[0]));//求出叉乘符号
                if(num2<0)swap(t2[1],t2[2]);//小于0则改变T11,T12可使叉乘符号变正,实即改变T1三个点的顺逆
                res+=CPIA(t1,t2,3,3);       //累加相交部分面积
            }
        }
        return res;
    }
    Point p1[maxn], p2[maxn];//两个数组存读入点集
    int main(){
        int n1, n2;         //定义
        while(cin>>n1>>n2){ //输入两个多边形的点数
            for(int i=0;i<n1;i++)scanf("%lf%lf",&p1[i].x,&p1[i].y);//输入点数
            for(int i=0;i<n2;i++)scanf("%lf%lf",&p2[i].x,&p2[i].y);//输入点数
            cout<<SPIA(p1,p2,n1,n2)<<endl;//输出面积交
        }//如果要求面积并,则先用三角剖分分别求两个多边形的面积S1,S2,然后S1+S2-面积交即可
        return 0;
    }
    /*
    in
    4 4
    0 0 1 0 1 1 0 1
    0.5 0.5 -1 0.5 -1 -1 0.5 -1
    out
    0.25
    int
    4 4
    0 0 5 0 5 5 0 5
    -1 -1 4 -1 4 4 -1 4
    out
    16
    */
    
  • 相关阅读:
    算法很美(一)
    pytest学习(四)
    pytest学习(三)
    pytest学习(二)
    pytest学习(一)
    HTTP协议详细介绍,面试详全强助攻!
    Docker实战总结
    微信小程序测试整理
    这些用例设计题,你在面试时遇到过吗?
    测试面试题集-Dubbo常见面试题(12)
  • 原文地址:https://www.cnblogs.com/zeolim/p/12270334.html
Copyright © 2011-2022 走看看