Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/164.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Qt-绘制多段线和绘制线之间的差异_C++_Qt_Qpainter_Coordinate Transformation - Fatal编程技术网

C++ 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) 有这么大的规模,因为我

在我的示例中,我以以下方式变换了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)
有这么大的规模,因为我的示例中的数据非常小。然后我为我的数据绘制了一张图——它的值大约为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
,效果非常好,但随着缩放比例的增加,线条开始消失。在玩弄这一点时,一位同事走了出来,暗示这可能只是浮点问题。我们很快对此进行了讨论,并得出结论:

  • 将非常大的数字与非常小的数字相乘根本不是问题。它包括(整数)乘以尾数并加上指数
  • 用非常小的数进行大数的加减运算是一个问题,因为两个数都必须以相等的指数(通过位移位尾数)进行加减尾数
因此,后者可能会将非0值擦除为0

1014是一个47位的二进制数。这接近尾数为53位的双精度但是:使用的
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
,效果非常好,但随着缩放比例的增加,线条开始消失。在玩弄这一点时,一位同事走了出来,暗示这可能只是浮点问题。我们很快对此进行了讨论,并得出结论:

  • 将非常大的数字与非常小的数字相乘根本不是问题。它包括(整数)乘以尾数并加上指数
  • 用非常小的数进行大数的加减运算是一个问题,因为两个数都必须以相等的指数(通过位移位尾数)进行加减尾数
因此,后者可能会将非0值擦除为0

1014是一个47位的二进制数。这接近尾数为53位的双精度但是:使用的
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();
}