0

I have a problem with QPainterPath because when I do this:

QPainterPath path(start);
path.quadTo(control, end);

QPainter painter;
painter.setBrush(Qt::black);
painter.drawPath(path);

it draws the area beneath the curve black as well. Using QPainterPath::closeSubpath() nor QPainterPath::moveTo(start) helps. The only thing that does help is drawing the curve back to beginning which is silly and with antialiasing on looks bad.

But this is not just a visual issue. I use the same code for QGraphicsItem::shape() and it actually causes the item's shape to include the area beneath the curve which is undesirable.

Current (with above code)

enter image description here

Desired (produced with QPainerPath::quadTo(control, start))

enter image description here

Notice the bad edges of the desired curve due to QPainter drawing it twice - once from each direction.

What am I doing wrong here?

Resurrection
  • 3,916
  • 2
  • 34
  • 56
  • It is not clear what the problem is. Try posting an image with what you get and what you want to get. – dtech Oct 10 '15 at 18:33
  • @ddriver Added the images. – Resurrection Oct 10 '15 at 19:01
  • Yes, just what I was thinking, but I needed to make sure. – dtech Oct 10 '15 at 19:22
  • Also, the title was a little misleading, because ultimately your intent has nothing to do with "closing a curve". – dtech Oct 10 '15 at 21:12
  • @ddriver I modified the title a bit but I think it is correct. I needed to close a curve in the QPainterPath. That it's not possible does not mean the title is misleading. It is a problem not just for painting the curve but for example for the shape() method which returns incorrect shape for a simple curve (an area beneath the curve instead of the curve alone). So again, the shape must be QPainterPathStroker both for shape() and paint() to make it work as expected (or double curve there and back). Both are work-arounds due to the fact that one cannot close a curve in QPainterPath at end point. – Resurrection Oct 10 '15 at 21:24
  • I am still confused. Why do you say you want a closed curve, when in the picture with the desired result, you have an open curve? Are we talking about different things? Speaking theoretically, a closed curve is one that has no beginning nor end, in practice you can assume it begins and ends at the same point. Which is why that's the default behavior - Qt just draws a straight line from the first to the last point. Seems like you mean something like in say corel draw, where you convert outline to fill, is that what you want? – dtech Oct 10 '15 at 21:48
  • @ddriver I mean close curve as in QPainterPath terms. It uses the word "close" to end a given subpath, in this case curve. I wanted a curve subpath to end (be closed) at the end of a curve. However that is not possible because apparently every subpath in QPainterPath needs to end in its origin even if through "moveTo" that does not get painted. For shapes and filling however move elements are regarded as regular lines so "open shapes" are only visual illusions and not useful for determining actual shape as seen here. QPainterPathStroke is a solution as you have said of course. Thanks! – Resurrection Oct 10 '15 at 22:14
  • Finally got it LOL, you should have gone for something like "multiple curves in a path", or at least "end/terminate one curve and begin another", because "closing a curve" is exactly what Qt did and you were unhappy with. I mean, it is not like you are closing an account or door or something :) Curves end, they don't "close", doh, lingo :) Also, though you might say that a curve "has a shape", a curve is not intrinsically a shape. A shape is defined by a (technically) closed curve. – dtech Oct 10 '15 at 23:03

1 Answers1

3

What you are doing wrong is you are using a method which effectively fills a path, producing a shape.

You should use the void QPainter::strokePath(const QPainterPath & path, const QPen & pen) method instead, which will only draw a path stroke.

Granted, "draw path" does sound a little ambiguous. It gets even worse expecting QBrush to work as an artistic brush. I guess it was programmers who came up with those names, not artists.

EDIT: If what you want to get is the "shape" or geometry of the stroke/outline, i.e. what gets drawn by QPainter::strokePath(), you can generate it with QPainterPathStroker::createStroke(const QPainterPath & path) and then use QPainter::drawPath() with the resulting path, which will produce the same result as QPainter::strokePath().

EDIT 2: I finally got your intent LOL. It is actually possible to have "separate/individual curves" within a single painter path, either by means of using sub-paths, i.e:

    QPainter p(this);
    QPainterPath p1(QPointF(10,10)), p2(QPointF(50,10)), p3;
    p1.quadTo(QPointF(100,50), QPointF(100,200));
    p2.quadTo(QPointF(150,50), QPointF(150,200));
    p3.addPath(p1);
    p3.addPath(p2);
    p.strokePath(p3, QPen(Qt::black));

Simply moveTo() seems to also work:

    QPainter p(this);
    QPainterPath p1(QPointF(10,10));
    p1.quadTo(QPointF(100,50), QPointF(100,200));
    p1.moveTo(50, 10);
    p1.quadTo(QPointF(150,50), QPointF(150,200));
    p.strokePath(p1, QPen(Qt::black));

And tadaaa, multiple separate curves in one path:

enter image description here

Seems like not only the visual output is the same, both approaches also have the same number path elements. Yet, as mentioned in the comments, none of those solutions for two open curves actually produces a shape.

dtech
  • 47,916
  • 17
  • 112
  • 190