Home > Mobile >  Make graphics item move around another item instead of passing through
Make graphics item move around another item instead of passing through

Time:11-17

I have a graphics scene with QGraphicsEllipseitem circles that are movable. I am trying to have the one I am dragging move around the other circle instead of allowing them to overlap aka collide. So far I was able to stop the collision but its not moving around smoothly it snaps to a corner. I dont know how to fix it.

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()

CodePudding user response:

It is simpler to keep the logic in Circleitem.mouseMoveEvent and use QLineF to find the distance and new position.

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())
  • Related