直線切割凹多邊形


一,算法原理

以上圖為例,直線(start,end)切割凹多邊形ABCDEFGHIJKLMNOP。

切割線divLine=(start,end)。

多邊形頂點序列vertexList=(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P)。

邊序列edgeList=(AB,BC,CD,DE,EF,FG,GH,HI,IJ,JK,KL,LM,MN,NO,OP,PA)。

下面開始計算:

1,求切割點。

遍歷edgeList,拿其中各edge與divLine求交,得切割點序列divPointList=(1,2,3,4,5,6,7,8)。

注:線段與直線求交,見:http://www.cnblogs.com/wantnon/p/6384543.html

插入切割點后頂點序列vertexList_afterDiv=(A,1,B,C,2,D,E,3,F,G,4,H,I,5,J,K,6,L,M,7,N,O,8,P)。

插入切割點后的邊序列edgeList_afterDiv=(A1,1B,BC,C2,2D,DE,E3,3F,FG,G4,4H,HI,I5,5J,JK,K6,6L,LM,M7,7N,NO,O8,8P,PA)。

2,求各邊在切割線哪一側。

所謂“點在切割線左側”是指:當站在start面朝end時,點在左手邊。

可以使用點到直線的帶符號距離來判斷點在直線的哪一側,參考:http://www.cnblogs.com/wantnon/p/6384543.html

求得結果為:B,C,F,G,J,K,N,O在切割線右側,A,D,E,H,I,L,M,P在切割線左側。

則切割后的邊集edgeList_afterDiv被划分為兩個集合:

右側邊集合:rightSideEdgeSet={1B,BC,C2,3F,FG,G4,5J,JK,K6,7N,NO,O8}。

左側邊集合:leftSideEdgeSet={A1,2D,DE,E3,4H,HI,I5,6L,LM,M7,8P,PA}。

3,求封口邊。

將divLine反向延長得到點veryFarStart,我們假定點veryFarStart足夠遠,以至於divPointList中的所有點都在射線[veryFarStart,end)上。

然后我們根據到veryFarStart的距離對divPointList中的點進行排序,得到divPointList_sorted=(1,2,3,8,7,4,5,6)。

然后把divPointList_sorted中的點相鄰兩個結對兒,得到12,38,74,56。可以發現規律:

線段12,線段38,線段74,線段56,正好都是左側子多邊形的封口。

而將上面每個線段都反向,得到:線段21,線段83,線段47,線段65,正好都是右側子多邊形的封口。

所以有:

leftSideCapSet={12,38,74,56},

rightSideCapList={21,83,47,65}。

4,重新組裝。

右側邊和封口形成的集合為rightSideEdgeAndCapSet=rightSideEdgeSet與rightSideCapSet的並集={1B,BC,C2,3F,FG,G4,5J,JK,K6,7N,NO,O8,21,83,47,65},

左側邊和封口形成的集合為leftSideEdgeAndCapSet=leftSideEdgeSet與leftSideCapSet的並集={A1,2D,DE,E3,4H,HI,I5,6L,LM,M7,8P,PA,12,38,74,56}。

對rightSideEdgeAndCapSet中的邊進行組裝,可得多邊形:1BC2,3FG47NO8,5JK6,

對leftSideEdgeAndCapSet中的邊形行組裝,可得多邊形:A12DE38P,4HI56LM7

(注意,組裝過程並不需要比較坐標(比較坐標的方法不但效率低,而且特殊情況還有可能產生錯誤),只需對線段端點字母進行匹配即可)。

所以凹多邊形ABCDEFGHIJKLMNOP被直線(start,end)切割成五個子多邊形:1BC2,3FG47NO8,5JK6,A12DE38P,4HI56LM7。

 

計算完畢。

 

二,實現

在unity里進行了試驗,效果如下:

開源地址:http://git.oschina.net/wantnon2/polygonDiv


免責聲明!

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



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