zoukankan      html  css  js  c++  java
  • 计算点、线、面等元素之间的交点、交线、封闭区域面积和闭合集(完)

     

         当折线的端点过于密集,以至于显示时堆积在一起时,有必要简化折线,以提高后续凸包或相交运算的处理效率与显示清晰度。关键问题是如何简化复杂折线,能够保持其特征,不至于失真。

         第一步通过设置顶点之间的距离阈值来减少冗余顶点。

                          
         第二步,采用Douglas-Peucker (DP)算法简化折线,其在计算机图形学与地理信息系统领域被广泛应用。

    其思想是顶点到某条边的距离过于接近的话,将被舍弃,保留距离大于阈值的顶点。初始化时,首先连接第一个和最后一个顶点构建第一条边,找到剩余顶点中距离这条线段最远的顶点,然后分别连接第一和最后一个顶点到此最远的顶点,构成两条线段,继续寻找剩余顶点中分别到这两条线段距离最远的顶点,依此类推,直到顶点到边的距离小于设置的阈值停止处理,那么找到的这些顶点构成了简化折线。


    //
    折线的简化程序,包含上述两步骤

    //    输入: 阈值 tol,折线的顶点数组 V[],顶点的个数 n;

    //    输出:   经过简化后的顶点数组 sV[];

    //    返回:   简化后的顶点数组中的顶点数量 m;

    int CDEMAlgorithm::poly_simplify( double tol, Point* V, int n, Point* sV )

    {

        int    i, k, m, pv;            //准备用做计数器

        double tol2 = tol * tol;       //阈值的平方

        Point* vt = new Point[n];      // 输入的顶点数组

        int*   mk = new int[n];       //给标记数组初始化

        for(i=0;i<n;i++)

        {

            mk[i] = 0;                   // 初始化

        }

        //第一步:通过顶点之间的距离判断,是否保留某些顶点

        vt[0] = V[0];      

    for (i=k=1, pv=0; i<n; i++) {                 //对输入的每个顶点循环处理

            if (d2(V[i], V[pv]) < tol2)          //顶点之间的距离小于阈值,直接跳到下个顶点进行处理

                continue;

            vt[k++] = V[i];                      //顶点之间的距离大于阈值,记录此顶点

            pv = i;                              //记录此顶点的索引号

        }

        if (pv < n-1)

            vt[k++] = V[n-1];      // 将最后一个顶点记录下来

        //第二步:采用 Douglas-Peucker算法进行简化

        mk[0] = mk[k-1] = 1;       // 给第一个和最后一个顶点标记为1

        simplifyDP( tol, vt, 0, k-1, mk );

        // copy marked vertices to the output simplified polyline

        for (i=m=0; i<k; i++) {

            if (mk[i])                           //如果标记为1的话

                sV[m++] = vt[i];                 //将顶点赋值给最后输出的结果数组

        }

        delete vt;           //删除临时顶点数组

        delete mk;           //删除标记数组

        return m;         // m vertices in simplified polyline

    }

    //    Douglas-Peucker (DP)算法

    //    输入: 阈值tol,顶点数组v[],j,k分别指示顶点数组中的第一和尾部顶点,在第一次运行此程序片段时,表示连接最初和最后的顶点构成线段,在后面的递归调用中,表示连接到最远顶点的子线段;

    //    输出: 简化后的顶点数组 mk[];

    void CDEMAlgorithm::simplifyDP( double tol, Point* v, int j, int k, int* mk )

    {

        if (k <= j+1) // 两顶点挨在一起,没必要简化

            return;

       

        int     maxi = j;          // 准备记录距离线段的最远顶点的索引

        double   maxd2 = 0;         // 准备记录最远距离的平方

        double   tol2 = tol * tol// 设置的阈值的平方

        Segment S = {v[j], v[k]}; // 构建 顶点v[j] 和 v[k]之间的线段

        Vector u = S.P1 - S.P0;   //矢量

        double cu = Dot(u,u);     // 线段长度的平方

        // 采用前面讲解的顶点到线段的距离求法,计算每个顶点到线段S的距离

        Vector w;

        Point   Pb;              

    double b, cw, dv2;     

        for (int i=j+1; i<k; i++)

        {

            w = v[i] - S.P0;

            cw = Dot(w,u);

            if ( cw <= 0 )

                dv2 = d2(v[i], S.P0);

            else if ( cu <= cw )

                dv2 = d2(v[i], S.P1);

            else {

                b = cw / cu;

                Pb = S.P0 + b * u;

                dv2 = d2(v[i], Pb);

            }

            if (dv2 <= maxd2)

                continue;

            // v[i]是符合要求的最远顶点

            maxi = i;

            maxd2 = dv2;

        }

        if (maxd2 > tol2)        // 如果最远顶点到线段S的距离大于阈值

        {

            mk[maxi] = 1;      //记录maxi这个索引, 此顶点将被最后输出

            //递归调用此程序

            simplifyDP( tol, v, j, maxi, mk ); // 第一条子线段

            simplifyDP( tol, v, maxi, k, mk ); // 第二条子线段

        }

        return;

    }

  • 相关阅读:
    redis基础
    Django Meta
    Django Query
    Django FileFieldManage
    Django Managers管理器
    Django 模型
    Pytables h5py
    python 高级部分
    Python和HDF 5大数据应用
    是时候放弃pipeline 模型 ?
  • 原文地址:https://www.cnblogs.com/wuhanhoutao/p/1120760.html
Copyright © 2011-2022 走看看