C++ Qt-绘制多段线和绘制线之间的差异
在我的示例中,我以以下方式变换了qt画师的坐标系:C++ Qt-绘制多段线和绘制线之间的差异,c++,qt,qpainter,coordinate-transformation,C++,Qt,Qpainter,Coordinate Transformation,在我的示例中,我以以下方式变换了qt画师的坐标系: 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) 有这么大的规模,因为我
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绘制线条时(例如,如下所示):
这条线画得很正确。我做了一个决定来解决这个问题
因此,我使用了更小的缩放比例,无法重现该问题。然后,我使用了比例1.0E14,如OP所述。突然,线条图消失了。降低了缩放比例,我将(在我的例子中)调整到1E12
,效果非常好,但随着缩放比例的增加,线条开始消失。在玩弄这一点时,一位同事走了出来,暗示这可能只是浮点问题。我们很快对此进行了讨论,并得出结论:
- 将非常大的数字与非常小的数字相乘根本不是问题。它包括(整数)乘以尾数并加上指数
- 用非常小的数进行大数的加减运算是一个问题,因为两个数都必须以相等的指数(通过位移位尾数)进行加减尾数
QPainter
渲染引擎可能基于OpenGL,其中float
是许多事情的默认设置<代码>浮点仅为尾数提供23位
所以,在思考了一下这个问题之后,我找到了不使用比例因子1014绘制的好理由
为了演示这一点,我制作了一个小样本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();
}
编译和测试于:
$qmake-qt5 testQPainterDrawLine.pro
$make
$./testQPainterDrawLine
Qt版本:5.9.4
所以,最后,我相信,这与qpaint::drawLine()
与qpaint::drawlyline()
没有任何关系。只是比例太高,导致浮点问题。这就是为什么线条可能会意外(dis-)出现的原因
解决方案很简单:在使用QPainter
绘制值之前,必须对值进行缩放,以便QPainter
中的内部转换发生在接近0和1的量级上。我提出了一个解决问题的方案
因此,我使用了更小的缩放比例,无法重现该问题。然后,我使用了比例1.0E14,如OP所述。突然,线条图消失了。降低了缩放比例,我将(在我的例子中)调整到1E12
,效果非常好,但随着缩放比例的增加,线条开始消失。在玩弄这一点时,一位同事走了出来,暗示这可能只是浮点问题。我们很快对此进行了讨论,并得出结论:
- 将非常大的数字与非常小的数字相乘根本不是问题。它包括(整数)乘以尾数并加上指数
- 用非常小的数进行大数的加减运算是一个问题,因为两个数都必须以相等的指数(通过位移位尾数)进行加减尾数
QPainter
渲染引擎可能基于OpenGL,其中float
是许多事情的默认设置<代码>浮点仅为尾数提供23位
所以,在思考了一下这个问题之后,我找到了不使用比例因子1014绘制的好理由
为了演示这一点,我制作了一个小样本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();
}
编译和测试于:
$qmake-qt5 testQPainterDrawLine.pro
$make
$./testQPainterDrawLine
Qt版本:5.9.4
所以,最后,我相信,这与qpaint::drawLine()
与qpaint::drawlyline()
没有任何关系。只是比例太高,导致浮点问题。这就是为什么线条可能会意外(dis-)出现的原因
解决方案很简单:在使用
QPainter
绘制值之前,必须对值进行缩放,以便QPainter
中的内部转换的大小接近于0和1。1。我调查了Qt医生。找不到任何描述的差异。2.我在woboq.org上查过。有许多不同的选项可以画出一条线,其中大多数都以引擎调用的相同函数结束。所以,应该没有什么区别。我可能忽略了什么。然而,我很确定这是一个特定引擎中的bug。因此,您可以查找Qt版本的更新,或者只需专门使用drawPolyline()
来解决此问题。1。我调查了Qt医生。找不到任何描述的差异。2.我在woboq.org上查过。有许多不同的选项可以画出一条线,其中大多数都以引擎调用的相同函数结束。所以,应该没有什么区别。我可能忽略了什么。然而,我很确定这是一个特定引擎中的bug。因此,您可以查找Qt版本的更新,或者只需使用drawPolyline()#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();
}