Skip to content
qwt_plot_spectrogram.cpp 16.7 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
 *****************************************************************************/

Bryant's avatar
Bryant committed
#include "qwt_plot_spectrogram.h"
pixhawk's avatar
pixhawk committed
#include "qwt_painter.h"
Bryant's avatar
Bryant committed
#include "qwt_interval.h"
pixhawk's avatar
pixhawk committed
#include "qwt_scale_map.h"
#include "qwt_color_map.h"
Bryant's avatar
Bryant committed
#include <qimage.h>
#include <qpen.h>
#include <qpainter.h>
#include <qmath.h>
#include <qalgorithms.h>
#if QT_VERSION >= 0x040400
#include <qthread.h>
#include <qfuture.h>
#include <qtconcurrentrun.h>
pixhawk's avatar
pixhawk committed
#endif

class QwtPlotSpectrogram::PrivateData
{
public:
Bryant's avatar
Bryant committed
    PrivateData():
        data( NULL )
pixhawk's avatar
pixhawk committed
    {
        colorMap = new QwtLinearColorMap();
        displayMode = ImageMode;

Bryant's avatar
Bryant committed
        conrecFlags = QwtRasterData::IgnoreAllVerticesOnLevel;
#if 0
        conrecFlags |= QwtRasterData::IgnoreOutOfRange;
#endif
pixhawk's avatar
pixhawk committed
    }
Bryant's avatar
Bryant committed
    ~PrivateData()
    {
pixhawk's avatar
pixhawk committed
        delete data;
        delete colorMap;
    }

    QwtRasterData *data;
    QwtColorMap *colorMap;
Bryant's avatar
Bryant committed
    DisplayModes displayMode;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QList<double> contourLevels;
pixhawk's avatar
pixhawk committed
    QPen defaultContourPen;
Bryant's avatar
Bryant committed
    QwtRasterData::ConrecFlags conrecFlags;
pixhawk's avatar
pixhawk committed
};

/*!
   Sets the following item attributes:
   - QwtPlotItem::AutoScale: true
   - QwtPlotItem::Legend:    false

   The z value is initialized by 8.0.
pixhawk's avatar
pixhawk committed
   \param title Title

   \sa QwtPlotItem::setItemAttribute(), QwtPlotItem::setZ()
*/
Bryant's avatar
Bryant committed
QwtPlotSpectrogram::QwtPlotSpectrogram( const QString &title ):
    QwtPlotRasterItem( title )
pixhawk's avatar
pixhawk committed
{
    d_data = new PrivateData();

Bryant's avatar
Bryant committed
    setItemAttribute( QwtPlotItem::AutoScale, true );
    setItemAttribute( QwtPlotItem::Legend, false );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    setZ( 8.0 );
pixhawk's avatar
pixhawk committed
}

//! Destructor
QwtPlotSpectrogram::~QwtPlotSpectrogram()
{
    delete d_data;
}

//! \return QwtPlotItem::Rtti_PlotSpectrogram
int QwtPlotSpectrogram::rtti() const
{
    return QwtPlotItem::Rtti_PlotSpectrogram;
}

/*!
   The display mode controls how the raster data will be represented.

   \param mode Display mode
   \param on On/Off

   The default setting enables ImageMode.

   \sa DisplayMode, displayMode()
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::setDisplayMode( DisplayMode mode, bool on )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( on != bool( mode & d_data->displayMode ) )
    {
pixhawk's avatar
pixhawk committed
        if ( on )
            d_data->displayMode |= mode;
        else
            d_data->displayMode &= ~mode;
    }

Bryant's avatar
Bryant committed
    legendChanged();
pixhawk's avatar
pixhawk committed
    itemChanged();
}

/*!
   The display mode controls how the raster data will be represented.

   \param mode Display mode
   \return true if mode is enabled
*/
Bryant's avatar
Bryant committed
bool QwtPlotSpectrogram::testDisplayMode( DisplayMode mode ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return ( d_data->displayMode & mode );
pixhawk's avatar
pixhawk committed
}

