
本文介绍一种基于法向量偏移的数学方法,使连接两圆的 qgraphicslineitem 在圆相对位置变化时保持平行且间距恒定,避免因简单坐标平移导致的线条靠拢或翻转问题。
本文介绍一种基于法向量偏移的数学方法,使连接两圆的 qgraphicslineitem 在圆相对位置变化时保持平行且间距恒定,避免因简单坐标平移导致的线条靠拢或翻转问题。
在 Qt 图形视图框架中,若需用两条平行线(如 ||)连接两个可移动的 QGraphicsEllipseItem(代表圆),直接对线段端点做固定像素偏移(如 ±4)会导致视觉失真:当两圆连线接近 45°(即 y = x 方向)时,线段会相互挤压甚至交叉——这是因为偏移方向未随连线方向动态正交调整。
正确解法是:沿连线的法向量(perpendicular vector)进行等距偏移。具体步骤如下:
- 计算源圆与目标圆之间的向量差 delta = source.pos() - dest.pos();
- 归一化该向量得到单位方向 direction;
- 构造与其垂直的单位法向量 perpendicular = (-dy, dx);
- 根据 foo 标志决定偏移方向(+1 或 −1),再乘以固定偏移量(如 line_offset = 5);
- 将同一法向偏移量同时应用于线段两端,确保线条平移后仍严格平行且间距恒定。
以下是优化后的 adjust() 实现(含边界防护):
def adjust(self, foo: bool):
self.prepareGeometryChange()
delta = QtCore.QPointF(self.source.pos() - self.dest.pos())
length = delta.manhattanLength()
if length == 0.0:
# 防止零向量除零错误,退化为点重合时的退化线段
self.setLine(QtCore.QLineF(self.source.pos(), self.dest.pos()))
return
# 归一化方向向量(使用欧氏长度更精确,但曼哈顿长度亦可接受)
norm = delta.length()
direction = QtCore.QPointF(delta.x() / norm, delta.y() / norm)
perpendicular = QtCore.QPointF(-direction.y(), direction.x()) # 逆时针旋转90°
line_offset = 5.0
sign = -1 if foo else 1
# 关键:沿法向量方向施加偏移,符号控制左右侧
offset = perpendicular * (sign * line_offset)
src_pos = self.source.pos() - offset
dst_pos = self.dest.pos() - offset
self.setLine(QtCore.QLineF(src_pos, dst_pos))
⚠️ 注意事项:
- 使用 delta.length()(欧氏长度)替代 manhattanLength() 可提升方向归一化精度,尤其在斜向场景下;
- 偏移量 line_offset 应根据实际图形尺寸调整,建议设为圆半径的 1–2 倍以保证视觉清晰;
- 若需支持动态缩放(如 QGraphicsView::scale()),应将 line_offset 改为与视图变换解耦的逻辑单位,或在 paint() 中动态计算像素偏移;
- 此方案天然支持任意角度旋转,且两线始终关于中心线对称,完美实现“绕圆旋转”效果——实质是绕两圆构成的轴线做刚性平移。
通过该方法,无论两圆如何相对运动,两条连接线均能稳定维持平行、等距、无翻转,真正实现以圆为锚点的自然联动效果。










