Skip to content
qwt_plot_curve.cpp 34.8 KiB
Newer Older
pixhawk's avatar
pixhawk committed
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

#include <qpainter.h>
#include <qpixmap.h>
#include <qbitarray.h>
#include "qwt_global.h"
#include "qwt_legend.h"
#include "qwt_legend_item.h"
#include "qwt_data.h"
#include "qwt_scale_map.h"
#include "qwt_double_rect.h"
#include "qwt_math.h"
#include "qwt_clipper.h"
#include "qwt_painter.h"
#include "qwt_plot.h"
#include "qwt_plot_canvas.h"
#include "qwt_curve_fitter.h"
#include "qwt_symbol.h"
#include "qwt_plot_curve.h"

#define SCALE_PEN 0

#if QT_VERSION < 0x040000
#include <qguardedptr.h>
#else
#include <qpointer.h>
#endif

#if QT_VERSION >= 0x040000

#include <qevent.h>
#include <qpaintengine.h>

class QwtPlotCurvePaintHelper: public QObject
{
public:
    QwtPlotCurvePaintHelper(const QwtPlotCurve *curve, int from, int to):
        _curve(curve),
        _from(from),
pixhawk's avatar
pixhawk committed
    }

    virtual bool eventFilter(QObject *, QEvent *event) {
        if ( event->type() == QEvent::Paint ) {
pixhawk's avatar
pixhawk committed
            _curve->draw(_from, _to);
            return true;
        }
        return false;
    }
private:
    const QwtPlotCurve *_curve;
    int _from;
    int _to;
};

#endif // QT_VERSION >= 0x040000

// Creating and initializing a QPainter is an
// expensive operation. So we keep an painter
// open for situations, where we paint outside
// of paint events. This improves the performance
// of incremental painting like in the realtime
// example a lot.
// But it is not possible to have more than
// one QPainter open at the same time. So we
// need to close it before regular paint events
// are processed.

class QwtGuardedPainter: public QObject
{
public:
    ~QwtGuardedPainter() {
pixhawk's avatar
pixhawk committed
        end();
    }

    QPainter *begin(QwtPlotCanvas *canvas) {
pixhawk's avatar
pixhawk committed
        _canvas = canvas;

        QMap<QwtPlotCanvas *, QPainter *>::iterator it = _map.find(_canvas);
        if ( it == _map.end() ) {
pixhawk's avatar
pixhawk committed
            QPainter *painter = new QPainter(_canvas);
            painter->setClipping(true);
            painter->setClipRect(_canvas->contentsRect());

            it = _map.insert(_canvas, painter);
            _canvas->installEventFilter(this);
        }
#if QT_VERSION < 0x040000
        return it.data();
#else
        return it.value();
#endif
    }

    void end() {
        if ( _canvas ) {
pixhawk's avatar
pixhawk committed
            QMap<QwtPlotCanvas *, QPainter *>::iterator it = _map.find(_canvas);
            if ( it != _map.end() ) {
pixhawk's avatar
pixhawk committed
                _canvas->removeEventFilter(this);

#if QT_VERSION < 0x040000
                delete it.data();
#else
                delete it.value();
#endif
                _map.erase(it);
            }
        }
    }

    virtual bool eventFilter(QObject *, QEvent *event) {
pixhawk's avatar
pixhawk committed
        if ( event->type() == QEvent::Paint )
            end();

        return false;
    }

private:
#if QT_VERSION < 0x040000
pixhawk's avatar
pixhawk committed
    QGuardedPtr<QwtPlotCanvas> _canvas;
#else
    QPointer<QwtPlotCanvas> _canvas;
#endif
    static QMap<QwtPlotCanvas *, QPainter *> _map;
};

QMap<QwtPlotCanvas *, QPainter *> QwtGuardedPainter::_map;

static QwtPolygon clipPolygon(QPainter *painter, int attributes,
                              const QwtPolygon &polygon)
pixhawk's avatar
pixhawk committed
{
    bool doClipping = attributes & QwtPlotCurve::ClipPolygons;
    QRect clipRect = painter->window();

    if ( !doClipping ) {
pixhawk's avatar
pixhawk committed
#if QT_VERSION >= 0x040000
        const QPaintEngine *pe = painter->paintEngine();
        if ( pe && pe->type() == QPaintEngine::SVG )
#else
        if ( painter->device()->devType() == QInternal::Picture )
#endif
        {
            // The SVG paint engine ignores any clipping,
            // so we enable polygon clipping.

            doClipping = true;
            if ( painter->hasClipping() )
                clipRect &= painter->clipRegion().boundingRect();
        }
    }

    if ( doClipping )
        return QwtClipper::clipPolygon(clipRect, polygon);
pixhawk's avatar
pixhawk committed
    return polygon;
}

static int verifyRange(int size, int &i1, int &i2)
{
    if (size < 1)
pixhawk's avatar
pixhawk committed
        return 0;

    i1 = qwtLim(i1, 0, size-1);
    i2 = qwtLim(i2, 0, size-1);

    if ( i1 > i2 )
        qSwap(i1, i2);

    return (i2 - i1 + 1);
}

class QwtPlotCurve::PrivateData
{
public:
    class PixelMatrix: private QBitArray
    {
    public:
        PixelMatrix(const QRect& rect):
            QBitArray(rect.width() * rect.height()),
            _rect(rect) {
pixhawk's avatar
pixhawk committed
            fill(false);
        }

        inline bool testPixel(const QPoint& pos) {
pixhawk's avatar
pixhawk committed
            if ( !_rect.contains(pos) )
                return false;

            const int idx = _rect.width() * (pos.y() - _rect.y()) +
                            (pos.x() - _rect.x());
pixhawk's avatar
pixhawk committed

            const bool marked = testBit(idx);
            if ( !marked )
                setBit(idx, true);
Loading
Loading full blame...