/*!
  Change the color map

  Often it is useful to display the mapping between intensities and
  colors as an additional plot axis, showing a color bar.

  \param colorMap Color Map

  \sa colorMap(), QwtScaleWidget::setColorBarEnabled(),
      QwtScaleWidget::setColorMap()
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::setColorMap( QwtColorMap *colorMap )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->colorMap != colorMap )
    {
        delete d_data->colorMap;
        d_data->colorMap = colorMap;
    }
pixhawk's avatar
pixhawk committed

    invalidateCache();
Bryant's avatar
Bryant committed

    legendChanged();
pixhawk's avatar
pixhawk committed
    itemChanged();
}

/*!
   \return Color Map used for mapping the intensity values to colors
   \sa setColorMap()
*/
Bryant's avatar
Bryant committed
const QwtColorMap *QwtPlotSpectrogram::colorMap() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->colorMap;
}

/*! 
  Build and assign the default pen for the contour lines
    
  In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
  non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
  to hide this incompatibility.
    
  \param color Pen color
  \param width Pen width
  \param style Pen style
    
  \sa pen(), brush()
 */ 
void QwtPlotSpectrogram::setDefaultContourPen( 
    const QColor &color, qreal width, Qt::PenStyle style )
{   
    setDefaultContourPen( QPen( color, width, style ) );
pixhawk's avatar
pixhawk committed
}

/*!
   \brief Set the default pen for the contour lines

   If the spectrogram has a valid default contour pen
pixhawk's avatar
pixhawk committed
   a contour line is painted using the default contour pen.
   Otherwise (pen.style() == Qt::NoPen) the pen is calculated
   for each contour level using contourPen().

Bryant's avatar
Bryant committed
   \sa defaultContourPen(), contourPen()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::setDefaultContourPen( const QPen &pen )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( pen != d_data->defaultContourPen )
    {
pixhawk's avatar
pixhawk committed
        d_data->defaultContourPen = pen;
Bryant's avatar
Bryant committed

        legendChanged();
pixhawk's avatar
pixhawk committed
        itemChanged();
    }
}

/*!
   \return Default contour pen
Bryant's avatar
Bryant committed
   \sa setDefaultContourPen()
pixhawk's avatar
pixhawk committed
*/
QPen QwtPlotSpectrogram::defaultContourPen() const
{
    return d_data->defaultContourPen;
}

/*!
   \brief Calculate the pen for a contour line
pixhawk's avatar
pixhawk committed
   The color of the pen is the color for level calculated by the color map
pixhawk's avatar
pixhawk committed
   \param level Contour level
   \return Pen for the contour line
   \note contourPen is only used if defaultContourPen().style() == Qt::NoPen

Bryant's avatar
Bryant committed
   \sa setDefaultContourPen(), setColorMap(), setContourLevels()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QPen QwtPlotSpectrogram::contourPen( double level ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->data == NULL || d_data->colorMap == NULL )
        return QPen();

    const QwtInterval intensityRange = d_data->data->interval(Qt::ZAxis);
    const QColor c( d_data->colorMap->rgb( intensityRange, level ) );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return QPen( c );
pixhawk's avatar
pixhawk committed
}

/*!
   Modify an attribute of the CONREC algorithm, used to calculate
   the contour lines.

Bryant's avatar
Bryant committed
   \param flag CONREC flag
pixhawk's avatar
pixhawk committed
   \param on On/Off

Bryant's avatar
Bryant committed
   \sa testConrecFlag(), renderContourLines(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::setConrecFlag(
    QwtRasterData::ConrecFlag flag, bool on )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( bool( d_data->conrecFlags & flag ) == on )
pixhawk's avatar
pixhawk committed
        return;

    if ( on )
Bryant's avatar
Bryant committed
        d_data->conrecFlags |= flag;
pixhawk's avatar
pixhawk committed
    else
Bryant's avatar
Bryant committed
        d_data->conrecFlags &= ~flag;
pixhawk's avatar
pixhawk committed

    itemChanged();
}

/*!
   Test an attribute of the CONREC algorithm, used to calculate
   the contour lines.

Bryant's avatar
Bryant committed
   \param flag CONREC flag
pixhawk's avatar
pixhawk committed
   \return true, is enabled

Bryant's avatar
Bryant committed
   The default setting enables QwtRasterData::IgnoreAllVerticesOnLevel

   \sa setConrecClag(), renderContourLines(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
bool QwtPlotSpectrogram::testConrecFlag(
    QwtRasterData::ConrecFlag flag ) const
Bryant's avatar
Bryant committed
    return d_data->conrecFlags & flag;
pixhawk's avatar
pixhawk committed
}

/*!
   Set the levels of the contour lines

   \param levels Values of the contour levels
Bryant's avatar
Bryant committed
   \sa contourLevels(), renderContourLines(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed

   \note contourLevels returns the same levels but sorted.
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::setContourLevels( const QList<double> &levels )
pixhawk's avatar
pixhawk committed
{
    d_data->contourLevels = levels;
Bryant's avatar
Bryant committed
    qSort( d_data->contourLevels );

    legendChanged();
pixhawk's avatar
pixhawk committed
    itemChanged();
}

/*!
Bryant's avatar
Bryant committed
   \return Levels of the contour lines.
pixhawk's avatar
pixhawk committed

   The levels are sorted in increasing order.

Bryant's avatar
Bryant committed
   \sa contourLevels(), renderContourLines(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QList<double> QwtPlotSpectrogram::contourLevels() const
pixhawk's avatar
pixhawk committed
{
    return d_data->contourLevels;
}

/*!
  Set the data to be displayed

  \param data Spectrogram Data
  \sa data()
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::setData( QwtRasterData *data )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( data != d_data->data )
    {
        delete d_data->data;
        d_data->data = data;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        invalidateCache();
        itemChanged();
    }
}

/*!
  \return Spectrogram data
  \sa setData()
*/
const QwtRasterData *QwtPlotSpectrogram::data() const
{
    return d_data->data;
pixhawk's avatar
pixhawk committed
}

