I have a graphics scene with QGraphicsEllipseitem circles that are movable. I am trying to prevent the circles from overlapping by having the one that am dragging to move around the other circles that it collides into. So far it works for 1 collision item to set the minumum distance.
I am trying to extend the code for len(colliding)==1 to work for 2 collision items so what I tried is to apply the code to each of the colliding items. I apply the one with the more overlap first and then the second one.
When the collision items are the same size it is partly working, because it moves around without overlap, but it "glitches" around a lot so I know its not perfect. But when they are a different size then it doesnt work at all and still overlap. I don't know how to fix it.
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 len(colliding)==1:
item = colliding[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())
elif len(colliding)==2:
item0 = colliding[0]
item1 = colliding[1]
line0 = QLineF(item0.pos(), self.pos())
line1 = QLineF(item1.pos(), self.pos())
if line0.length() < line1.length():
mindist = (self.rect().width() + item0.rect().width()) / 2
if line0.length() < mindist:
line0.setLength(mindist)
self.setPos(line0.p2())
second = item1
else:
mindist = (self.rect().width() + item1.rect().width()) / 2
if line1.length() < mindist:
line1.setLength(mindist)
self.setPos(line1.p2())
second = item0
line = QLineF(second.pos(), self.pos())
min_distance = (self.rect().width() + second.rect().width()) / 2
if line.length() < min_distance:
line.setLength(min_distance)
self.setPos(line.p2())
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.circle3 =Circleitem(80, brush=QColor(0,255,0))
self.gscene.addItem(self.circle1)
self.gscene.addItem(self.circle2)
self.gscene.addItem(self.circle3)
self.circle1.setPos(500, 500)
self.circle2.setPos(300, 300)
self.circle3.setPos(300, 400)
self.show()
app = QApplication([])
win = MainWindow()
app.exec()