Menu

#226 QwtPointMapper rounding overflow

None
closed
nobody
None
5
2016-02-27
2015-02-11
Anonymous
No

QwtPointMapper uses qRound() to transform float values to integer coordinates. This may cause an overflow, negative coordinates and incorrect plot lines drawing on deep zoom. For example, when horizontal axis is date/time axis and has large values that become even larger when zoomed. qRound() should probably be replaced by qRound64().

Discussion

  • Anonymous

    Anonymous - 2015-02-11

    Example:

    class MyPlotZoomer : public QwtPlotZoomer
    {
    public:
        MyPlotZoomer(QWidget* canvas) : QwtPlotZoomer(canvas) {}
    protected:
        QSizeF minZoomSize() const
        {
            // one second range
            return QSizeF(1, QwtPlotZoomer::minZoomSize().height());
        }
    };
    
    MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
    {
        QVector<QPointF> data;
        QDateTime xMin = QDateTime(QDate(2014, 1, 1));
        QDateTime xMax = QDateTime(QDate(2015, 1, 1));
        double yMin = 0;
        double yMax = 1;
        data.append(QPointF(xMin.toTime_t(), yMin));
        data.append(QPointF(xMax.toTime_t(), yMax));
    
        QwtPointSeriesData* seriesData = new QwtPointSeriesData(data);
        QwtPlotCurve* curve = new QwtPlotCurve();
        curve->setData(seriesData);
        curve->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, QBrush(Qt::black), QPen(), QSize(4, 4)));
        QwtPlot* plot = new QwtPlot(this);
        curve->attach(plot);
        MyPlotZoomer* zoomer = new MyPlotZoomer(plot->canvas());
        setCentralWidget(plot);
    
        // zoom to (xMin, yMin)
        //zoomer->zoom(QRectF(xMin.toTime_t() - 1, yMin - 1, 2, 2));
    }
    
     
  • Uwe Rathmann

    Uwe Rathmann - 2015-04-07

    When using integers ( regardless of 32/64 bit ) you might run into this overflow situation and the best way to avoid it is to stay with doubles.

    Fortunately QwtPointMapper already supports this and in combination with QwtPlotCurve::ClipPolygons it is possible to clip away large values before mapping them to paint device coordinates ( integers again for QWidget ).

    By QwtPainter::setRoundingAlignment( false ) you can tell QwtPlotCurve to run into the non rounding path ( maybe overload QwtPlotCurve::drawSeries, enabling/disabling this flag ).

    There were a couple of reasons, why Qwt is rounding to integers manually - one of them was that in several Qt versions the raster paint engine is significantly slower for doubles, than for integers. But I need to re-evaluate the situation for the relevant Qt versions we have today - that's why I will keep this bug report open for the moment.

     
  • Uwe Rathmann

    Uwe Rathmann - 2016-02-27
    • status: open --> closed
    • Group: -->
     
  • Uwe Rathmann

    Uwe Rathmann - 2016-02-27

    Unfortunately nearbyint()/round() are not available on all platforms. Therefore I added a slightly less performant version without having integers involved.

    Fixed on all branches >= 6.1

     

Anonymous
Anonymous

Add attachments
Cancel