I need to detect precisely the collision between rectangle item and another item that has a bezier curve shape. At the moment collision is detected correctly when I collide rectangle with bottom part of the bezier curve shape. But when I move rectangle inside the bezier curve shape collision is also detected, although that items aren't collided. I want to obtain a precise collision between these two items. I don't understand where I made a mistake.
class RectangleItem(QGraphicsRectItem):
def __init__(self, *args):
super().__init__(*args)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setPen(QPen(Qt.cyan))
class CurveItem(QGraphicsItem):
def __init__(self):
super().__init__()
self.path = self._setupPath()
def paint(self, painter, styles, widget=None):
painter.drawPath(self.path)
def boundingRect(self):
return self.path.boundingRect()
def shape(self):
return self.path
def _setupPath(self):
path = QPainterPath()
p1 = QPointF(0, 100)
p2 = QPointF(400, 100)
c = QPointF(200, 800)
path.moveTo(p1)
path.quadTo(c, p2)
return path
class Scene(QGraphicsScene):
def __init__(self):
super().__init__()
self.curve_item = CurveItem()
self.addItem(self.curve_item)
self.rectangle_item = RectangleItem(0, 0, 50, 50)
self.addItem(self.rectangle_item)
def mouseMoveEvent(self, e):
print(self.collidingItems(self.curve_item))
super().mouseMoveEvent(e)
To observe what is the cause of the problem we can place a QBrush to paint the CurveItem content and we get the following:
def paint(self, painter, styles, widget=None):
painter.setBrush(QBrush(QColor("green")))
painter.drawPath(self.path)
QPainterPath
joins the final and initial points if the figure is not closed, so it generates a figure with content, and that causes when you move the rectangle over the line it signals that it is intersecting.
Go back through the same path to the starting point, thus joining the new final line with the initial one without generating the content.
In the following code is the solution:
class CurveItem(QGraphicsItem):
def __init__(self):
super().__init__()
self.path = self._setupPath()
def paint(self, painter, styles, widget):
painter.drawPath(self.path)
def boundingRect(self):
return self.path.boundingRect()
def shape(self):
return self.path
def _setupPath(self):
path = QPainterPath()
p1 = QPointF(0, 100)
p2 = QPointF(400, 100)
c = QPointF(200, 800)
path.moveTo(p1)
path.quadTo(c, p2)
# back
path.quadTo(c, p1)
return path