道格拉斯—普克(Douglas一Peukcer)節點抽稀算法


道格拉斯-普克抽稀算法,是將曲線近似表示為一系列點,並減少點的數量的一種算法。

Douglas一Peukcer算法由D.Douglas和T.Peueker於1973年提出,簡稱D一P算法,是眼下公認的線狀要素化簡經典算法。現有的線化簡算法中,有相當一部分都是在該算法基礎上進行改進產生的。它的長處是具有平移和旋轉不變性,給定曲線與閡值后,抽樣結果一定。

算法的基本思路是:對每一條曲線的首末點虛連一條直線,求所有點與直線的距離,並找出最大距離值dmax ,用dmax與限差D相比:若dmax < ,這條曲線上的中間點所有舍去;若dmax ≥,保留dmax 相應的坐標點,並以該點為界,把曲線分為兩部分,對這兩部分反復使用該方法。

算法的具體過程如下:

(1) 在曲線首尾兩點間虛連一條直線,求出其余各點到該直線的距離,如圖3(1)。

(2) 選其最大者與閾值相比較,若大於閾值,則離該直線距離最大的點保留,否則將直線兩端點間各點所有舍去,如圖3(2),第4點保留。

(3) 根據所保留的點,將已知曲線分成兩部分處理,反復第1、2步操作,迭代操作,即仍選距離最大者與閾值比較,依次取舍,直到無點可舍去,最后得到滿足給定精度限差的曲線點坐標,如圖3(3)、(4)依次保留第6點、第7點,舍去其它點,即完成線的化簡。

 

 

 

利用遞歸的方法遍歷所有的點進行道格拉斯抽稀。

驗證數據如圖。

其中,黑色的線為原始線狀數據,其他顏色為進行抽稀元算時所做輔助線。

 

 ArrayList myar = new ArrayList();//存入原始數據  
 ArrayList newar = new ArrayList(); //存入抽稀后的數據  
  
public class canshu//記錄直線參數的類  
    {  
     public   double k;  
     public   double b;  
    }  
  
public class zuobiao//坐標數據類  
    {  
        public double x;  
        public double y;  
    }  
   public canshu xielv(zuobiao shou, zuobiao wei)//求斜率  
        {  
            double k, b;  
            canshu newcs = new canshu();  
           k = (wei.y - shou.y) / (wei.x - shou.x);  
           b = shou.y - k * shou.x;  
           newcs.k = k;  
           newcs.b = b;  
           return newcs;  
        }  
  
        public double distance(zuobiao dot,canshu cs)//求點到直線距離  
        {  
            double dis =(Math.Abs (cs.k * dot.x - dot.y + cs.b)) / Math.Sqrt(cs.k * cs.k + 1);  
            return dis;  
        } 

 

道格拉斯算法如下:

public void Douglas(int number1, int number2)  
       {  
           int max=0;//定義擁有最大距離值的點的編號  
           canshu myc = new canshu();  
          myc= xielv((zuobiao)myar[number1], (zuobiao)myar[number2-1]);  
           double maxx = distance((zuobiao)myar[number1+1], myc);//假設第二個點為最大距離點  
           double yuzhi = Convert.ToInt32(textBox1.Text);//設閾值  
               for (int i = number1 + 1; i < number2 - 1; i++)//從第二個點遍歷到最后一個點前方的點  
               {  
                   if (distance((zuobiao)myar[i], myc) > yuzhi && distance((zuobiao)myar[i], myc) >= maxx)//找出擁有最大距離的點  
                   {  
                       max = i;  
                       maxx = distance((zuobiao)myar[i], myc);  
                   }  
               }  
           if(max==0)//若不存在最大距離點,則只將首尾點存入arraylist,結束這一次的道格拉斯抽稀  
           {  
               newar.Add((zuobiao)myar[number2-1]);  
               return;  
           }  
           else if (number1 + 1 == max&&number2-2!=max)//如果第二個點是最大距離點,則以下一個點和尾點作為參數進行道格拉斯抽稀釋  
           {  
               Douglas(max+1, number2);      
           }  
           else if (number2 - 2 == max&&number1+1!=max)//<span style="font-family: Arial;">如果倒數第二個點是最大距離點,則以首點和倒數第三點作為參數進行道格拉斯抽稀  
lt;/span>            {  
               Douglas(0, max+1);                
           }  
           else if (number1 + 1 == max && number2 - 2 == max)//如果首點尾點夾住最大距離點,則將最大距離點和尾點存入arraylist  
           {  
               newar.Add((zuobiao)myar[max]);  
               newar.Add((zuobiao)myar[max+1]);  
               return;  
           }  
           else  
           {  
               Douglas(number1, max+1);  
               Douglas(max, number2);  
           }  
            
       }  

不同閾值的運行情況如圖:

 

 

 

 轉載:https://blog.csdn.net/u011609113/article/details/39234851

Demo

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM