qwt_plot_spectrogram.cpp 16.7 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9
/* -*- 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
10
#include "qwt_plot_spectrogram.h"
pixhawk's avatar
pixhawk committed
11
#include "qwt_painter.h"
Bryant's avatar
Bryant committed
12
#include "qwt_interval.h"
pixhawk's avatar
pixhawk committed
13 14
#include "qwt_scale_map.h"
#include "qwt_color_map.h"
Bryant's avatar
Bryant committed
15 16 17 18 19 20 21 22 23
#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
24 25 26 27 28
#endif

class QwtPlotSpectrogram::PrivateData
{
public:
Bryant's avatar
Bryant committed
29 30
    PrivateData():
        data( NULL )
pixhawk's avatar
pixhawk committed
31 32 33 34
    {
        colorMap = new QwtLinearColorMap();
        displayMode = ImageMode;

Bryant's avatar
Bryant committed
35 36 37 38
        conrecFlags = QwtRasterData::IgnoreAllVerticesOnLevel;
#if 0
        conrecFlags |= QwtRasterData::IgnoreOutOfRange;
#endif
pixhawk's avatar
pixhawk committed
39
    }
Bryant's avatar
Bryant committed
40 41
    ~PrivateData()
    {
pixhawk's avatar
pixhawk committed
42 43 44 45 46 47
        delete data;
        delete colorMap;
    }

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

Bryant's avatar
Bryant committed
50
    QList<double> contourLevels;
pixhawk's avatar
pixhawk committed
51
    QPen defaultContourPen;
Bryant's avatar
Bryant committed
52
    QwtRasterData::ConrecFlags conrecFlags;
pixhawk's avatar
pixhawk committed
53 54 55 56 57 58 59 60
};

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

   The z value is initialized by 8.0.
61

pixhawk's avatar
pixhawk committed
62 63 64 65
   \param title Title

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

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

Bryant's avatar
Bryant committed
74
    setZ( 8.0 );
pixhawk's avatar
pixhawk committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
}

//! 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
99
void QwtPlotSpectrogram::setDisplayMode( DisplayMode mode, bool on )
pixhawk's avatar
pixhawk committed
100
{
Bryant's avatar
Bryant committed
101 102
    if ( on != bool( mode & d_data->displayMode ) )
    {
pixhawk's avatar
pixhawk committed
103 104 105 106 107 108
        if ( on )
            d_data->displayMode |= mode;
        else
            d_data->displayMode &= ~mode;
    }

Bryant's avatar
Bryant committed
109
    legendChanged();
pixhawk's avatar
pixhawk committed
110 111 112 113 114 115 116 117 118
    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
119
bool QwtPlotSpectrogram::testDisplayMode( DisplayMode mode ) const
pixhawk's avatar
pixhawk committed
120
{
Bryant's avatar
Bryant committed
121
    return ( d_data->displayMode & mode );
pixhawk's avatar
pixhawk committed
122 123 124 125 126 127 128 129 130 131 132 133 134
}

/*!
  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
135
void QwtPlotSpectrogram::setColorMap( QwtColorMap *colorMap )
pixhawk's avatar
pixhawk committed
136
{
Bryant's avatar
Bryant committed
137 138 139 140 141
    if ( d_data->colorMap != colorMap )
    {
        delete d_data->colorMap;
        d_data->colorMap = colorMap;
    }
pixhawk's avatar
pixhawk committed
142 143

    invalidateCache();
Bryant's avatar
Bryant committed
144 145

    legendChanged();
pixhawk's avatar
pixhawk committed
146 147 148 149 150 151 152
    itemChanged();
}

/*!
   \return Color Map used for mapping the intensity values to colors
   \sa setColorMap()
*/
Bryant's avatar
Bryant committed
153
const QwtColorMap *QwtPlotSpectrogram::colorMap() const
pixhawk's avatar
pixhawk committed
154
{
Bryant's avatar
Bryant committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    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
175 176 177 178 179
}

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

180
   If the spectrogram has a valid default contour pen
pixhawk's avatar
pixhawk committed
181 182 183 184
   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
185
   \sa defaultContourPen(), contourPen()
pixhawk's avatar
pixhawk committed
186
*/
Bryant's avatar
Bryant committed
187
void QwtPlotSpectrogram::setDefaultContourPen( const QPen &pen )
pixhawk's avatar
pixhawk committed
188
{
Bryant's avatar
Bryant committed
189 190
    if ( pen != d_data->defaultContourPen )
    {
pixhawk's avatar
pixhawk committed
191
        d_data->defaultContourPen = pen;
Bryant's avatar
Bryant committed
192 193

        legendChanged();
pixhawk's avatar
pixhawk committed
194 195 196 197 198 199
        itemChanged();
    }
}

