• GIS矢量数据化简:一种改进的道格拉斯-普克算法以及C++实现


    GIS领域的同志都知道,传统的道格拉斯-普克算法都是递归实现。然而有时候递归的层次太深的话会出现栈溢出的情况。在此,介绍一种非递归的算法。

           要将递归算法改为非递归算法,一般情况下分为两种场景。第一种是问题定义是递归的,如阶乘、斐波那契数列等,对于这类问题,改为递归算法很简单,直接用迭代来做。另外一种是过程是递归的,如本文的道格拉斯-普克算法,对于这类问题呢,一般是用栈(stack)来记录中间结果,最后得到结果。

            为了保证极值点的不被舍去,将曲线在弯曲极值点分为两段处理,弯曲极值点通过中间点与相邻两个顶点的角度度量。然而传统的Douglas-Peucker算法一般在计算过程中没有考虑到记录中间最大的距离的节点,造成循环时间长、递归嵌套层次太深,从而影响了程序的运行效率。本文提出一种结合栈数据结构的分段Douglas-Peucker算法,它从曲线的一端出发,首先将第一个点和最后一个点作为改进的Douglas-Peucker算法的工作区间,然后判断最远点的距离是否大于阈值,这样完成线要素的综合化简。改进D-P算法的具体步骤如下:

    (1)寻找曲线曲率最大的点,将曲线以此点为界一分为二分成两部分,对于每一部分都有点列 。然后分别处理这两段曲线。

    (2)对于第一段曲线,有矢量的离散点序列 ,设 并且 ,连接 组成一条线段。生成一个栈 ,将 点入栈 。

    (3)在 之间的点中寻找与 线段距离最大的点,记为 。

    (4)判断 点到 的距离是否小于阈值,若否,则设 ,并将 加入到特征点序列,将 压入栈 ,用线段连接 ,回到(3)。若是,执行第(5)步。

    (5)判断 是否等于 的栈顶元素,若否,则设 、 , 表示栈顶,用线段连接 ,回到(3)。若是,执行(6)。

    (6)判断 是否等于 ,若否,则设 、 ( 表示 的栈顶的下一点),用线段连接 ,栈顶元素出栈,回到(3)。

    (7)当栈为空时,第一段曲线计算结束。处理第二段曲线,重复(1)~(7)。

    改进算法的程序流程图如下图所示。

                                                                                                             

     

    图 改进Douglas-Peucker流程图

    本文提出的改进算法虽然在编程上面比较复杂,但是能够减少中间重复循环的次数。有了上面的流程图之后,那么代码就相对简单了。

     1 void DouglasPeucker(LineVertex *V,int &i,int &j,double e)
     2 {
     3     double dist = 9999;
     4     int f = 0;            //最大距离的点的序号
     5     stack<int> tempVertex;            //STL实现的栈
     6     tempVertex.push(j);
     7 
     8     do 
     9     {
    10         //循环i和j之间距离直线ij最大的点
    11         FindSplit(*V,i,j,&f,&dist);
    12 
    13         if (dist > e)      //大于阈值
    14         {
    15             (*V)[f].flag = true;
    16 
    17             j = f;    //更新B值
    18 
    19             tempVertex.push(f);                    //记录最大距离点,放入栈中存储
    20             continue;
    21         }
    22 
    23         else            
    24         {
    25             if (!tempVertex.empty() && j != tempVertex.top())    //判断后一点是否和当前栈顶相等
    26             {
    27                 i = f;
    28                 j = tempVertex.top();
    29                 continue;
    30             }
    31             else
    32             {
    33                 if (j != V->size())        //判断最后一个点是否和当前线段的B点重合
    34                 {
    35                     i = j;
    36                     if (!tempVertex.empty())
    37                     {
    38                         deque<int> cont = tempVertex._Get_container();
    39                         if (cont.size() > 1) //栈中至少还有两个点
    40                         {
    41                             j = cont[cont.size()-2];
    42                         }
    43                         else if (cont.size() == 1)    //栈中只有一个点
    44                         {
    45                             j = cont[cont.size()-1];
    46                         }
    47                         tempVertex.pop();
    48                         continue;
    49                     }
    50                 }
    51             }
    52         }
    53     } while (!tempVertex.empty());
    54 
    55 }

    代码不是完整的,其中有调用到了另外一个函数,就是找曲线中离曲线两端点的直线的距离的最大值点,这个过程很简单,就不讲了,还有自己定义的一些数据结构,本文只是讲解这一种算法的思想,其中算法描述部分由公式,原文是在word中编辑的,如果看不懂就直接看流程图还清晰点。

    文章来源:http://blog.csdn.net/zhouxuguang236/article/details/12313503

  • 相关阅读:
    交互设计必懂--开发有价值的用户体验
    优秀APP启动页的设计思维
    增加用户体验的细节--三个按钮的交互设计思维
    零基础掌握交互设计的重点笔记
    在失败的滴滴出行LOGO上谈APP设计
    是成为设计的主人?还是沦为设计的工具?
    大图标+不规则几何创造不同风格
    如何定义视觉设计规范?
    10条SKETCH的秘诀,为你提高工作的效率
    MVC过滤器详解
  • 原文地址:https://www.cnblogs.com/qiernonstop/p/4005734.html
Copyright © 2020-2023  润新知