Sutherland-Hodgeman多邊形裁剪算法思想:
每次用窗口的一條邊界(包括延長線)對要裁剪的多邊形進行裁剪,裁剪時,順序地測試多邊形各頂點,保留邊界內側的頂點,刪除外側的頂點,同時,適時地插入新的頂點:即交點和窗口頂點,從而得到一個新的多邊形頂點序列。
然後以此新的頂點序列作爲輸入,相對第二條窗邊界線進行裁剪,又得到一個更新的多邊形頂點序列。
依次下去,相對於第三條、第四條邊界線進行裁剪,最後輸出的多邊形頂點序列即爲所求的裁剪好了的多邊形。如下圖所示。
新的多邊形頂點序列產生規則:
在用窗口一條邊界及其延長線裁剪一個多邊形時,該邊界線把平面分成兩個部分:一部分稱爲邊界內側;另一部分稱爲邊界外側。
如下圖所示,依序考慮多邊形的各條邊。假設當前處理的多邊形的邊爲SP(箭頭表示順序關係,S爲前一點,P爲當前點),邊SP與裁剪線的位置關係只有下面四種情況:
- S在外側,P在內側。則交點 I、當前點P保存到新多邊形中。
- S、P均在內側,則當前點P保存到新多邊形中。
- S在內側,P在外側。則交點 I 保存到新多邊形中。
- S、P均在外側。則沒有點被保存到新多邊形中。
核心代碼:
def poly_clip(self, rect):
print(len(self.vertex_pts))
vsold = copy.deepcopy(self.vertex_pts)
vsnew = []
'''
對左邊界進行操作
'''
flag = 1 #前一個點S的內外標誌,用變量flag來標識:0表示在內側,1表示在外側。
vp1 = vsold.pop(0)
if (vp1.x() >= rect.left()):
flag = 0
vsold.append(vp1)
for i in range(len(vsold)):
# 對於左邊界,判斷第i個頂點是否在邊界內
vp2 = vsold.pop(0)
#當前第i個頂點在邊界內側
if (vp2.x() >= rect.left()):
if flag!=0: #前一個點在外側
flag = 0 #將標誌置0,作爲下一次循環的前一點標誌
vsnew.append(QPoint(rect.left(),vp2.y() + (vp1.y() - vp2.y()) * (rect.left() - vp2.x()) / (vp1.x() - vp2.x())))
vsnew.append(vp2)
#當前第i個頂點在邊界外側
else:
if flag == 0: #前一個點在內側
flag = 1 #將標誌置0,作爲下一次循環的前一點標誌
vsnew.append(QPoint(rect.left(),vp2.y() + (vp1.y() - vp2.y()) * (rect.left() - vp2.x()) / (vp1.x() - vp2.x())))
vp1=vp2 #將當前點作爲下次循環的前一點
'''
對上邊界進行操作
'''
vsold = copy.deepcopy(vsnew)
vsnew = copy.deepcopy([])
flag = 1
vp1 = vsold.pop(0)
if (vp1.y() >= rect.top()):
flag = 0
vsold.append(vp1)
for i in range(len(vsold)):
vp2 = vsold.pop(0)
if (vp2.y() >= rect.top()):
if flag != 0:
flag = 0
vsnew.append(QPoint(vp2.x() + (vp1.x() - vp2.x()) * (rect.top() - vp2.y()) / (vp1.y() - vp2.y()), rect.top()))
vsnew.append(vp2)
else:
if flag == 0:
flag = 1
vsnew.append(QPoint(vp2.x() + (vp1.x() - vp2.x()) * (rect.top() - vp2.y()) / (vp1.y() - vp2.y()), rect.top()))
vp1 = vp2
'''
對右邊界進行操作
'''
vsold = copy.deepcopy(vsnew)
vsnew = copy.deepcopy([])
flag = 1
vp1 = vsold.pop(0)
if (vp1.x() <= rect.right()):
flag = 0
vsold.append(vp1)
for i in range(len(vsold)):
vp2 = vsold.pop(0)
if (vp2.x() <= rect.right()):
if flag != 0:
flag = 0
vsnew.append(QPoint(rect.right(), vp2.y() + (vp1.y() - vp2.y()) * (rect.right() - vp2.x()) / (
vp1.x() - vp2.x())))
vsnew.append(vp2)
else:
if flag == 0:
flag = 1
vsnew.append(QPoint(rect.right(), vp2.y() + (vp1.y() - vp2.y()) * (rect.right() - vp2.x()) / (
vp1.x() - vp2.x())))
vp1 = vp2
'''
對下邊界進行操作
'''
vsold = copy.deepcopy(vsnew)
vsnew = copy.deepcopy([])
flag = 1
vp1 = vsold.pop(0)
if (vp1.y() <= rect.bottom()):
flag = 0
vsold.append(vp1)
for i in range(len(vsold)):
vp2 = vsold.pop(0)
if (vp2.y() <= rect.bottom()):
if flag != 0:
flag = 0
vsnew.append(QPoint(vp2.x() + (vp1.x() - vp2.x()) * (rect.bottom() - vp2.y()) / (vp1.y() - vp2.y()),
rect.bottom()))
vsnew.append(vp2)
else:
if flag == 0:
flag = 1
vsnew.append(QPoint(vp2.x() + (vp1.x() - vp2.x()) * (rect.bottom() - vp2.y()) / (vp1.y() - vp2.y()),
rect.bottom()))
vp1 = vp2
polyclip = QPolygon(vsnew)
return polyclip
算法特點:
Sutherland-Hodgeman多邊形裁剪算法具有一般性,被裁剪多邊形可以是任意凸多邊形或凹多邊形,裁剪窗口不侷限於矩形,可以是任意凸多邊形(這裏代碼中我只用矩形舉例,大家可以踊躍嘗試)。
加上UI界面實現效果:
PS: 如需參考完整代碼,請移步: https://download.csdn.net/download/qq_42185999/11958148 進行下載