Skip to content
Snippets Groups Projects
qwt_plot_rasteritem.cpp 7.45 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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 <qapplication.h>
    #include <qdesktopwidget.h>
    #include <qpaintdevice.h>
    #include <qpainter.h>
    #include "qwt_legend.h"
    #include "qwt_legend_item.h"
    #include "qwt_scale_map.h"
    #include "qwt_plot_rasteritem.h"
    
    class QwtPlotRasterItem::PrivateData
    {
    public:
        PrivateData():
            alpha(-1)
        {
            cache.policy = QwtPlotRasterItem::NoCache;
        }
    
        int alpha;
    
        struct ImageCache
        {
            QwtPlotRasterItem::CachePolicy policy;
            QwtDoubleRect rect;
            QSize size;
            QImage image;
        } cache;
    };
    
    static QImage toRgba(const QImage& image, int alpha)
    {
        if ( alpha < 0 || alpha >= 255 )  
            return image;
    
    #if QT_VERSION < 0x040000
        QImage alphaImage(image.size(), 32);
        alphaImage.setAlphaBuffer(true);
    #else
        QImage alphaImage(image.size(), QImage::Format_ARGB32);
    #endif
    
        const QRgb mask1 = qRgba(0, 0, 0, alpha);
        const QRgb mask2 = qRgba(255, 255, 255, 0);
        const QRgb mask3 = qRgba(0, 0, 0, 255);
    
        const int w = image.size().width();
        const int h = image.size().height();
    
        if ( image.depth() == 8 )
        {
            for ( int y = 0; y < h; y++ )
            {
                QRgb* alphaLine = (QRgb*)alphaImage.scanLine(y);
                const unsigned char *line = image.scanLine(y);
    
                for ( int x = 0; x < w; x++ )
                    *alphaLine++ = (image.color(*line++) & mask2) | mask1;
            }
        }
        else if ( image.depth() == 32 )
        {
            for ( int y = 0; y < h; y++ )
            {
                QRgb* alphaLine = (QRgb*)alphaImage.scanLine(y);
                const QRgb* line = (const QRgb*) image.scanLine(y);
    
                for ( int x = 0; x < w; x++ )
                {
                    const QRgb rgb = *line++;
                    if ( rgb & mask3 ) // alpha != 0
                        *alphaLine++ = (rgb & mask2) | mask1;
                    else
                        *alphaLine++ = rgb;
                }
            }
        }
    
        return alphaImage;
    }
    
    //! Constructor
    QwtPlotRasterItem::QwtPlotRasterItem(const QString& title):
        QwtPlotItem(QwtText(title))
    {
        init();
    }
    
    //! Constructor
    QwtPlotRasterItem::QwtPlotRasterItem(const QwtText& title):
        QwtPlotItem(title)
    {
        init();
    }
    
    //! Destructor
    QwtPlotRasterItem::~QwtPlotRasterItem()
    {
        delete d_data;
    }
    
    void QwtPlotRasterItem::init()
    {
        d_data = new PrivateData();
    
        setItemAttribute(QwtPlotItem::AutoScale, true);
        setItemAttribute(QwtPlotItem::Legend, false);
    
        setZ(8.0);
    }
    
    /*!
       \brief Set an alpha value for the raster data
    
       Often a plot has several types of raster data organized in layers.
       ( f.e a geographical map, with weather statistics ).
       Using setAlpha() raster items can be stacked easily.
    
       The alpha value is a value [0, 255] to
       control the transparency of the image. 0 represents a fully 
       transparent color, while 255 represents a fully opaque color.
       
       \param alpha Alpha value
    
       - alpha >= 0\n
         All alpha values of the pixels returned by renderImage() will be set to 
         alpha, beside those with an alpha value of 0 (invalid pixels). 
       - alpha < 0
         The alpha values returned by renderImage() are not changed.
    
       The default alpha value is -1.
    
       \sa alpha()
    */
    void QwtPlotRasterItem::setAlpha(int alpha)
    {
        if ( alpha < 0 )
            alpha = -1;
    
        if ( alpha > 255 )
            alpha = 255;
    
        if ( alpha != d_data->alpha )
        {
            d_data->alpha = alpha;
    
            itemChanged();
        }
    }
    
    /*!
      \return Alpha value of the raster item
      \sa setAlpha()
    */
    int QwtPlotRasterItem::alpha() const
    {
        return d_data->alpha;
    }
    
    /*!
      Change the cache policy
    
      The default policy is NoCache
    
      \param policy Cache policy
      \sa CachePolicy, cachePolicy()
    */
    void QwtPlotRasterItem::setCachePolicy(
        QwtPlotRasterItem::CachePolicy policy)
    {
        if ( d_data->cache.policy != policy )
        {
            d_data->cache.policy = policy;
    
            invalidateCache();
            itemChanged();
        }
    }
    
    /*!
      \return Cache policy
      \sa CachePolicy, setCachePolicy()
    */
    QwtPlotRasterItem::CachePolicy QwtPlotRasterItem::cachePolicy() const
    {
        return d_data->cache.policy;
    }
    
    /*!
       Invalidate the paint cache
       \sa setCachePolicy
    */
    void QwtPlotRasterItem::invalidateCache()
    {
        d_data->cache.image = QImage();
        d_data->cache.rect = QwtDoubleRect();
        d_data->cache.size = QSize();
    }
    
    /*!
       \brief Returns the recommended raster for a given rect.
    
       F.e the raster hint can be used to limit the resolution of
       the image that is rendered.
    
       The default implementation returns an invalid size (QSize()),
       what means: no hint.
    */
    QSize QwtPlotRasterItem::rasterHint(const QwtDoubleRect &) const
    {
        return QSize();
    }
    
    /*!
      \brief Draw the raster data
      \param painter Painter
      \param xMap X-Scale Map
      \param yMap Y-Scale Map
      \param canvasRect Contents rect of the plot canvas
    */
    void QwtPlotRasterItem::draw(QPainter *painter,
        const QwtScaleMap &xMap, const QwtScaleMap &yMap,
        const QRect &canvasRect) const
    {
        if ( canvasRect.isEmpty() || d_data->alpha == 0 )
            return;
    
        QwtDoubleRect area = invTransform(xMap, yMap, canvasRect);
        if ( boundingRect().isValid() )
            area &= boundingRect();
    
        const QRect paintRect = transform(xMap, yMap, area);
        if ( !paintRect.isValid() )
            return;
    
        QImage image;
    
        bool doCache = true;
        if ( painter->device()->devType() == QInternal::Printer 
                || painter->device()->devType() == QInternal::Picture )
        {
            doCache = false;
        }
    
        if ( !doCache || d_data->cache.policy == NoCache )
        {
            image = renderImage(xMap, yMap, area);
            if ( d_data->alpha >= 0 && d_data->alpha < 255 )
                image = toRgba(image, d_data->alpha);
    
        }
        else if ( d_data->cache.policy == PaintCache )
        {
            if ( d_data->cache.image.isNull() || d_data->cache.rect != area
                || d_data->cache.size != paintRect.size() )
            {
                d_data->cache.image = renderImage(xMap, yMap, area);
                d_data->cache.rect = area;
                d_data->cache.size = paintRect.size();
            }
    
            image = d_data->cache.image;
            if ( d_data->alpha >= 0 && d_data->alpha < 255 )
                image = toRgba(image, d_data->alpha);
        }
        else if ( d_data->cache.policy == ScreenCache )
        {
            const QSize screenSize =
                QApplication::desktop()->screenGeometry().size();
    
            if ( paintRect.width() > screenSize.width() ||
                paintRect.height() > screenSize.height() )
            {
                image = renderImage(xMap, yMap, area);
            }
            else
            {
                if ( d_data->cache.image.isNull() || d_data->cache.rect != area )
                {
                    QwtScaleMap cacheXMap = xMap;
                    cacheXMap.setPaintInterval( 0, screenSize.width());
    
                    QwtScaleMap cacheYMap = yMap;
                    cacheYMap.setPaintInterval(screenSize.height(), 0);
    
                    d_data->cache.image = renderImage(
                        cacheXMap, cacheYMap, area);
                    d_data->cache.rect = area;
                    d_data->cache.size = paintRect.size();
                }
    
                image = d_data->cache.image;
            }
            image = toRgba(image, d_data->alpha);
        }
    
        painter->drawImage(paintRect, image);
    }