PySide2+PyQtGraph实现史密斯图时ItemClipsChildrenToShape裁剪异常问题
问题原因
ItemClipsChildrenToShape标志的裁剪边界基于父项的shape()返回值,QGraphicsEllipseItem默认的shape()会包含自身描边的宽度范围,比外圆的实际填充边界大了半个画笔宽度,子项的描边刚好可以从这个溢出的区域漏出。- Qt抗锯齿渲染时,描边边缘的半透明像素不会被严格裁剪,会有视觉上的溢出效果。
- 子项自身的描边宽度没有被纳入裁剪计算,子项的路径边界即使刚好对齐父项边界,描边的一半宽度也会超出路径范围,导致溢出。
解决方案
推荐两种可直接落地的方案,任选即可:
方案1:调整父项裁剪逻辑+分离外圆描边
修改父项的裁剪边界为无描边的纯圆形区域,外圆的描边单独绘制在最上层,避免裁剪范围偏移,性能更好适合动态更新内部路径的场景:
rline = [0.2, 0.5, 1.0, 2.0, 5.0] xline = [0.2, 0.5, 1, 2, 5] # 1. 专门用于裁剪的父圆,不显示自身描边 clip_circle = QGraphicsEllipseItem(-1, -1, 2, 2) clip_circle.setPen(mkPen(None)) # 隐藏父圆的描边,避免shape包含描边宽度 clip_circle.setFlag(clip_circle.ItemClipsChildrenToShape) # 2. 绘制内部圆弧 pathItem = QGraphicsPathItem() path = QPainterPath() path.moveTo(1, 0) for r in rline: raggio = 1./(1+r) path.addEllipse(1, -raggio, -raggio*2, raggio*2) for x in xline: path.arcTo(1-x, 0, x*2, x*2, 90, 180) path.moveTo(1, 0) path.arcTo(1-x, 0, x*2, -x*2, 90, 180) pathItem.setPath(path) pathItem.setPen(mkPen('b', width = 0.5)) pathItem.setParentItem(clip_circle) # 3. 单独绘制最上层的外圆描边,不参与裁剪 border_circle = QGraphicsEllipseItem(-1, -1, 2, 2) border_circle.setPen(mkPen('b', width=0.5))
方案2:路径布尔运算直接裁剪内部路径
不用依赖Qt的Item裁剪机制,直接将内部路径和外圆路径求交集,生成的路径本身就不会超出外圆范围,裁剪效果最精确,适合静态史密斯图的场景:
from PySide2.QtGui import QPainterPath rline = [0.2, 0.5, 1.0, 2.0, 5.0] xline = [0.2, 0.5, 1, 2, 5] # 外圆路径 circle_path = QPainterPath() circle_path.addEllipse(-1, -1, 2, 2) # 生成内部路径 inner_path = QPainterPath() inner_path.moveTo(1, 0) for r in rline: raggio = 1./(1+r) inner_path.addEllipse(1, -raggio, -raggio*2, raggio*2) for x in xline: inner_path.arcTo(1-x, 0, x*2, x*2, 90, 180) inner_path.moveTo(1, 0) inner_path.arcTo(1-x, 0, x*2, -x*2, 90, 180) # 求路径交集,直接裁剪掉外圆外的部分 clipped_path = circle_path.intersected(inner_path) pathItem = QGraphicsPathItem(clipped_path) pathItem.setPen(mkPen('b', width = 0.5)) # 绘制外圆 circle1 = QGraphicsEllipseItem(-1, -1, 2, 2) circle1.setPen(mkPen('b', width=0.5))
内容的提问来源于stack exchange,提问作者Andy Pender
相关产品推荐
相关产品推荐

