一,算法原理

以上圖為例,直線(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