/*!
  \return Spectrogram data
  \sa setData()
*/
Bryant's avatar
Bryant committed
QwtRasterData *QwtPlotSpectrogram::data()
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->data;
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
   \return Bounding interval for an axis

   The default implementation returns the interval of the
   associated raster data object.

   \param axis X, Y, or Z axis
   \sa QwtRasterData::interval()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QwtInterval QwtPlotSpectrogram::interval(Qt::Axis axis) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->data == NULL )
        return QwtInterval();

    return d_data->data->interval( axis );
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
   \brief Pixel hint

   The geometry of a pixel is used to calculated the resolution and
   alignment of the rendered image. 
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
   The default implementation returns data()->pixelHint( rect );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
   \param area In most implementations the resolution of the data doesn't
               depend on the requested area.

   \return Bounding rectangle of a pixel

   \sa QwtPlotRasterItem::pixelHint(), QwtRasterData::pixelHint(), 
       render(), renderImage()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->data == NULL )
        return QRectF();

    return d_data->data->pixelHint( area );
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
   \brief Render an image from data and color map.
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
   For each pixel of area the value is mapped into a color.
pixhawk's avatar
pixhawk committed

  \param xMap X-Scale Map
  \param yMap Y-Scale Map
Bryant's avatar
Bryant committed
  \param area Requested area for the image in scale coordinates
  \param imageSize Size of the requested image
pixhawk's avatar
pixhawk committed

   \return A QImage::Format_Indexed8 or QImage::Format_ARGB32 depending
pixhawk's avatar
pixhawk committed
           on the color map.

Bryant's avatar
Bryant committed
   \sa QwtRasterData::value(), QwtColorMap::rgb(),
pixhawk's avatar
pixhawk committed
       QwtColorMap::colorIndex()
*/
QImage QwtPlotSpectrogram::renderImage(
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
Bryant's avatar
Bryant committed
    const QRectF &area, const QSize &imageSize ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( imageSize.isEmpty() || d_data->data == NULL 
        || d_data->colorMap == NULL )
    {
pixhawk's avatar
pixhawk committed
        return QImage();
    }

Bryant's avatar
Bryant committed
    const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis );
pixhawk's avatar
pixhawk committed
    if ( !intensityRange.isValid() )
Bryant's avatar
Bryant committed
        return QImage();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB )
        ? QImage::Format_ARGB32 : QImage::Format_Indexed8;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QImage image( imageSize, format );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( d_data->colorMap->format() == QwtColorMap::Indexed )
        image.setColorTable( d_data->colorMap->colorTable( intensityRange ) );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    d_data->data->initRaster( area, image.size() );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
