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  进行下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值