/*!
   \return Default contour pen
Bryant's avatar
Bryant committed
200
   \sa setDefaultContourPen()
pixhawk's avatar
pixhawk committed
201 202 203 204 205 206 207 208
*/
QPen QwtPlotSpectrogram::defaultContourPen() const
{
    return d_data->defaultContourPen;
}

/*!
   \brief Calculate the pen for a contour line
209

pixhawk's avatar
pixhawk committed
210
   The color of the pen is the color for level calculated by the color map
211

pixhawk's avatar
pixhawk committed
212 213 214 215
   \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
216
   \sa setDefaultContourPen(), setColorMap(), setContourLevels()
pixhawk's avatar
pixhawk committed
217
*/
Bryant's avatar
Bryant committed
218
QPen QwtPlotSpectrogram::contourPen( double level ) const
pixhawk's avatar
pixhawk committed
219
{
Bryant's avatar
Bryant committed
220 221 222 223 224
    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
225

Bryant's avatar
Bryant committed
226
    return QPen( c );
pixhawk's avatar
pixhawk committed
227 228 229 230 231 232
}

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

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

Bryant's avatar
Bryant committed
236 237
   \sa testConrecFlag(), renderContourLines(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
238
*/
Bryant's avatar
Bryant committed
239 240
void QwtPlotSpectrogram::setConrecFlag(
    QwtRasterData::ConrecFlag flag, bool on )
pixhawk's avatar
pixhawk committed
241
{
Bryant's avatar
Bryant committed
242
    if ( bool( d_data->conrecFlags & flag ) == on )
pixhawk's avatar
pixhawk committed
243 244 245
        return;

    if ( on )
Bryant's avatar
Bryant committed
246
        d_data->conrecFlags |= flag;
pixhawk's avatar
pixhawk committed
247
    else
Bryant's avatar
Bryant committed
248
        d_data->conrecFlags &= ~flag;
pixhawk's avatar
pixhawk committed
249 250 251 252 253 254 255 256

    itemChanged();
}

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

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

Bryant's avatar
Bryant committed
260 261 262 263
   The default setting enables QwtRasterData::IgnoreAllVerticesOnLevel

   \sa setConrecClag(), renderContourLines(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
264
*/
Bryant's avatar
Bryant committed
265 266
bool QwtPlotSpectrogram::testConrecFlag(
    QwtRasterData::ConrecFlag flag ) const
267
{
Bryant's avatar
Bryant committed
268
    return d_data->conrecFlags & flag;
pixhawk's avatar
pixhawk committed
269 270 271 272 273 274
}

/*!
   Set the levels of the contour lines

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

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

    legendChanged();
pixhawk's avatar
pixhawk committed
286 287 288 289
    itemChanged();
}

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

   The levels are sorted in increasing order.

Bryant's avatar
Bryant committed
294 295
   \sa contourLevels(), renderContourLines(),
       QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
296
*/
Bryant's avatar
Bryant committed
297
QList<double> QwtPlotSpectrogram::contourLevels() const
pixhawk's avatar
pixhawk committed
298 299 300 301 302 303 304 305 306 307
{
    return d_data->contourLevels;
}

/*!
  Set the data to be displayed

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

Bryant's avatar
Bryant committed
315 316 317 318 319 320 321 322 323 324 325 326
        invalidateCache();
        itemChanged();
    }
}

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

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

/*!
Bryant's avatar
Bryant committed
339 340 341 342 343 344 345
   \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
346
*/
Bryant's avatar
Bryant committed
347
QwtInterval QwtPlotSpectrogram::interval(Qt::Axis axis) const
pixhawk's avatar
pixhawk committed
348
{
Bryant's avatar
Bryant committed
349 350 351 352
    if ( d_data->data == NULL )
        return QwtInterval();

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

/*!
Bryant's avatar
Bryant committed
356 357 358 359
   \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
360

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

Bryant's avatar
Bryant committed
363 364 365 366 367 368 369
   \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
370
*/
Bryant's avatar
Bryant committed
371
QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const
pixhawk's avatar
pixhawk committed
372
{
Bryant's avatar
Bryant committed
373 374 375 376
    if ( d_data->data == NULL )
        return QRectF();

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

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

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

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

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

Bryant's avatar
Bryant committed
392
   \sa QwtRasterData::value(), QwtColorMap::rgb(),
pixhawk's avatar
pixhawk committed
393 394 395
       QwtColorMap::colorIndex()
*/
QImage QwtPlotSpectrogram::renderImage(
396
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
Bryant's avatar
Bryant committed
397
    const QRectF &area, const QSize &imageSize ) const
pixhawk's avatar
pixhawk committed
398
{
Bryant's avatar
Bryant committed
399 400 401
    if ( imageSize.isEmpty() || d_data->data == NULL 
        || d_data->colorMap == NULL )
    {
pixhawk's avatar
pixhawk committed
402 403 404
        return QImage();
    }

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

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

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

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

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

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

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

Bryant's avatar
Bryant committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
    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
444 445
        }
    }
Bryant's avatar
Bryant committed
446 447 448 449 450 451 452
    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
453 454 455

    d_data->data->discardRaster();

Bryant's avatar
Bryant committed
456 457
    return image;
}
pixhawk's avatar
pixhawk committed
458

Bryant's avatar
Bryant committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
/*!
    \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
495
    }
Bryant's avatar
Bryant committed
496 497 498 499 500
    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
501

Bryant's avatar
Bryant committed
502 503 504 505 506 507 508 509 510 511 512 513
            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
514 515 516 517 518
}

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

Bryant's avatar
Bryant committed
519
   A larger size will improve the precision of the CONREC algorithm,
pixhawk's avatar
pixhawk committed
520 521 522
   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
523
   the resolution depending on pixelSize().
pixhawk's avatar
pixhawk committed
524

Bryant's avatar
Bryant committed
525 526
   \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
527 528 529
   \return Raster to be used by the CONREC contour algorithm.

   \note The size will be bounded to rect.size().
530

Bryant's avatar
Bryant committed
531
   \sa drawContourLines(), QwtRasterData::contourLines()
pixhawk's avatar
pixhawk committed
532
*/
Bryant's avatar
Bryant committed
533 534
QSize QwtPlotSpectrogram::contourRasterSize( 
    const QRectF &area, const QRect &rect ) const
pixhawk's avatar
pixhawk committed
535 536 537
{
    QSize raster = rect.size() / 2;

Bryant's avatar
Bryant committed
538 539 540 541 542 543 544
    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
545 546 547 548 549 550 551 552 553

    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
554
   \return Calculated contour lines
pixhawk's avatar
pixhawk committed
555

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

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

pixhawk's avatar
pixhawk committed
569 570 571 572 573 574 575 576
/*!
   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
577
   \sa renderContourLines(), defaultContourPen(), contourPen()
pixhawk's avatar
pixhawk committed
578
*/
Bryant's avatar
Bryant committed
579
void QwtPlotSpectrogram::drawContourLines( QPainter *painter,
pixhawk's avatar
pixhawk committed
580
        const QwtScaleMap &xMap, const QwtScaleMap &yMap,
Bryant's avatar
Bryant committed
581
        const QwtRasterData::ContourLines &contourLines ) const
pixhawk's avatar
pixhawk committed
582
{
Bryant's avatar
Bryant committed
583 584
    if ( d_data->data == NULL )
        return;
pixhawk's avatar
pixhawk committed
585

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

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

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

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

        const QPolygonF &lines = contourLines[level];
Bryant's avatar
Bryant committed
601 602 603 604 605 606 607 608
        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
609 610 611 612 613 614 615 616 617 618
        }
    }
}

/*!
  \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
619
  \param canvasRect Contents rectangle of the canvas in painter coordinates
pixhawk's avatar
pixhawk committed
620

Bryant's avatar
Bryant committed
621 622
  \sa setDisplayMode(), renderImage(),
      QwtPlotRasterItem::draw(), drawContourLines()
pixhawk's avatar
pixhawk committed
623
*/
Bryant's avatar
Bryant committed
624 625 626
void QwtPlotSpectrogram::draw( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect ) const
pixhawk's avatar
pixhawk committed
627 628
{
    if ( d_data->displayMode & ImageMode )
Bryant's avatar
Bryant committed
629
        QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect );
pixhawk's avatar
pixhawk committed
630

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

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

Bryant's avatar
Bryant committed
640 641 642
        const QRectF br = boundingRect();
        if ( br.isValid() )
        {
pixhawk's avatar
pixhawk committed
643 644 645 646
            area &= br;
            if ( area.isEmpty() )
                return;

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

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

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