Я сделал MCVE , чтобы связаться с проблемой.
Таким образом, я использовал гораздо меньшие масштабирования и не смог воспроизвести проблему.Затем я использовал масштабирование 1.0E14, как указано в OP.Внезапно исчезли чертежи.Понизив масштабирование, я выяснил, что (в моем случае) до 1E12
это работало довольно хорошо, но с более высокими масштабами линии начали исчезать.Играя с этим, коллега ушел и дал намек, что это могут быть просто проблемы с плавающей точкой.Мы коротко обсудили это и пришли к выводу:
- умножение очень больших чисел на очень маленькие не проблема вообще.Он состоит из (целого) умножения мантисс и сложения показателей.
- сложение / вычитание больших чисел с очень маленькими является проблемой, так как оба числа должны быть сделаны с равными показателями (по битам)мантиссы) для добавления / вычитания мантисс.
Таким образом, может произойти последнее, что приведет к стиранию значений, отличных от 0, в 0.
10 14 в двоичном виде число с 47 цифрами.Это близко к точности double
с 53 битами мантиссы. Но : используемый механизм рендеринга QPainter
может быть основан на OpenGL, где float
является значением по умолчанию для многих вещей.float
предоставляет только 23 бита для мантиссы!
Итак, подумав немного об этом, я нашел веские причины не рисовать с коэффициентом масштабирования 10 14 .
Чтобы продемонстрировать это, я сделал небольшой образец 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
Скомпилировано и протестировано в cygwin64 :
$ qmake-qt5 testQPainterDrawLine.pro
$ make
$ ./testQPainterDrawLine
Qt Version: 5.9.4
Итак, наконец, я считаю, что это не имеет ничего общего с QPainter::drawLine()
против QPainter::drawPolyline()
.Это просто слишком большое масштабирование, которое вызывает проблемы с плавающей запятой.Вот почему линии могут случайно (не отображаться).
Решение простое: значения должны быть масштабированы до их рисования с помощью QPainter
, чтобы внутренние преобразования в QPainter
происходили в величинах, близких к 0и 1.