在我的示例中,我通过以下方式转换了qt painter的坐标系:
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)
之所以如此庞大,是因为我的示例中的数据非常少。然后,我为数据绘制图-它的值大约为1e-14,并且一切都正确绘制。然后,我除了要绘制由两个点指定的图外,还要绘制几条线。
我应用了drawPolyLine函数:
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);
其中seismMax大约为1e-14(作为图中所有点)。并画出了线。 然后我应用drawLine(因为我只有两点):
painter.drawLine(QPointF(0, 0), QPointF(0, std::abs(seismMax)));
在这种情况下,未绘制线。我怀疑这两个功能处理的坐标可能不同。就像我用drawLine以原始比例绘制线条时(例如这样):
painter.drawLine(QPointF(0, 0), QPointF(0, 1000));
线条正确绘制。
答案 0 :(得分:3)
我提出了MCVE来解决问题。
因此,我使用的缩放比例小得多,无法重现该问题。然后,我使用了OP所述的缩放比例1.0E14。突然,线条图消失了。降低缩放比例,我弄弄说(以我为例)直到1E12
都很好用,但是缩放比例较高的行开始消失。玩弄这个时,一位同事走了,并暗示这可能只是浮点问题。我们对此进行了简短讨论并得出结论:
因此,后者可能会发生,从而将非0值擦除为0。
10 14 是二进制的47位数字。 53位尾数接近double
的精度。 但是: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。