#if QT_VERSION >= 0x040400 && !defined(QT_NO_QFUTURE)
    uint numThreads = renderThreadCount();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( numThreads <= 0 )
        numThreads = QThread::idealThreadCount();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( numThreads <= 0 )
        numThreads = 1;

    const int numRows = imageSize.height() / numThreads;

    QList< QFuture<void> > futures;
    for ( uint i = 0; i < numThreads; i++ )
    {
        QRect tile( 0, i * numRows, image.width(), numRows );
        if ( i == numThreads - 1 )
        {
            tile.setHeight( image.height() - i * numRows );
            renderTile( xMap, yMap, tile, &image );
        }
        else
        {
            futures += QtConcurrent::run(
                this, &QwtPlotSpectrogram::renderTile,
                xMap, yMap, tile, &image );
pixhawk's avatar
pixhawk committed
        }
    }
Bryant's avatar
Bryant committed
    for ( int i = 0; i < futures.size(); i++ )
        futures[i].waitForFinished();

#else // QT_VERSION < 0x040400
    const QRect tile( 0, 0, image.width(), image.height() );
    renderTile( xMap, yMap, tile, &image );
#endif
pixhawk's avatar
pixhawk committed

    d_data->data->discardRaster();

Bryant's avatar
Bryant committed
    return image;
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
/*!
    \brief Render a tile of an image.

    Rendering in tiles can be used to composite an image in parallel
    threads.

    \param xMap X-Scale Map
    \param yMap Y-Scale Map
    \param tile Geometry of the tile in image coordinates
    \param image Image to be rendered
*/
void QwtPlotSpectrogram::renderTile(
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRect &tile, QImage *image ) const
{
    const QwtInterval range = d_data->data->interval( Qt::ZAxis );
    if ( !range.isValid() )
        return;

    if ( d_data->colorMap->format() == QwtColorMap::RGB )
    {
        for ( int y = tile.top(); y <= tile.bottom(); y++ )
        {
            const double ty = yMap.invTransform( y );

            QRgb *line = reinterpret_cast<QRgb *>( image->scanLine( y ) );
            line += tile.left();

            for ( int x = tile.left(); x <= tile.right(); x++ )
            {
                const double tx = xMap.invTransform( x );

                *line++ = d_data->colorMap->rgb( range,
                    d_data->data->value( tx, ty ) );
            }
        }
pixhawk's avatar
pixhawk committed
    }
Bryant's avatar
Bryant committed
    else if ( d_data->colorMap->format() == QwtColorMap::Indexed )
    {
        for ( int y = tile.top(); y <= tile.bottom(); y++ )
        {
            const double ty = yMap.invTransform( y );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            unsigned char *line = image->scanLine( y );
            line += tile.left();

            for ( int x = tile.left(); x <= tile.right(); x++ )
            {
                const double tx = xMap.invTransform( x );

                *line++ = d_data->colorMap->colorIndex( range,
                    d_data->data->value( tx, ty ) );
            }
        }
    }
pixhawk's avatar
pixhawk committed
}

/*!
   \brief Return the raster to be used by the CONREC contour algorithm.

Bryant's avatar
Bryant committed
   A larger size will improve the precision of the CONREC algorithm,
pixhawk's avatar
pixhawk committed
   but will slow down the time that is needed to calculate the lines.

   The default implementation returns rect.size() / 2 bounded to
Bryant's avatar
Bryant committed
   the resolution depending on pixelSize().
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
   \param area Rectangle, where to calculate the contour lines
   \param rect Rectangle in pixel coordinates, where to paint the contour lines
pixhawk's avatar
pixhawk committed
   \return Raster to be used by the CONREC contour algorithm.

   \note The size will be bounded to rect.size().
Bryant's avatar
Bryant committed
   \sa drawContourLines(), QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QSize QwtPlotSpectrogram::contourRasterSize( 
    const QRectF &area, const QRect &rect ) const
pixhawk's avatar
pixhawk committed
{
    QSize raster = rect.size() / 2;

Bryant's avatar
Bryant committed
    const QRectF pixelRect = pixelHint( area );
    if ( !pixelRect.isEmpty() )
    {
        const QSize res( qCeil( rect.width() / pixelRect.width() ),
            qCeil( rect.height() / pixelRect.height() ) );
        raster = raster.boundedTo( res );
    }
pixhawk's avatar
pixhawk committed

    return raster;
}

/*!
   Calculate contour lines

   \param rect Rectangle, where to calculate the contour lines
   \param raster Raster, used by the CONREC algorithm
Bryant's avatar
Bryant committed
   \return Calculated contour lines
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
   \sa contourLevels(), setConrecFlag(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
*/
QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines(
Bryant's avatar
Bryant committed
    const QRectF &rect, const QSize &raster ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->data == NULL )
        return QwtRasterData::ContourLines();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return d_data->data->contourLines( rect, raster,
        d_data->contourLevels, d_data->conrecFlags );
}
Don Gagne's avatar
Don Gagne committed

