GIS面裁減(二)

 

李泉   陳玉進(南京跬步科技有限公司http://www.creable.cn

圖中S1…….S13是主多邊形的節點序列(注意:主多邊形的兩個環是逆時針方向的),C1……C4是裁剪多邊形的節點序列,I1……I4是交點序列,其中I1I3是入點,I2I4是出點。算法開始時從主多邊形的節點序列中開始尋找入點(I1),I1標記爲已讀,沿主多邊形順時針繼續(S4S5),發現一個出點(I2),然後跳躍到裁剪多邊形序列上,發現下一個入點(I3),跳躍到主多邊形(S7),發現一個出現(I4),跳躍到裁剪多邊形,發現起始點(I1)裁剪出一個小多邊形(I1S4S5I2I3S7I4I1)。從頭搜索沒有未讀入點則算法結束。有一個環與裁剪多邊形沒有交點,需要判斷該環是在裁剪框多邊形還是外(判斷環的每個節點是否都在裁切多邊形內部)。如果在裁剪框內部,則再次判斷在剛剛裁剪出來的哪個多邊形(裁剪之後的多邊形會有多個)的內部,這樣這個環的歸屬問題就解決了。

 

該算法可以應用在任意多邊形與任意多邊形的情況。在算法描述上矩形與任意多邊形也就節點數量的區別,其他基本一樣。具體算法實施步驟不在詳述。

一、線段求交問題

由於在我們地理信息系統中的面裁剪應用中,裁剪多邊形爲矩形的情況比較多,這裏討論在這種情況下的優化算法。交點必然出現在矩形邊上,求交時必然已知一個交點的橫座標或縱座標,比用解方程組求交先利用先用向量來判斷是否有交點再求交這種方式來的高(裁剪多邊形不是矩形是則需要先利用向量判斷是否有交點,再解方程組來計算出交點座標)。下面以計算圖1I1爲例說明求交的算法。設裁剪框的最小橫座標爲x,最小縱座標爲ymin,最大縱座標爲ymax,且爲已知,交點的x座標必然等於x,只需求解交點的y值即可,設S1的座標爲(x1,y1),S2的座標爲(x2,y2),那麼有這樣的等式成立 ,可以轉換爲 。很快即可計算出y值。(如果 ,那麼 ,不用代入公式計算,如果 ,說明該主多邊形上的線段與裁剪框的邊平行,直接返回無交點)。需要判斷該交點是否在上述兩個線段上,滿足如下不等式則交點在線段上,

二、算法實現流程

Weiler-Atherton算法相對比較複雜,對數據結構的依賴性很明顯,好的數據結構是算法高效的基礎。

1. 主多邊形不包含環的情況。

設計這麼一個結構PointInfo用於保存節點相關信息,其中pos記錄點座標,flag表示節點類型(0爲正常的節點,1爲入交點,-1爲出交點),pos1爲此交點後面一個主多邊形上節點的序號,pos2爲此交點後面一個裁剪多邊形上節點的序號。

class PointInfo

{

    public IPoint pos;

    public byte flag;//0爲正常的節點,1爲入交點,-1爲出交點

    public int pos1;

    public int pos2;

   

    public PointInfo(float x,float y)

    {

       pos=new Point(x,y);

    }

   

    public PointInfo(IPoint pt)

    {

       pos=pt;

    }

}

     使用兩個能夠管理上述結構的鏈表(list1list2)分別存放主多邊形和裁剪多邊形節點序列,再使用一個鏈表(list3)來存放計算出來的交點。

     將交點按照上述結構的pos1升序排序,之後反向插入到list1中(注意:爲什麼要反向插入?如果從正向插入list1,那麼插入第一個交點之後,list1後面節點的序號就變了,insert函數需要一個插入到那裏的參數,這樣插入的次序就會錯亂。反之,從距離主多邊形節點序列最後的交點首先插入到list1中,則不會影響list1後面節點的序號。)。有的朋友會問爲什麼不降序排序,這樣就不用反向插入list1了。計算交點的代碼使用一個循環,該循環體的變量是主多邊形的節點,所以計算出來的交點序列基本上是按照pos1升序的,升序排序的效率比較高,而反向插入的效率和正向差不多。

     將交點按照上述結構的pos2升序排序,之後反向插入到list2中。

     建立一個鏈表result存放結果多邊形節點序列。

     遍歷list1,發現flag=1的入點時開始算法,添加該點到result,並將flag設置爲0(表示該入點已讀,記錄該點爲起始點S,沿着list1取點,發現flag=-1(出點)時則跳躍到list2上,跳躍的位置在當前點的pos2中標識了,沿着list2取點,若發現起始點則算法結束,發現flag=1(入點)則將該flag設置爲0,並跳躍到list1上,跳躍位置在當前點的pos1中標識了。

2. 主多邊形包含環的情況。

如果主多邊形保護環,則需要使用兩個數組來存放上述鏈表list1list2的指針,數組的成員個數等於主多邊形內部環的個數加上1,這樣可以形成一個橫向可變的鋸齒型二維數組。將每個環和外邊界的座標序列放在在這個二維數組中。交點也採用這樣的鋸齒型二維數組來存放。PointInfo中添加一個成員index,用於標識該點位於哪個環中。還是採用上述的步驟,不過需要進行多次排序插入操作。在遍歷查找過程中,需要藉助index成員的值來在不同的環中跳轉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章