Smooth line in QGraphicsScene with Qt

7.3k views Asked by At

I need to draw curves with Qt: The user clicks on QGraphicsScene (via QGraphicsView) and straight lines are drawn between the points clicked on by the user. When the user finishes to draw straight lines (by clicking on the right button), the set of lines becomes a curve.

For that, I need to use the QPainterPath::cubicTo(...) method and add the path to the QGraphicsScene using QGraphicsScene::addPath(...).

The problem is that I don't know how to compute the parameter values that are passed to cubicTo(...).

For example, in the following picture, the user has drawn the two gray lines by clicking points A B and C. When she clicks the right button, I want to draw the red line using cubicTo(...):

The intended lines and curves

My current code only draws gray lines because I have set c1, c2, d1 and d2 values to point positions clicked on by the user :

void Visuel::mousePressEvent(QMouseEvent *event)
{
    int x = ((float)event->pos().x()/(float)this->rect().width())*(float)scene()->sceneRect().width();
    int y = ((float)event->pos().y()/(float)this->rect().height())*(float)scene()->sceneRect().height();
    qDebug() << x << y;

    if(event->button() == Qt::LeftButton)
    {
        path->cubicTo(x,y,x,y,x,y);
    }
    if(event->button() == Qt::RightButton)
    {
        if(path == NULL)
        {
            path = new QPainterPath();
            path->moveTo(x,y);

        }
        else
        {

            path->cubicTo(x,y,x,y,x,y);
            scene()->addPath(*path,QPen(QColor(79, 106, 25)));
            path = NULL;
        }
    }
}
1

There are 1 answers

0
divanov On

Apparently control points c1, c2, d1, d2 are just coordinates of point B in your picture. In more general case point C lies on AB line and point D lies on BC line.

In Qt code this can be written as follows: Visuel class should have the following properties:

QPoint A, B, C;
unsigned int count;

Which should be initialized in Visuel's constructor.

void Visuel::Visuel()
{
    count = 0;
    // Initialize other stuff as well
}

Then we are going to overload QGraphicsScene::mousePressEvent() to detect user's mouse events:

void Visuel::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    /* Ignore everything else except left button's press */
    if (event->type() != QEvent::GraphicsSceneMousePress ||
        event->button() != Qt::LeftButton) {
        return;
    }
    switch (count) {
    case 0:
        A = event->scenePos();
        break;
    case 1: {
        B = event->scenePos();

        /* Draw AB line */
        QPainterPath path(A);
        path.lineTo(B);
        scene()->addPath(path, Qt::grey);
        }
        break;
    case 2: {
        C = event->scenePos();

        /* Draw BC line */
        QPainterPath path(B);
        path.lineTo(C);
        scene()->addPath(path, Qt::grey);

        /* Draw ABBC cubic Bezier curve */
        QPainterPath path2(A);
        path2.cubicTo(B, B, C);
        scene()->addPath(path2, Qt::red);
        }
        break;
    default:
        break;
    }
    if (count >= 2) {
        count = 0;
    } else {
        count++;
    }
}