pixhawk's avatar
pixhawk committed
/*!
   Paint the contour lines

   \param painter Painter
   \param xMap Maps x-values into pixel coordinates.
   \param yMap Maps y-values into pixel coordinates.
   \param contourLines Contour lines

Bryant's avatar
Bryant committed
   \sa renderContourLines(), defaultContourPen(), contourPen()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::drawContourLines( QPainter *painter,
pixhawk's avatar
pixhawk committed
        const QwtScaleMap &xMap, const QwtScaleMap &yMap,
Bryant's avatar
Bryant committed
        const QwtRasterData::ContourLines &contourLines ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->data == NULL )
        return;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    const int numLevels = d_data->contourLevels.size();
    for ( int l = 0; l < numLevels; l++ )
    {
pixhawk's avatar
pixhawk committed
        const double level = d_data->contourLevels[l];

        QPen pen = defaultContourPen();
        if ( pen.style() == Qt::NoPen )
Bryant's avatar
Bryant committed
            pen = contourPen( level );
pixhawk's avatar
pixhawk committed

        if ( pen.style() == Qt::NoPen )
            continue;

Bryant's avatar
Bryant committed
        painter->setPen( pen );
pixhawk's avatar
pixhawk committed

        const QPolygonF &lines = contourLines[level];
Bryant's avatar
Bryant committed
        for ( int i = 0; i < lines.size(); i += 2 )
        {
            const QPointF p1( xMap.transform( lines[i].x() ),
                yMap.transform( lines[i].y() ) );
            const QPointF p2( xMap.transform( lines[i+1].x() ),
                yMap.transform( lines[i+1].y() ) );

            QwtPainter::drawLine( painter, p1, p2 );
pixhawk's avatar
pixhawk committed
        }
    }
}

/*!
  \brief Draw the spectrogram

  \param painter Painter
  \param xMap Maps x-values into pixel coordinates.
  \param yMap Maps y-values into pixel coordinates.
Bryant's avatar
Bryant committed
  \param canvasRect Contents rectangle of the canvas in painter coordinates
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \sa setDisplayMode(), renderImage(),
      QwtPlotRasterItem::draw(), drawContourLines()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotSpectrogram::draw( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect ) const
pixhawk's avatar
pixhawk committed
{
    if ( d_data->displayMode & ImageMode )
Bryant's avatar
Bryant committed
        QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( d_data->displayMode & ContourMode )
    {
        // Add some pixels at the borders
pixhawk's avatar
pixhawk committed
        const int margin = 2;
Bryant's avatar
Bryant committed
        QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin,
            canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        const QRectF br = boundingRect();
        if ( br.isValid() )
        {
pixhawk's avatar
pixhawk committed
            area &= br;
            if ( area.isEmpty() )
                return;

Bryant's avatar
Bryant committed
            rasterRect = QwtScaleMap::transform( xMap, yMap, area );
pixhawk's avatar
pixhawk committed
        }

Bryant's avatar
Bryant committed
        QSize raster = contourRasterSize( area, rasterRect.toRect() );
        raster = raster.boundedTo( rasterRect.toRect().size() );
        if ( raster.isValid() )
        {
pixhawk's avatar
pixhawk committed
            const QwtRasterData::ContourLines lines =
Bryant's avatar
Bryant committed
                renderContourLines( area, raster );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            drawContourLines( painter, xMap, yMap, lines );
pixhawk's avatar
pixhawk committed
        }
    }
}