1. 程式人生 > >(四)建築物多邊形化簡系統——“去尾巴”和分割複雜多邊形

(四)建築物多邊形化簡系統——“去尾巴”和分割複雜多邊形

問題說明

實際操作中,發現有的多邊形存在“尾巴”或者很細的部分。“尾巴”細長,明顯不是有效建築物區域,特點就是區域面積小,看起來細長,附著於大面積多邊形外測或者連線兩個多邊形

需要去除尾巴或者分割多邊形,為後面擬合多邊形做準備。

演算法思想

去除“尾巴”(凸出部分)和分割多邊形的演算法思想:

1.求平均距離。

針對環,遍歷每個點,求到下一個點之間的距離,計算該環兩點間的平均距離L,為之後設定閾值做準備。   

具體做法:每個polyline(環)新增計算平均距離的函式calAvgDis,新增平均距離成員變數avgDis,在建構函式中呼叫calAvgDis函式初始化avgDis。

2.設定判斷兩點的距離閾值和下標閾值。

即存在兩個點下標差超過閾值,距離差小於閾值,若兩點與其之間的點構成的環面積小於閾值,則說明“尾巴”存在;若大於閾值,則說明多邊形應該分割。

此處下標閾值設定為10,距離閾值設定為3個avgDis,面積閾值設定為固定值,具體效果和引數的改變要根據實際效果改變。

3.遍歷環上的沒點,找到最符合條件的兩點。

計算每點到其他點的距離,針對每個點來說,遍歷的起點是本點閾值+下標閾值。

當出現距離小於閾值時,記錄下標號,得到(本點下標,距離小於閾值點的下標)的下標對。

每個點可能有不同的下標對,每個環可能有不同的疑似點及其下標對。

如何找到最合理的兩點,遍歷這些下標對:1)首先找下標號差距最大;2)相同的情況下距離最小的;

4.找到兩點後:1)針對“尾巴”(面積小於閾值),消除兩個點之間的點,得到除去尾巴的多邊形。2)針對面積大於閾值的,分割多邊形。

5.迴圈操作,直至某一次操作前後環的點個數一致。

實際操作

1.設定 距離閾值 和 下標差閾值,實際數值根據要求進行設定

int firstNum = circles[i]->pts.size();  //操作前點數
int lastNum = 0;   //操作後點數  初始為0
int t = circles[i]->pointDisThreshold; //下標差閾值
double length = circles[i]->calAvgDis(circles[i]->pts);  //距離閾值

2.針對環的每一個點,求與之距離超出閾值,下標差超過閾值且差值最大的點,形成一個點與另一個點的關係對(J和K),遍歷所有的關係對,找到最合適的一個關係對(因為每次只刪除一個尾巴)

while( count<1 && firstNum!=lastNum )
		{
			firstNum = circles[i]->pts.size();
			int num = circles[i]->pts.size()-1;  //環的點數(去除尾點)
			int finalJ = 0, finalK = 0, FinalDis = 0, finalType = 0;  //最後J,K,型別
			if(num > t) { //環的總點數大於點數差閾值時

				//找到所有環中下標差最大的兩點
				for(int j = 0 ; j < (num - t); j++){ //遍歷環的每個點,
					int tempDis = 0, tempk = 0, temptype = 0;
					for(int k = (j + t) ; k<num && (j+num-k)>=t ; k++) {  //針對每一個點,計算該點與符合要求的點的距離,找到下標差最大的另一個點,
						int dis = (j+num-k)>=(k-j)?(k-j):(j+num-k);   //取小的
						int type = (j+num-k)>=(k-j)?1:2;   // 1代表順序,2代表非順序
						if( (calDis(circles[i]->pts[j],circles[i]->pts[k])<(length*3)) && (tempDis<dis) ){  //尋找下標差最大
							tempDis = dis;
							tempk = k;
							temptype = type;
						}
					}
					if( FinalDis<=tempDis ){
						FinalDis = tempDis;
						finalJ = j;
						finalK = tempk;
						finalType = temptype;
					}
				}	
			}

3.刪除尾巴或者分割多邊形

實驗效果

            

總結

由於本演算法自己原創,實際問題又非常複雜,所以效果並沒有很理想,後期還有優化。實際操作中,部分尾巴去不掉,演算法也耗時,這表明這種方法並不是一個很成熟的演算法。而且由於資料的複雜性,考慮的問題很多。比如有的最理想的點對中,一個在環首附近的位置,另一個在環尾附近位置,需要考慮不同的取捨辦法,等等。

該演算法以後需要進一步考慮和優化。