qwt_plot_spectrogram.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_plot_spectrogram.h"
00011 #include "qwt_painter.h"
00012 #include "qwt_interval.h"
00013 #include "qwt_scale_map.h"
00014 #include "qwt_color_map.h"
00015 #include <qimage.h>
00016 #include <qpen.h>
00017 #include <qpainter.h>
00018 #include <qmath.h>
00019 #include <qalgorithms.h>
00020 #include <qthread.h>
00021 #include <qfuture.h>
00022 #include <qtconcurrentrun.h>
00023 
00024 #define DEBUG_RENDER 0
00025 
00026 #if DEBUG_RENDER
00027 #include <QElapsedTimer>
00028 #endif
00029 
00030 static inline bool qwtIsNaN( double d )
00031 {   
00032     // qt_is_nan is private header and qIsNaN is not inlined
00033     // so we need these code here too
00034     
00035     const uchar *ch = (const uchar *)&d;
00036     if ( QSysInfo::ByteOrder == QSysInfo::BigEndian )
00037     {   
00038         return (ch[0] & 0x7f) == 0x7f && ch[1] > 0xf0;
00039     } 
00040     else
00041     {   
00042         return (ch[7] & 0x7f) == 0x7f && ch[6] > 0xf0;
00043     }
00044 }
00045 
00046 class QwtPlotSpectrogram::PrivateData
00047 {
00048 public:
00049     PrivateData():
00050         data( NULL ),
00051         maxRGBColorTableSize( 0 )
00052     {
00053         colorMap = new QwtLinearColorMap();
00054         displayMode = ImageMode;
00055 
00056         conrecFlags = QwtRasterData::IgnoreAllVerticesOnLevel;
00057 #if 0
00058         conrecFlags |= QwtRasterData::IgnoreOutOfRange;
00059 #endif
00060     }
00061     ~PrivateData()
00062     {
00063         delete data;
00064         delete colorMap;
00065     }
00066 
00067     void updateColorTable()
00068     {
00069         if ( colorMap->format() == QwtColorMap::Indexed )
00070         {
00071             colorTable = colorMap->colorTable256();
00072         }
00073         else
00074         {
00075             if ( maxRGBColorTableSize == 0 )
00076                 colorTable.clear();
00077             else
00078                 colorTable = colorMap->colorTable( maxRGBColorTableSize );
00079         }
00080     }
00081 
00082     QwtRasterData *data;
00083     QwtColorMap *colorMap;
00084     DisplayModes displayMode;
00085 
00086     QList<double> contourLevels;
00087     QPen defaultContourPen;
00088     QwtRasterData::ConrecFlags conrecFlags;
00089 
00090     int maxRGBColorTableSize;
00091     QVector<QRgb> colorTable;
00092 };
00093 
00105 QwtPlotSpectrogram::QwtPlotSpectrogram( const QString &title ):
00106     QwtPlotRasterItem( title )
00107 {
00108     d_data = new PrivateData();
00109 
00110     setItemAttribute( QwtPlotItem::AutoScale, true );
00111     setItemAttribute( QwtPlotItem::Legend, false );
00112 
00113     setZ( 8.0 );
00114 }
00115 
00117 QwtPlotSpectrogram::~QwtPlotSpectrogram()
00118 {
00119     delete d_data;
00120 }
00121 
00123 int QwtPlotSpectrogram::rtti() const
00124 {
00125     return QwtPlotItem::Rtti_PlotSpectrogram;
00126 }
00127 
00138 void QwtPlotSpectrogram::setDisplayMode( DisplayMode mode, bool on )
00139 {
00140     if ( on != bool( mode & d_data->displayMode ) )
00141     {
00142         if ( on )
00143             d_data->displayMode |= mode;
00144         else
00145             d_data->displayMode &= ~mode;
00146     }
00147 
00148     legendChanged();
00149     itemChanged();
00150 }
00151 
00158 bool QwtPlotSpectrogram::testDisplayMode( DisplayMode mode ) const
00159 {
00160     return ( d_data->displayMode & mode );
00161 }
00162 
00174 void QwtPlotSpectrogram::setColorMap( QwtColorMap *colorMap )
00175 {
00176     if ( colorMap == NULL )
00177         return;
00178 
00179     if ( colorMap != d_data->colorMap )
00180     {
00181         delete d_data->colorMap;
00182         d_data->colorMap = colorMap;
00183     }
00184 
00185     d_data->updateColorTable();
00186 
00187     invalidateCache();
00188 
00189     legendChanged();
00190     itemChanged();
00191 }
00192 
00197 const QwtColorMap *QwtPlotSpectrogram::colorMap() const
00198 {
00199     return d_data->colorMap;
00200 }
00201 
00202 void QwtPlotSpectrogram::setMaxRGBTableSize( int numColors )
00203 {
00204     numColors = qMax( numColors, 0 );
00205     if ( numColors != d_data->maxRGBColorTableSize )
00206     {
00207         d_data->maxRGBColorTableSize = numColors;
00208         d_data->updateColorTable();
00209         invalidateCache();
00210     }
00211 }
00212 
00213 int QwtPlotSpectrogram::maxRGBTableSize() const
00214 {
00215     return d_data->maxRGBColorTableSize;
00216 }
00217 
00231 void QwtPlotSpectrogram::setDefaultContourPen( 
00232     const QColor &color, qreal width, Qt::PenStyle style )
00233 {   
00234     setDefaultContourPen( QPen( color, width, style ) );
00235 }
00236 
00247 void QwtPlotSpectrogram::setDefaultContourPen( const QPen &pen )
00248 {
00249     if ( pen != d_data->defaultContourPen )
00250     {
00251         d_data->defaultContourPen = pen;
00252 
00253         legendChanged();
00254         itemChanged();
00255     }
00256 }
00257 
00262 QPen QwtPlotSpectrogram::defaultContourPen() const
00263 {
00264     return d_data->defaultContourPen;
00265 }
00266 
00278 QPen QwtPlotSpectrogram::contourPen( double level ) const
00279 {
00280     if ( d_data->data == NULL || d_data->colorMap == NULL )
00281         return QPen();
00282 
00283     const QwtInterval intensityRange = d_data->data->interval(Qt::ZAxis);
00284     const QColor c( d_data->colorMap->rgb( intensityRange, level ) );
00285 
00286     return QPen( c );
00287 }
00288 
00299 void QwtPlotSpectrogram::setConrecFlag(
00300     QwtRasterData::ConrecFlag flag, bool on )
00301 {
00302     if ( bool( d_data->conrecFlags & flag ) == on )
00303         return;
00304 
00305     if ( on )
00306         d_data->conrecFlags |= flag;
00307     else
00308         d_data->conrecFlags &= ~flag;
00309 
00310     itemChanged();
00311 }
00312 
00325 bool QwtPlotSpectrogram::testConrecFlag(
00326     QwtRasterData::ConrecFlag flag ) const
00327 {
00328     return d_data->conrecFlags & flag;
00329 }
00330 
00340 void QwtPlotSpectrogram::setContourLevels( const QList<double> &levels )
00341 {
00342     d_data->contourLevels = levels;
00343     qSort( d_data->contourLevels );
00344 
00345     legendChanged();
00346     itemChanged();
00347 }
00348 
00357 QList<double> QwtPlotSpectrogram::contourLevels() const
00358 {
00359     return d_data->contourLevels;
00360 }
00361 
00368 void QwtPlotSpectrogram::setData( QwtRasterData *data )
00369 {
00370     if ( data != d_data->data )
00371     {
00372         delete d_data->data;
00373         d_data->data = data;
00374 
00375         invalidateCache();
00376         itemChanged();
00377     }
00378 }
00379 
00384 const QwtRasterData *QwtPlotSpectrogram::data() const
00385 {
00386     return d_data->data;
00387 }
00388 
00393 QwtRasterData *QwtPlotSpectrogram::data()
00394 {
00395     return d_data->data;
00396 }
00397 
00407 QwtInterval QwtPlotSpectrogram::interval(Qt::Axis axis) const
00408 {
00409     if ( d_data->data == NULL )
00410         return QwtInterval();
00411 
00412     return d_data->data->interval( axis );
00413 }
00414 
00431 QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const
00432 {
00433     if ( d_data->data == NULL )
00434         return QRectF();
00435 
00436     return d_data->data->pixelHint( area );
00437 }
00438 
00455 QImage QwtPlotSpectrogram::renderImage(
00456     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00457     const QRectF &area, const QSize &imageSize ) const
00458 {
00459     if ( imageSize.isEmpty() || d_data->data == NULL 
00460         || d_data->colorMap == NULL )
00461     {
00462         return QImage();
00463     }
00464 
00465     const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis );
00466     if ( !intensityRange.isValid() )
00467         return QImage();
00468 
00469     const QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB )
00470         ? QImage::Format_ARGB32 : QImage::Format_Indexed8;
00471 
00472     QImage image( imageSize, format );
00473 
00474     if ( d_data->colorMap->format() == QwtColorMap::Indexed )
00475         image.setColorTable( d_data->colorMap->colorTable256() );
00476 
00477     d_data->data->initRaster( area, image.size() );
00478 
00479 #if DEBUG_RENDER
00480     QElapsedTimer time;
00481     time.start();
00482 #endif
00483 
00484 #if !defined(QT_NO_QFUTURE)
00485     uint numThreads = renderThreadCount();
00486 
00487     if ( numThreads <= 0 )
00488         numThreads = QThread::idealThreadCount();
00489 
00490     if ( numThreads <= 0 )
00491         numThreads = 1;
00492 
00493     const int numRows = imageSize.height() / numThreads;
00494 
00495     QList< QFuture<void> > futures;
00496     for ( uint i = 0; i < numThreads; i++ )
00497     {
00498         QRect tile( 0, i * numRows, image.width(), numRows );
00499         if ( i == numThreads - 1 )
00500         {
00501             tile.setHeight( image.height() - i * numRows );
00502             renderTile( xMap, yMap, tile, &image );
00503         }
00504         else
00505         {
00506             futures += QtConcurrent::run(
00507                 this, &QwtPlotSpectrogram::renderTile,
00508                 xMap, yMap, tile, &image );
00509         }
00510     }
00511     for ( int i = 0; i < futures.size(); i++ )
00512         futures[i].waitForFinished();
00513 
00514 #else 
00515     const QRect tile( 0, 0, image.width(), image.height() );
00516     renderTile( xMap, yMap, tile, &image );
00517 #endif
00518 
00519 #if DEBUG_RENDER
00520     const qint64 elapsed = time.elapsed();
00521     qDebug() << "renderImage" << imageSize << elapsed;
00522 #endif
00523 
00524     d_data->data->discardRaster();
00525 
00526     return image;
00527 }
00528 
00540 void QwtPlotSpectrogram::renderTile(
00541     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00542     const QRect &tile, QImage *image ) const
00543 {
00544     const QwtInterval range = d_data->data->interval( Qt::ZAxis );
00545     if ( range.width() <= 0.0 )
00546         return;
00547 
00548     const bool hasGaps = !d_data->data->testAttribute( QwtRasterData::WithoutGaps );
00549 
00550     if ( d_data->colorMap->format() == QwtColorMap::RGB )
00551     {
00552         const int numColors = d_data->colorTable.size();
00553         const QRgb *rgbTable = d_data->colorTable.constData();
00554         const QwtColorMap *colorMap = d_data->colorMap;
00555 
00556         for ( int y = tile.top(); y <= tile.bottom(); y++ )
00557         {
00558             const double ty = yMap.invTransform( y );
00559 
00560             QRgb *line = reinterpret_cast<QRgb *>( image->scanLine( y ) );
00561             line += tile.left();
00562 
00563             for ( int x = tile.left(); x <= tile.right(); x++ )
00564             {
00565                 const double tx = xMap.invTransform( x );
00566 
00567                 const double value = d_data->data->value( tx, ty );
00568 
00569                 if ( hasGaps && qwtIsNaN( value ) )
00570                 {
00571                     *line++ = 0u;
00572                 }
00573                 else if ( numColors == 0 )
00574                 {
00575                     *line++ = colorMap->rgb( range, value );
00576                 }
00577                 else
00578                 {
00579                     const uint index = colorMap->colorIndex( numColors, range, value );
00580                     *line++ = rgbTable[index];
00581                 }
00582             }
00583         }
00584     }
00585     else if ( d_data->colorMap->format() == QwtColorMap::Indexed )
00586     {
00587         for ( int y = tile.top(); y <= tile.bottom(); y++ )
00588         {
00589             const double ty = yMap.invTransform( y );
00590 
00591             unsigned char *line = image->scanLine( y );
00592             line += tile.left();
00593 
00594             for ( int x = tile.left(); x <= tile.right(); x++ )
00595             {
00596                 const double tx = xMap.invTransform( x );
00597 
00598                 const double value = d_data->data->value( tx, ty );
00599 
00600                 if ( hasGaps && qwtIsNaN( value ) )
00601                 {
00602                     *line++ = 0;
00603                 }
00604                 else
00605                 {
00606                     const uint index = d_data->colorMap->colorIndex( 256, range, value );
00607                     *line++ = static_cast<unsigned char>( index );
00608                 }
00609             }
00610         }
00611     }
00612 }
00613 
00631 QSize QwtPlotSpectrogram::contourRasterSize( 
00632     const QRectF &area, const QRect &rect ) const
00633 {
00634     QSize raster = rect.size() / 2;
00635 
00636     const QRectF pixelRect = pixelHint( area );
00637     if ( !pixelRect.isEmpty() )
00638     {
00639         const QSize res( qCeil( rect.width() / pixelRect.width() ),
00640             qCeil( rect.height() / pixelRect.height() ) );
00641         raster = raster.boundedTo( res );
00642     }
00643 
00644     return raster;
00645 }
00646 
00657 QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines(
00658     const QRectF &rect, const QSize &raster ) const
00659 {
00660     if ( d_data->data == NULL )
00661         return QwtRasterData::ContourLines();
00662 
00663     return d_data->data->contourLines( rect, raster,
00664         d_data->contourLevels, d_data->conrecFlags );
00665 }
00666 
00677 void QwtPlotSpectrogram::drawContourLines( QPainter *painter,
00678         const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00679         const QwtRasterData::ContourLines &contourLines ) const
00680 {
00681     if ( d_data->data == NULL )
00682         return;
00683 
00684     const int numLevels = d_data->contourLevels.size();
00685     for ( int l = 0; l < numLevels; l++ )
00686     {
00687         const double level = d_data->contourLevels[l];
00688 
00689         QPen pen = defaultContourPen();
00690         if ( pen.style() == Qt::NoPen )
00691             pen = contourPen( level );
00692 
00693         if ( pen.style() == Qt::NoPen )
00694             continue;
00695 
00696         painter->setPen( pen );
00697 
00698         const QPolygonF &lines = contourLines[level];
00699         for ( int i = 0; i < lines.size(); i += 2 )
00700         {
00701             const QPointF p1( xMap.transform( lines[i].x() ),
00702                 yMap.transform( lines[i].y() ) );
00703             const QPointF p2( xMap.transform( lines[i+1].x() ),
00704                 yMap.transform( lines[i+1].y() ) );
00705 
00706             QwtPainter::drawLine( painter, p1, p2 );
00707         }
00708     }
00709 }
00710 
00722 void QwtPlotSpectrogram::draw( QPainter *painter,
00723     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00724     const QRectF &canvasRect ) const
00725 {
00726     if ( d_data->displayMode & ImageMode )
00727         QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect );
00728 
00729     if ( d_data->displayMode & ContourMode )
00730     {
00731         // Add some pixels at the borders
00732         const int margin = 2;
00733         QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin,
00734             canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin );
00735 
00736         QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect );
00737 
00738         const QRectF br = boundingRect();
00739         if ( br.isValid() )
00740         {
00741             area &= br;
00742             if ( area.isEmpty() )
00743                 return;
00744 
00745             rasterRect = QwtScaleMap::transform( xMap, yMap, area );
00746         }
00747 
00748         QSize raster = contourRasterSize( area, rasterRect.toRect() );
00749         raster = raster.boundedTo( rasterRect.toRect().size() );
00750         if ( raster.isValid() )
00751         {
00752             const QwtRasterData::ContourLines lines =
00753                 renderContourLines( area, raster );
00754 
00755             drawContourLines( painter, xMap, yMap, lines );
00756         }
00757     }
00758 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56