利用道格拉斯·普客法(DP法)壓縮矢量多邊形(C++)


1.算法描述

經典的Douglas-Peucker算法(簡稱DP法)描述如下:

(1)在曲線首尾兩點A,B之間連接一條直線AB,該直線為曲線的弦;

(2)得到曲線上離該直線段距離最大的點C,計算其與AB的距離d;

(3)比較該距離與預先給定的閾值threshold的大小,如果小於threshold,則該直線段作為曲線的近似,該段曲線處理完畢。

(4)如果距離大於閾值,則用C將曲線分為兩段AC和BC,並分別對兩段取信進行1~3的處理。

(5)當所有曲線都處理完畢時,依次連接各個分割點形成的折線,即可以作為曲線的近似

 

2.算法分析

①顯然,整個過程是一個迭代過程,第四步時迭代,再次回到第一步。

②由於計算開方耗時,所以直接取d²作為評判值更加方便。

③DP法一般是化簡一條曲線,本次化簡的是多邊形,實質是一條首尾相連的多邊形,意味着曲線首尾兩點的坐標相等。如果兩點坐標相等,則第二步計算距離時會出現分母為0的問題。因此要換一個就近的點。

 

3.算法實現

 ①計算某點到已知兩點的距離。

// 計算一點到一條直線(已知兩點)的距離
double disP2L(CMyPoint* first, CMyPoint* last, CMyPoint* third) //first和last分別為線的兩端,third是第三點
																//CMyPoint是點的類型,可以換成CPoint
{
	double x0 = first->Getx();
	double y0 = first->Gety();
	double x1 = last->Getx();
	double y1 = last->Gety();
	double x = third->Getx();
	double y = third->Gety();
	//diSquare是d²,不開方,耗時更短。
	double disSuqare = ((y0 - y1)*x + (x1 - x0)*y + (x0*y1 - x1*y0))*((y0 - y1)*x + (x1 - x0)*y + (x0*y1 - x1*y0)) / ((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0));
	return disSuqare;
}

 ②壓縮算法

// Douglas–Peucker法,20190220,壓縮,zf
void DP(vector<CMyPoint*> inputLine)        //輸入是包含指針的數組,vector類型
{
	if (inputLine.size() <= 2)              //若少於兩點,直接返回
		return;
	int size = inputLine.size();
	CMyPoint *first = inputLine[0];         //定義首點
	CMyPoint *last = inputLine[size - 1];   //定義尾點
	while (last->Getx() == first->Getx() && last->Gety() == first->Gety()) {//若首尾相同,則換點
		size = size - 1;
		last = inputLine[size - 1];
	}
	int flag = 0;                            //標記距離最大的點的下標
	double disSquare = 0;                    
	for (int i = 1; i<inputLine.size() - 1; i++) {
		double temp = disP2L(first, last, inputLine[i]);
		if (temp>disSquare) {                //記錄最大距離及編號
			disSquare = temp;
			flag = i;
		}
	}
	if (disSquare<4) {                       //判斷值與閾值的關系,閾值自己設定
		out_DP.push_back(first);             //如果小於閾值,則保留首尾點
		out_DP.push_back(last);              //out_DP是一個全局變量,vector<CMyPoint*> out_DP
		                                     //用於存儲留下來的點,是最后的成果
	}
	else {                                   //否則分成兩段
		vector<CMyPoint*> head, rear;
		for (int j = 0; j<inputLine.size(); j++) {
			if (j <= flag) head.push_back(inputLine[j]);
			if (j >= flag) rear.push_back(inputLine[j]);
		}
		DP(head);                            //迭代進行
		DP(rear);
	}
}

4.實驗效果

 分別是前、后

   

在保持圖形和面積基本不變的前提下,多邊形的點變少,壓縮具有較好效果。


免責聲明!

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



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