道格拉斯—普克(Douglas一Peukcer)演算法 分類: 地圖||地理資料 2012-05-10 21:55 1431人閱讀 評論(0) 收藏 舉報 演算法
Douglas一Peukcer演算法由D.Douglas和T.Peueker於1973年提出,簡稱D一P演算法,是目前公認的線狀要素化簡經典演算法。現有的線化簡演算法中,有相當一部分都是在該演算法基礎上進行改進產生的。它的優點是具有平移和旋轉不變性,給定曲線與閡值後,抽樣結果一定。本章線化簡重點講解該演算法。
演算法的基本思路是:對每一條曲線的首末點虛連一條直線,求所有點與直線的距離,並找出最大距離值dmax ,用dmax與限差D相比:若dmax < D ,這條曲線上的中間點全部捨去;若dmax ≥D ,保留dmax 對應的座標點,並以該點為界,把曲線分為兩部分,對這兩部分重複使用該方法。
演算法的詳細步驟如下:
(1) 在曲線首尾兩點間虛連一條直線,求出其餘各點到該直線的距離,如圖3(1)。
(2) 選其最大者與閾值相比較,若大於閾值,則離該直線距離最大的點保留,否則將直線兩端點間各點全部捨去,如圖3(2),第4點保留。
(3) 依據所保留的點,將已知曲線分成兩部分處理,重複第1、2步操作,迭代操作,即仍選距離最大者與閾值比較,依次取捨,直到無點可捨去,最後得到滿足給定精度限差的曲線點座標,如圖3(3)、(4)依次保留第6點、第7點,捨去其他點,即完成線的化簡。
GIS向量資料化簡:一種改進的道格拉斯-普克演算法以及C++實現 分類: GIS底層開發 2013-10-05 16:46 124人閱讀 評論(0) 收藏 舉報
既然今天有時間,就多寫幾篇博文算了,也為了明天出去玩好好放鬆一下。
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流程圖
本文提出的改進演算法雖然在編程上面比較複雜,但是能夠減少中間重複迴圈的次數。有了上面的流程圖之後,那麼代碼就相對簡單了。 [cpp] view plain copy void DouglasPeucker(LineVertex *V,int &i,int &j,double e) { double dist = 9999; int f = 0; //最大距離的點的序號 stack<int> tempVertex; //STL實現的棧 tempVertex.push(j); do { //迴圈i和j之間距離直線ij最大的點 FindSplit(*V,i,j,&f,&dist); if (dist > e) //大於閾值