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