how can I achieve the implementation effect like revit by use QPainterPath in Qt?

80 views Asked by At

I want to implement the effect that one path through another, the two path break off and they still two independence path.

When I use the method according to my code. ( I draw two path using QPainterPath object and put them into QGraphicsPathItem like first picture. red one is pRect1 and blue one is pRect2. Then I use simplified() function to union two path, the result is green one).

What should I do to achieve my purpose? should I use the method in QPainterPath or I must write my own algorithm? Which algorithm should I consider?

Could you please give me some suggestions what should I do to achieve the implementation effect like revit ( Like the second picture, one path through another, they still independence path).

Thank you very much.

    QGraphicsView* viewer = new QGraphicsView(this);
    this->setCentralWidget(viewer);
    viewer->show();
    QGraphicsScene* scene = new QGraphicsScene(viewer);
    viewer->setScene(scene);
    QGraphicsPathItem* item1 = new QGraphicsPathItem;
    QGraphicsPathItem* item2 = new QGraphicsPathItem;
    QGraphicsPathItem* item3 = new QGraphicsPathItem;

    scene->setSceneRect(QRect(0,0, viewer->width(), viewer->height()));

    const int kb = 80;
    const int offset = kb/10;
    QRectF br(0, 0, kb*2, offset);

    QPainterPath pRect1;
    pRect1.moveTo(br.left(), br.top());
    pRect1.lineTo(br.right(), br.top());
    pRect1.lineTo(br.right(), br.bottom());
    pRect1.lineTo(br.left(), br.bottom());
    pRect1.lineTo(br.left(), br.top());

    QPainterPath pRect2;
    pRect2.moveTo(br.left() + br.width()/2.0 - offset, br.top() - br.width());
    pRect2.lineTo(br.left() + br.width()/2.0 + offset, br.top() - br.width());
    pRect2.lineTo(br.left() + br.width()/2.0 + offset, br.bottom() + br.width());
    pRect2.lineTo(br.left() + br.width()/2.0 - offset, br.bottom() + br.width());
    pRect2.lineTo(br.left() + br.width()/2.0 - offset, br.top() - br.width());

    QPainterPath shape = pRect1.united(pRect2);
    shape.simplified();

    item1->setPen(QPen(QColor(255,0,0)));
    item1->setPos(0,50);
    item1->setPath(pRect1);

    item2->setPen(QPen(QColor(0,0,255)));
    item2->setPos(0,50);
    item2->setPath(pRect2);


    item3->setPen(QPen(QColor(0,255,0)));
    item3->setPos(250,50);
    item3->setPath(shape);

    scene->addItem(item1);
    scene->addItem(item2);
    scene->addItem(item3);

enter image description here enter image description here

2

There are 2 answers

0
musicamante On BEST ANSWER

This is not possible with standard graphics items, but you can do this by overriding the paint() in a QGraphicsPathItem subclass, and subtract the shape of the colliding items from the clip path.

The following is a simple implementation in PyQt/PySide, but porting in C++ should be trivial. It clips overlapping parts of each colliding path as long as they are of the same item type.

Screenshot of the example code

class CollidingItem(QGraphicsPathItem):
    def __init__(self):
        super().__init__()
        path = QPainterPath()
        path.addRect(QRectF(-200, -25, 400, 50))
        self.setPath(path)

    def paint(self, qp, opt, widget=None):
        shape = self.shape()
        for item in self.collidingItems():
            if isinstance(item, CollidingItem):
                shape -= self.mapFromItem(item, item.path())
        qp.save()
        qp.setClipPath(shape)
        super().paint(qp, opt, widget)
        qp.restore()

app = QApplication(sys.argv)
scene = QGraphicsScene()

item1 = CollidingItem()
item1.setPen(QPen(Qt.red, 2))
item1.setBrush(QColor('aqua'))

item2 = CollidingItem()
item2.setPen(QPen(Qt.blue, 2))
item2.setRotation(45)

scene.addItem(item1)
scene.addItem(item2)

window = QGraphicsView(scene)
window.setRenderHint(QPainter.Antialiasing)
window.show()

app.exec()
0
Nome On

maybe you means this:

change your code lines:

QPainterPath shape = pRect1.united(pRect2);
shape.simplified();

to:

QPainterPath shape = pRect1.subtracted(pRect2);
shape.addPath(pRect2);

or simply:

item2->setBrush(QBrush(QColor(100,100,255)));