In my example I transformed the coordinate system of the qt painter in the following way:
QTransform xform;
xform.rotate(90);
xform.scale(1, 1000000000000000);
xform.translate(0, -std::abs(max));
if (limit != 0)
xform.scale(1, std::abs(max)/std::abs(limit));
painter->setTransform(xform)
There is such a big scale because I have very small data in my example. Then I draw the plot for my data - it's values are about 1e-14 and everything is drawn correctly. Then I want to draw couple of lines in addition to my plot specified by two points.
I apply drawPolyLine function:
QPointF* line = new QPointF[2];
line[0].setX(0);
line[0].setY(0);
line[1].setX(0);
line[1].setY(std::abs(seismMax));
painter.drawPolyline(line, 2);
where seismMax is of the orders of 1e-14 ( as all my points in the plot). And the line is drawn. Then I apply drawLine ( as I have only two points):
painter.drawLine(QPointF(0, 0), QPointF(0, std::abs(seismMax)));
And in this case line is not drawn. I suspect that maybe these two functions process coordinates differently. As when I draw the line with drawLine in original scale (for example like this) :
painter.drawLine(QPointF(0, 0), QPointF(0, 1000));
the line is drawn correctly.
I made an MCVE to come in touch with the problem.
Thereby, I used much smaller scalings and was not able to reproduce the issue. Then, I used the scaling 1.0E14 as stated by OP. Suddenly, the line drawings disappeared. Lowering the scaling, I fiddled out that (in my case) upto 1E12
it worked quite good but with higher scalings lines begun to disappear. While toying with this, a colleague came away and provided the hint that this might been simply floating point issues. We shortly discussed this and came to the conclusion:
So, the latter might happen which erases the non-0 values to 0.
1014 is in binary a number with 47 digits. This is close to the precision of double
with 53 bits mantissa. But: the used rendering engine of QPainter
may be based on OpenGL where float
is the default for many things. float
provides only 23 bits for mantissa!
So, after thinking a bit about this, I found good reasons not to paint with a scaling factor of 1014.
To demonstrate this, I made a small sample testQPainterDrawLine.cc
:
#include <QtWidgets>
class Widget: public QWidget {
public:
const double scale;
public:
Widget(double scale, QWidget *pQParent = nullptr):
QWidget(pQParent),
scale(scale)
{ }
virtual ~Widget() = default;
Widget(const Widget&) = delete;
Widget& operator=(const Widget&) = delete;
protected:
virtual void paintEvent(QPaintEvent *pQEvent) override;
};
void Widget::paintEvent(QPaintEvent*)
{
const double value = height() / scale;
QPainter qPainter(this);
qPainter.fillRect(0, 0, width(), height(), QColor(Qt::white));
qPainter.drawRect(0, 0, width() - 1, height() - 1);
QTransform xform;
xform.scale(1, scale);
qPainter.setTransform(xform);
qPainter.setPen(QPen(QColor(Qt::red), 3.0));
const double xL = 0.333 * width();
qPainter.drawLine(QPointF(xL, 0.0), QPointF(xL, value));
qPainter.setPen(QPen(QColor(Qt::blue), 3.0));
const double xPL = 0.667 * width();
QPointF qPts[] = { QPointF(xPL, 0.0), QPointF(xPL, value) };
const int nPts = sizeof qPts / sizeof *qPts;
qPainter.drawPolyline(qPts, nPts);
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QWidget qWin;
QGridLayout qGrid;
qGrid.setRowStretch(0, 0); qGrid.setRowStretch(1, 1);
double scale = 1.0E11;
for (int i = 0; i < 4; ++i, scale *= 10.0) {
qGrid.addWidget(
new QLabel(QString("Scale: %1").arg(scale)),
0, i);
qGrid.addWidget(new Widget(scale), 1, i);
}
qWin.setLayout(&qGrid);
qWin.resize(1024, 256);
qWin.show();
return app.exec();
}
testQPainterDrawLine.pro
:
SOURCES = testQPainterDrawLine.cc
QT = widgets
Compiled and tested in cygwin64:
$ qmake-qt5 testQPainterDrawLine.pro
$ make
$ ./testQPainterDrawLine
Qt Version: 5.9.4
So, finally, I believe, it hasn't anything to do with QPainter::drawLine()
vs. QPainter::drawPolyline()
. It's simply the scaling which is too high and causes floating point issues. That's why lines may accidentally (dis-)appear.
The solution is simple: The values have to be scaled before drawing them with QPainter
, so that internal transformations in QPainter
happen in magnitudes closer to 0 and 1.