使图形项目围绕另一个项目移动而不是穿过

Make graphics item move around another item instead of passing through

我有一个带有可移动 QGraphicsEllipseitem 圆圈的图形场景。我试图让我拖动的那个绕着另一个圆圈移动,而不是让它们重叠也就是碰撞。到目前为止,我已经能够阻止碰撞,但它并没有平稳地移动,而是卡在了一个角落里。我不知道如何解决它。

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import math


class Circleitem(QGraphicsEllipseItem):

    def __init__(self, size, brush):
        super().__init__()
        radius = size / -2
        self.setRect(radius, radius, size, size)
        self.setBrush(brush)
        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemIsSelectable)

    def paint(self, painter, option, a):
        option.state = QStyle.State_None
        return super(Circleitem, self).paint(painter,option)
    
    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)
        self.scene().views()[0].parent().movearound()



class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.gscene = QGraphicsScene(0, 0, 1000, 1000)
        gview = QGraphicsView(self.gscene)
        self.setCentralWidget(gview)
        self.circle1 = Circleitem (123, brush=QColor(255,255,0))
        self.circle2 =Circleitem(80, brush=QColor(0,255,0))
        self.gscene.addItem(self.circle1)
        self.gscene.addItem(self.circle2)
        self.circle1.setPos(500, 500)
        self.circle2.setPos(300, 300)
        self.show()

    def movearound(self):
        if self.gscene.selectedItems()[0] == self.circle1:
            moveditem = self.circle1
            stillitem = self.circle2
        else:
            moveditem = self.circle2
            stillitem = self.circle1
        
        if len(self.gscene.collidingItems(moveditem)) != 0:
            xdist = moveditem.x() - stillitem.x()
            ydist = moveditem.y() - stillitem.y()
            totaldist = moveditem.rect().width()/2 + stillitem.rect().width()/2
            totaldist *= math.sqrt(1 + pow(math.pi, 2)/10)/2
            
            if ( abs(xdist) < totaldist or abs(ydist) < totaldist ):
                if xdist > 0:
                    x = stillitem.x() + totaldist
                else:
                    x = stillitem.x() - totaldist
                if ydist > 0:
                    y = stillitem.y() + totaldist
                else:
                    y = stillitem.y() - totaldist

                moveditem.setPos(x, y)
        


app = QApplication([])
win = MainWindow()
app.exec()

保持Circleitem.mouseMoveEvent中的逻辑更简单,使用QLineF求距离和新位置

class Circleitem(QGraphicsEllipseItem):

    def __init__(self, size, brush):
        super().__init__()
        radius = size / -2
        self.setRect(radius, radius, size, size)
        self.setBrush(brush)
        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemIsSelectable)

    def paint(self, painter, option, a):
        option.state = QStyle.State_None
        return super(Circleitem, self).paint(painter,option)

    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)
        colliding = self.collidingItems()
        if colliding:
            item = colliding[0]                  # Add offset if points are equal so length > 0
            line = QLineF(item.pos(), self.pos() + QPoint(self.pos() == item.pos(), 0))
            min_distance = (self.rect().width() + item.rect().width()) / 2
            if line.length() < min_distance:
                line.setLength(min_distance)
                self.setPos(line.p2())