Sutherland-Hodgeman 逐次裁剪法(多邊形裁剪)

Sutherland-Hodgeman多邊形裁剪算法思想:

  每次用窗口的一條邊界(包括延長線)對要裁剪的多邊形進行裁剪,裁剪時,順序地測試多邊形各頂點,保留邊界內側的頂點,刪除外側的頂點,同時,適時地插入新的頂點:即交點和窗口頂點,從而得到一個新的多邊形頂點序列。

  然後以此新的頂點序列作爲輸入,相對第二條窗邊界線進行裁剪,又得到一個更新的多邊形頂點序列。

  依次下去,相對於第三條、第四條邊界線進行裁剪,最後輸出的多邊形頂點序列即爲所求的裁剪好了的多邊形。如下圖所示。

 

新的多邊形頂點序列產生規則:

  在用窗口一條邊界及其延長線裁剪一個多邊形時,該邊界線把平面分成兩個部分:一部分稱爲邊界內側;另一部分稱爲邊界外側。

  如下圖所示,依序考慮多邊形的各條邊。假設當前處理的多邊形的邊爲SP(箭頭表示順序關係,S爲前一點,P爲當前點),邊SP與裁剪線的位置關係只有下面四種情況:

  1. S在外側,P在內側。則交點 I、當前點P保存到新多邊形中。                                                                    
  2. S、P均在內側,則當前點P保存到新多邊形中。                                                                                      
  3. S在內側,P在外側。則交點 I 保存到新多邊形中。                                                                                                    
  4. 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  進行下載

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