PDA

View Full Version : QPainterPath::arcTo draws asymmertric "circle"



stryga42
28th December 2019, 17:18
I try to draw a "stadium-shape" (two half circles connected by straight lines) using QPainter on a QPainterPath. This basically works but the half circles are always slightly asymmetric. A casual viewer won't notice but for the trained eye this is really annoying.
The details - I removed the straight lines so that it becomes clear what belongs to the arc.
r is the radius of the (half)circles, d is the length of the straight line, a1 and a2 are the arc starting angles and a is always 180 deg for a semicircle.


QPainterPath p;
painter.setPen(colFont);
painter.setBrush(colBack);
QRectF lb(0, 0, 2*r, 2*r), rb(d, 0, 2*r, 2*r);
qreal a1(90), a2(270), a(180);
qDebug()<<"RBOX"<<r<<d<<lb<<rb<<a1<<a2<<a;
p.moveTo(r, r);
p.arcTo(lb, a1, a);
p.moveTo(r+d, r);
p.arcTo(rb, a2, a);
painter.drawPath(p);

This yields

RBOX 14 34 QRectF(0,0 28x28) QRectF(34,0 28x28) 90 270 180
13308
Yellow and orange stuff belongs to other widgets. The gimp selection marker you see in the screenshot is 14x28 pixel - the bounding box I would expect for the half circle. As you may notice, the upper half and the lower half are not mirror images of each other - which they should be to my understanding.

I also tried to make the width and height of the bounding box uneven integers, so that the circle has true "center pixels". Doesn't make a big difference, the asymmetry remains:


QPainterPath p;
painter.setPen(colFont);
painter.setBrush(colBack);
QRectF lb(0, 0, 2*r+1, 2*r+1), rb(d, 0, 2*r+1, 2*r+1);
qreal a1(90), a2(270), a(180);
qDebug()<<"RBOX"<<r<<d<<lb<<rb<<a1<<a2<<a;
p.moveTo(r, r);
p.arcTo(lb, a1, a);
p.moveTo(r+d, r);
p.arcTo(rb, a2, a);
painter.drawPath(p);


RBOX 14 34 QRectF(0,0 29x29) QRectF(34,0 29x29) 90 270 180
gimp box is now 15x29
13309
Has anyone an idea why the upper half of the semicircle is not a mirror image of the lower half?

Qt 5.7.0 open source on Ubuntu 18.04.3

ChrisW67
28th December 2019, 23:30
Your QPainterPath is not closed, so the outline is not complete, which more than likely explains the half-and-half colouring along the diameter. You need to call closeSubpath() as described here:
https://doc.qt.io/qt-5/qpainterpath.html#arcTo

I would guess that anti-aliasing combined with the coordinate system has something to do with the remaining asymmetry
You could try it without the anti-aliasing render hint.
There's quite a lot of detail here: https://doc.qt.io/qt-5/coordsys.html#rendering

You are drawing full semicircles, so you could also use QPainter::drawPie() to see if that result is more to your liking. (The restrictions on angles in this function suggest it is relying heavily on symmetry for speed.)

stryga42
29th December 2019, 14:57
Thank you for your suggestions!

not closed path: that just happened because I removed the straight lines to make clear what belongs to the arc - not relevant to the problem, sorry for the confusion.

rendering hints, especially QPainter::Antialiasing. Good input, that solved the issue. Although the pixel pattern is still not symmetrical in a mathematical sense it is good enough even for the most nitpicking viewer.

QPainter::drawPie(): no change, gives identical pixel patterns to QPainter::arcTo(). Seems to use the same internal engine.

For me it looks like the underlying draw engine does not draw pixels according to the distance (center of pixel)<->(mathematically ideal position) but (lower right corner of pixel)<->(mathematically ideal position) or something like this.
Anyway, problem solved, many thanks!