使用贝塞尔曲线形状检测矩形和项目之间的碰撞

Detecting collision between rectangle and item with bezier curve shape

我需要精确检测矩形项目与另一个具有贝塞尔曲线形状的项目之间的碰撞。目前,当我将矩形与贝塞尔曲线形状的底部碰撞时,可以正确检测到碰撞。但是当我在贝塞尔曲线内移动矩形时,也会检测到形状碰撞,尽管这些项目没有发生碰撞。我想获得这两个项目之间的精确碰撞。我不明白我哪里弄错了。

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)

为了观察问题的原因,我们可以放置一个 QBrush 来绘制 CurveItem 内容,我们得到以下结果:

def paint(self, painter, styles, widget=None):
    painter.setBrush(QBrush(QColor("green")))
    painter.drawPath(self.path)

为什么会这样?

如果图形未闭合,

QPainterPath 会连接最终点和初始点,因此它会生成一个具有 content 的图形,这会导致您将矩形移动到上方它表示相交的线。

解决方法是什么?

通过相同的路径返回到起点,从而将新的最后一行与第一行连接起来,而不生成 内容

解决方法如下代码:

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