• 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(续8)


     

    现在介绍平面上顶点集合凸包的Bentley-Faust-Preparata (BFP)方法,与前面讲解的Graham ScanAndrew's Monotone Chain方法不同之处是,预先并不需要将整个顶点集合一起按照XY轴数值排序。这种方法虽然是种近似方法,但时间复杂度降低,对于大数据量顶点的处理要求比较适合。

    基本方法是,取代整个顶点集合的依次XY轴排序,而首先依X轴数值大小划分几个区间,在每个区间中找到YminYmax顶点,以所有区间的这些顶点为预选,采用Andrew's Monotone Chain算法中使用过的“左转”方式来判断凸包条件是否成立,最后构成上下两个凸包子集,将其合并得到结果。其近似的原因是,每个区间可能不只有YminYmax等顶点作为预选。倘若将区间数量增大,则算法的准确性上升。

      
              参考代码:

    //     输入: 没有排序的顶点数组P[],数组中的顶点个数n,准备将X轴分开成 k个区间

    //     输出:  生成的凸包顶点集合H[]

    //     返回的数值: 凸包H[]中的顶点个数

    int CDEMAlgorithm::nearHull_2D( Point* P, int n, int k, Point* H )

    {

        int minmin=0, minmax=0; //准备记录X轴数值最小情况下Y轴数值最小和最大顶点索引

        int maxmin=0, maxmax=0; //准备记录X轴数值最大情况下Y轴数值最小和最大顶点索引

        double xmin = P[0].xxmax = P[0].x;   //初始化X轴最小和最大数值

        Point* cP;                       // 被处理的顶点

        int    bot=0, top=(-1);          // 指示栈底和栈顶

        for (int i=1; i<n; i++) {            //对所有顶点循环处理

            cP = &P[i];

            if (cP->x <= xmin) {

                if (cP->x < xmin) {        // 有更小的X轴数值出现

                     xmin = cP->x;

                     minmin = minmax = i//记录下顶点索引

                }

                else {                      // 若相同的X轴最小数值出现

                     if (cP->y < P[minmin].y)

                         minmin = i;          //记录下顶点索引,此时Y轴更小

                     else if (cP->y > P[minmax].y)

                         minmax = i;          //记录下顶点索引,此时Y轴更大

                }

            }

            if (cP->x >= xmax) {             // 有更大或相同的X轴数值出现

                if (cP->x > xmax) {        // 有比xmax还大的顶点出现

                     xmax = cP->x;

                     maxmin = maxmax = i;     //记录顶点索引

                }

                else {                      //若相同的X轴最大数值出现

                     if (cP->y < P[maxmin].y)

                         maxmin = i;          //记录下顶点索引,此时Y轴更小

                     else if (cP->y > P[maxmax].y)

                         maxmax = i;          //记录下顶点索引,此时Y轴更大

                }

            }

        }

        if (xmin == xmax) { // 一种极端情况出现:X轴最小与最大数值相同,即所有数值等同

            H[++top] = P[minmin];           //记录下此顶点

            if (minmax != minmin)           // 如果Y轴的数值不同

                H[++top] = P[minmax];        //记录下此顶点

            return top+1;                   // 返回顶点个数,这种特殊情况下是1或2个

        }

       

    Bin*   B = new Bin[k+2];   // 初始化区间数据结构

        B[0].min = minmin;         B[0].max = minmax;        // 设置第一个区间

        B[k+1].min = maxmin;       B[k+1].max = maxmax;      // 设置最后一个区间

        for (int b=1; b<=k; b++) {

            B[b].min = B[b].max = -99;   // 初始赋值

        }

        for (int b, i=0; i<n; i++) {     //循环处理每个顶点

            cP = &P[i];

            if (cP->x == xmin || cP->x == xmax) // 如果是整个集合中的X轴最小或最大数值

                continue;                    //继续下次循环

            if (isLeft( P[minmin], P[maxmin], *cP) < 0) { // 当前顶点处于低线之下

                b = (int)( k * (cP->x - xmin) / (xmax - xmin) ) + 1;//得Bin结构的序号

                if (B[b].min == -99)       // 这个Bin结构中还没有赋Y轴上的最低顶点

                     B[b].min = i;           //记录索引

                else if (cP->y < P[B[b].min].y //若比已经记录的最低数值还低

                     B[b].min = i;           // 新的最低顶点

                continue;

            }

            if (isLeft( P[minmax], P[maxmax], *cP) > 0) { //当前顶点处于高线之上

                b = (int)( k * (cP->x - xmin) / (xmax - xmin) ) + 1; //得Bin结构的序号

                if (B[b].max == -99)      // 这个Bin结构中还没有赋Y轴上的最高顶点

                     B[b].max = i;           //记录索引

                else if (cP->y > P[B[b].max].y) //若比已经记录的最高数值还高

                     B[b].max = i;           //新的最高顶点

                continue;

            }

        }

        //和前面讲解的Andrew's Monotone Chain算法中一样,使用 “左转”方式来判断凸包条件是否成立,分别构成上下两个子集

        for (int i=0; i <= k+1; ++i)//对每个区间循环处理

        {

            if (B[i].min == -99) // 如果区间中没有最低顶点记录的话,继续下次循环

                continue;

            cP = &P[ B[i].min ];   // 取出当前区间中的最低顶点

            while (top > 0)        // 当栈中至少有2个元素的时候,top > 0

            {

                // 看是否满足“左转”条件

                if (isLeft( H[top-1], H[top], *cP) > 0)

                     break;         // 此顶点是满足条件的新凸包顶点

                else

                     top--;         // 由于顶点破坏凸包条件,需要弹出栈顶元素,直到满足

            }

            H[++top] = *cP;        // 将这个顶点压入栈

        }

        //下面,计算上半部分的凸包顶点集合

        if (maxmax != maxmin)      //如果X轴数值最大情况下Y轴有不同顶点存在

            H[++top] = P[maxmax]; //将X轴数值与Y轴数值最大的顶点压入栈

        bot = top;                 //记住准备增加元素到栈前已经存在的元素个数

        for (int i=k; i >= 0; --i)   //对每个区间循环处理

        {

            if (B[i].max == -99) //如果区间中没有最高顶点记录的话,继续下次循环

                continue;

            cP = &P[ B[i].max ];   //取出当前区间中的最高顶点

            while (top > bot)      // top还是比开始记住的bot大,表明栈中至少有2个元素

            {

                // 看是否满足“左转”条件

                if (isLeft( H[top-1], H[top], *cP) > 0)

                     break;         //此顶点是满足条件的新凸包顶点

                else

                     top--;         //由于顶点破坏凸包条件,需要弹出栈顶元素,直到满足

            }

            H[++top] = *cP;        //将这个顶点压入栈

        }

        if (minmax != minmin)    //如果X轴数值最小情况下Y轴有不同顶点存在

            H[++top] = P[minmin]; //把这最后一个顶点压入栈

        delete B;                  // 释放

        return top+1;              //返回输出的凸包数组中的顶点个数
    }

  • 相关阅读:
    ms日期函数大全
    Sql server char,nchar,varchar与Nvarchar的区别
    clientX pageX
    jswindow对象的方法和属性资料
    Asp.Net中不修改IIS实现URL重写,支持任意扩展名及无扩展名
    该行已经属于另一个表的解决方法
    dopostBack机制(转)
    js触发asp.net的Button的Onclick事件
    Value、ReadString、ReadContentAsString、ReadElementContentAsString 区别
    有关元素元素位置的属性
  • 原文地址:https://www.cnblogs.com/wuhanhoutao/p/1114887.html
Copyright © 2020-2023  润新知