Loading...
Searching...
No Matches
qwt_plot_spectrogram.cpp
/******************************************************************************
* 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 "qwt_plot_spectrogram.h"
#include "qwt_painter.h"
#include "qwt_interval.h"
#include "qwt_scale_map.h"
#include "qwt_color_map.h"
#include "qwt_math.h"
#include <qimage.h>
#include <qpen.h>
#include <qpainter.h>
#include <qthread.h>
#include <qfuture.h>
#include <qtconcurrentrun.h>
#define DEBUG_RENDER 0
#if DEBUG_RENDER
#include <qelapsedtimer.h>
#endif
#include <algorithm>
static inline bool qwtIsNaN( double d )
{
// qt_is_nan is private header and qIsNaN is not inlined
// so we need these code here too
const uchar* ch = (const uchar*)&d;
if ( QSysInfo::ByteOrder == QSysInfo::BigEndian )
{
return ( ch[0] & 0x7f ) == 0x7f && ch[1] > 0xf0;
}
else
{
return ( ch[7] & 0x7f ) == 0x7f && ch[6] > 0xf0;
}
}
class QwtPlotSpectrogram::PrivateData
{
public:
PrivateData()
: data( NULL )
, colorTableSize( 0 )
{
colorMap = new QwtLinearColorMap();
displayMode = ImageMode;
conrecFlags = QwtRasterData::IgnoreAllVerticesOnLevel;
#if 0
conrecFlags |= QwtRasterData::IgnoreOutOfRange;
#endif
}
~PrivateData()
{
delete data;
delete colorMap;
}
void updateColorTable()
{
if ( colorMap->format() == QwtColorMap::Indexed )
{
colorTable = colorMap->colorTable256();
}
else
{
if ( colorTableSize == 0 )
colorTable.clear();
else
colorTable = colorMap->colorTable( colorTableSize );
}
}
QwtRasterData* data;
QwtColorMap* colorMap;
DisplayModes displayMode;
QList< double > contourLevels;
QPen defaultContourPen;
QwtRasterData::ConrecFlags conrecFlags;
int colorTableSize;
QVector< QRgb > colorTable;
};
QwtPlotSpectrogram::QwtPlotSpectrogram( const QString& title )
: QwtPlotRasterItem( title )
{
m_data = new PrivateData();
setItemAttribute( QwtPlotItem::AutoScale, true );
setItemAttribute( QwtPlotItem::Legend, false );
setZ( 8.0 );
}
QwtPlotSpectrogram::~QwtPlotSpectrogram()
{
delete m_data;
}
int QwtPlotSpectrogram::rtti() const
{
return QwtPlotItem::Rtti_PlotSpectrogram;
}
void QwtPlotSpectrogram::setDisplayMode( DisplayMode mode, bool on )
{
if ( on != bool( mode & m_data->displayMode ) )
{
if ( on )
m_data->displayMode |= mode;
else
m_data->displayMode &= ~mode;
}
legendChanged();
itemChanged();
}
bool QwtPlotSpectrogram::testDisplayMode( DisplayMode mode ) const
{
return ( m_data->displayMode & mode );
}
void QwtPlotSpectrogram::setColorMap( QwtColorMap* colorMap )
{
if ( colorMap == NULL )
return;
if ( colorMap != m_data->colorMap )
{
delete m_data->colorMap;
m_data->colorMap = colorMap;
}
m_data->updateColorTable();
invalidateCache();
legendChanged();
itemChanged();
}
const QwtColorMap* QwtPlotSpectrogram::colorMap() const
{
return m_data->colorMap;
}
void QwtPlotSpectrogram::setColorTableSize( int numColors )
{
numColors = qMax( numColors, 0 );
if ( numColors != m_data->colorTableSize )
{
m_data->colorTableSize = numColors;
m_data->updateColorTable();
invalidateCache();
}
}
int QwtPlotSpectrogram::colorTableSize() const
{
return m_data->colorTableSize;
}
void QwtPlotSpectrogram::setDefaultContourPen(
const QColor& color, qreal width, Qt::PenStyle style )
{
setDefaultContourPen( QPen( color, width, style ) );
}
void QwtPlotSpectrogram::setDefaultContourPen( const QPen& pen )
{
if ( pen != m_data->defaultContourPen )
{
m_data->defaultContourPen = pen;
legendChanged();
itemChanged();
}
}
QPen QwtPlotSpectrogram::defaultContourPen() const
{
return m_data->defaultContourPen;
}
QPen QwtPlotSpectrogram::contourPen( double level ) const
{
if ( m_data->data == NULL || m_data->colorMap == NULL )
return QPen();
const QwtInterval intensityRange = m_data->data->interval(Qt::ZAxis);
const QColor c( m_data->colorMap->rgb( intensityRange, level ) );
return QPen( c );
}
void QwtPlotSpectrogram::setConrecFlag(
QwtRasterData::ConrecFlag flag, bool on )
{
if ( bool( m_data->conrecFlags & flag ) == on )
return;
if ( on )
m_data->conrecFlags |= flag;
else
m_data->conrecFlags &= ~flag;
itemChanged();
}
bool QwtPlotSpectrogram::testConrecFlag(
QwtRasterData::ConrecFlag flag ) const
{
return m_data->conrecFlags & flag;
}
void QwtPlotSpectrogram::setContourLevels( const QList< double >& levels )
{
m_data->contourLevels = levels;
std::sort( m_data->contourLevels.begin(), m_data->contourLevels.end() );
legendChanged();
itemChanged();
}
QList< double > QwtPlotSpectrogram::contourLevels() const
{
return m_data->contourLevels;
}
void QwtPlotSpectrogram::setData( QwtRasterData* data )
{
if ( data != m_data->data )
{
delete m_data->data;
m_data->data = data;
invalidateCache();
itemChanged();
}
}
const QwtRasterData* QwtPlotSpectrogram::data() const
{
return m_data->data;
}
QwtRasterData* QwtPlotSpectrogram::data()
{
return m_data->data;
}
QwtInterval QwtPlotSpectrogram::interval(Qt::Axis axis) const
{
if ( m_data->data == NULL )
return QwtInterval();
return m_data->data->interval( axis );
}
QRectF QwtPlotSpectrogram::pixelHint( const QRectF& area ) const
{
if ( m_data->data == NULL )
return QRectF();
return m_data->data->pixelHint( area );
}
QImage QwtPlotSpectrogram::renderImage(
const QwtScaleMap& xMap, const QwtScaleMap& yMap,
const QRectF& area, const QSize& imageSize ) const
{
if ( imageSize.isEmpty() || m_data->data == NULL
|| m_data->colorMap == NULL )
{
return QImage();
}
const QwtInterval intensityRange = m_data->data->interval( Qt::ZAxis );
if ( !intensityRange.isValid() )
return QImage();
const QImage::Format format = ( m_data->colorMap->format() == QwtColorMap::RGB )
? QImage::Format_ARGB32 : QImage::Format_Indexed8;
QImage image( imageSize, format );
if ( m_data->colorMap->format() == QwtColorMap::Indexed )
image.setColorTable( m_data->colorMap->colorTable256() );
m_data->data->initRaster( area, image.size() );
#if DEBUG_RENDER
QElapsedTimer time;
time.start();
#endif
#if !defined( QT_NO_QFUTURE )
uint numThreads = renderThreadCount();
if ( numThreads <= 0 )
numThreads = QThread::idealThreadCount();
if ( numThreads <= 0 )
numThreads = 1;
const int numRows = imageSize.height() / numThreads;
QVector< QFuture< void > > futures;
futures.reserve( numThreads - 1 );
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(
#if QT_VERSION >= 0x060000
&QwtPlotSpectrogram::renderTile, this,
#else
this, &QwtPlotSpectrogram::renderTile,
#endif
xMap, yMap, tile, &image );
}
}
for ( int i = 0; i < futures.size(); i++ )
futures[i].waitForFinished();
#else
const QRect tile( 0, 0, image.width(), image.height() );
renderTile( xMap, yMap, tile, &image );
#endif
#if DEBUG_RENDER
const qint64 elapsed = time.elapsed();
qDebug() << "renderImage" << imageSize << elapsed;
#endif
m_data->data->discardRaster();
return image;
}
void QwtPlotSpectrogram::renderTile(
const QwtScaleMap& xMap, const QwtScaleMap& yMap,
const QRect& tile, QImage* image ) const
{
const QwtInterval range = m_data->data->interval( Qt::ZAxis );
if ( range.width() <= 0.0 )
return;
const bool hasGaps = !m_data->data->testAttribute( QwtRasterData::WithoutGaps );
if ( m_data->colorMap->format() == QwtColorMap::RGB )
{
const int numColors = m_data->colorTable.size();
const QRgb* rgbTable = m_data->colorTable.constData();
const QwtColorMap* colorMap = m_data->colorMap;
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 );
const double value = m_data->data->value( tx, ty );
if ( hasGaps && qwtIsNaN( value ) )
{
*line++ = 0u;
}
else if ( numColors == 0 )
{
*line++ = colorMap->rgb( range, value );
}
else
{
const uint index = colorMap->colorIndex( numColors, range, value );
*line++ = rgbTable[index];
}
}
}
}
else if ( m_data->colorMap->format() == QwtColorMap::Indexed )
{
for ( int y = tile.top(); y <= tile.bottom(); y++ )
{
const double ty = yMap.invTransform( y );
unsigned char* line = image->scanLine( y );
line += tile.left();
for ( int x = tile.left(); x <= tile.right(); x++ )
{
const double tx = xMap.invTransform( x );
const double value = m_data->data->value( tx, ty );
if ( hasGaps && qwtIsNaN( value ) )
{
*line++ = 0;
}
else
{
const uint index = m_data->colorMap->colorIndex( 256, range, value );
*line++ = static_cast< unsigned char >( index );
}
}
}
}
}
QSize QwtPlotSpectrogram::contourRasterSize(
const QRectF& area, const QRect& rect ) const
{
QSize raster = rect.size() / 2;
const QRectF pixelRect = pixelHint( area );
if ( !pixelRect.isEmpty() )
{
const QSize res( qwtCeil( rect.width() / pixelRect.width() ),
qwtCeil( rect.height() / pixelRect.height() ) );
raster = raster.boundedTo( res );
}
return raster;
}
QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines(
const QRectF& rect, const QSize& raster ) const
{
if ( m_data->data == NULL )
return QwtRasterData::ContourLines();
return m_data->data->contourLines( rect, raster,
m_data->contourLevels, m_data->conrecFlags );
}
void QwtPlotSpectrogram::drawContourLines( QPainter* painter,
const QwtScaleMap& xMap, const QwtScaleMap& yMap,
const QwtRasterData::ContourLines& contourLines ) const
{
if ( m_data->data == NULL )
return;
const int numLevels = m_data->contourLevels.size();
for ( int l = 0; l < numLevels; l++ )
{
const double level = m_data->contourLevels[l];
QPen pen = defaultContourPen();
if ( pen.style() == Qt::NoPen )
pen = contourPen( level );
if ( pen.style() == Qt::NoPen )
continue;
painter->setPen( pen );
const QPolygonF& lines = contourLines[level];
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 );
}
}
}
void QwtPlotSpectrogram::draw( QPainter* painter,
const QwtScaleMap& xMap, const QwtScaleMap& yMap,
const QRectF& canvasRect ) const
{
if ( m_data->displayMode & ImageMode )
QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect );
if ( m_data->displayMode & ContourMode )
{
// Add some pixels at the borders
const int margin = 2;
QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin,
canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin );
QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect );
const QRectF br = boundingRect();
if ( br.isValid() )
{
area &= br;
if ( area.isEmpty() )
return;
rasterRect = QwtScaleMap::transform( xMap, yMap, area );
}
QSize raster = contourRasterSize( area, rasterRect.toRect() );
raster = raster.boundedTo( rasterRect.toRect().size() );
if ( raster.isValid() )
{
const QwtRasterData::ContourLines lines =
renderContourLines( area, raster );
drawContourLines( painter, xMap, yMap, lines );
}
}
}
QList< double >
QMap
Definition qwt_compass.h:19
QVector< QRgb >
QwtColorMap
QwtColorMap is used to map values into colors.
Definition qwt_color_map.h:38
QwtColorMap::colorIndex
virtual uint colorIndex(int numColors, const QwtInterval &interval, double value) const
Map a value of a given interval into a color index.
Definition qwt_color_map.cpp:278
QwtColorMap::Indexed
@ Indexed
Definition qwt_color_map.h:60
QwtColorMap::RGB
@ RGB
The map is intended to map into RGB values.
Definition qwt_color_map.h:48
QwtColorMap::colorTable
virtual QVector< QRgb > colorTable(int numColors) const
Definition qwt_color_map.cpp:325
QwtColorMap::colorTable256
virtual QVector< QRgb > colorTable256() const
Definition qwt_color_map.cpp:304
QwtColorMap::rgb
virtual QRgb rgb(const QwtInterval &interval, double value) const =0
QwtInterval
A class representing an interval.
Definition qwt_interval.h:23
QwtInterval::width
double width() const
Return the width of an interval.
Definition qwt_interval.h:227
QwtInterval::isValid
bool isValid() const
Definition qwt_interval.h:210
QwtLinearColorMap
QwtLinearColorMap builds a color map from color stops.
Definition qwt_color_map.h:99
QwtPainter::drawLine
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
Definition qwt_painter.h:154
QwtPlotItem::legendChanged
virtual void legendChanged()
Definition qwt_plot_item.cpp:491
QwtPlotItem::setZ
void setZ(double z)
Set the z value.
Definition qwt_plot_item.cpp:165
QwtPlotItem::setItemAttribute
void setItemAttribute(ItemAttribute, bool on=true)
Definition qwt_plot_item.cpp:228
QwtPlotItem::Rtti_PlotSpectrogram
@ Rtti_PlotSpectrogram
For QwtPlotSpectrogram.
Definition qwt_plot_item.h:105
QwtPlotItem::itemChanged
virtual void itemChanged()
Definition qwt_plot_item.cpp:481
QwtPlotItem::Legend
@ Legend
The item is represented on the legend.
Definition qwt_plot_item.h:150
QwtPlotItem::AutoScale
@ AutoScale
Definition qwt_plot_item.h:157
QwtPlotItem::renderThreadCount
uint renderThreadCount() const
Definition qwt_plot_item.cpp:360
QwtPlotRasterItem
A class, which displays raster data.
Definition qwt_plot_rasteritem.h:38
QwtPlotRasterItem::draw
virtual void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const override
Draw the raster data.
Definition qwt_plot_rasteritem.cpp:614
QwtPlotRasterItem::boundingRect
virtual QRectF boundingRect() const override
Definition qwt_plot_rasteritem.cpp:800
QwtPlotRasterItem::invalidateCache
void invalidateCache()
Definition qwt_plot_rasteritem.cpp:568
QwtPlotSpectrogram::setColorTableSize
void setColorTableSize(int numColors)
Definition qwt_plot_spectrogram.cpp:224
QwtPlotSpectrogram::contourPen
virtual QPen contourPen(double level) const
Calculate the pen for a contour line.
Definition qwt_plot_spectrogram.cpp:303
QwtPlotSpectrogram::DisplayModes
QFlags< DisplayMode > DisplayModes
Definition qwt_plot_spectrogram.h:53
QwtPlotSpectrogram::contourRasterSize
virtual QSize contourRasterSize(const QRectF &, const QRect &) const
Return the raster to be used by the CONREC contour algorithm.
Definition qwt_plot_spectrogram.cpp:663
QwtPlotSpectrogram::renderContourLines
virtual QwtRasterData::ContourLines renderContourLines(const QRectF &rect, const QSize &raster) const
Definition qwt_plot_spectrogram.cpp:689
QwtPlotSpectrogram::contourLevels
QList< double > contourLevels() const
Definition qwt_plot_spectrogram.cpp:382
QwtPlotSpectrogram::pixelHint
virtual QRectF pixelHint(const QRectF &) const override
Pixel hint.
Definition qwt_plot_spectrogram.cpp:456
QwtPlotSpectrogram::setDisplayMode
void setDisplayMode(DisplayMode, bool on=true)
Definition qwt_plot_spectrogram.cpp:141
QwtPlotSpectrogram::interval
virtual QwtInterval interval(Qt::Axis) const override
Definition qwt_plot_spectrogram.cpp:432
QwtPlotSpectrogram::setColorMap
void setColorMap(QwtColorMap *)
Definition qwt_plot_spectrogram.cpp:177
QwtPlotSpectrogram::setContourLevels
void setContourLevels(const QList< double > &)
Definition qwt_plot_spectrogram.cpp:365
QwtPlotSpectrogram::setData
void setData(QwtRasterData *data)
Definition qwt_plot_spectrogram.cpp:393
QwtPlotSpectrogram::testConrecFlag
bool testConrecFlag(QwtRasterData::ConrecFlag) const
Definition qwt_plot_spectrogram.cpp:350
QwtPlotSpectrogram::drawContourLines
virtual void drawContourLines(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtRasterData::ContourLines &) const
Definition qwt_plot_spectrogram.cpp:709
QwtPlotSpectrogram::renderTile
void renderTile(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &tile, QImage *) const
Render a tile of an image.
Definition qwt_plot_spectrogram.cpp:572
QwtPlotSpectrogram::DisplayMode
DisplayMode
Definition qwt_plot_spectrogram.h:45
QwtPlotSpectrogram::ContourMode
@ ContourMode
The data is displayed using contour lines.
Definition qwt_plot_spectrogram.h:50
QwtPlotSpectrogram::ImageMode
@ ImageMode
The values are mapped to colors using a color map.
Definition qwt_plot_spectrogram.h:47
QwtPlotSpectrogram::colorTableSize
int colorTableSize() const
Definition qwt_plot_spectrogram.cpp:238
QwtPlotSpectrogram::QwtPlotSpectrogram
QwtPlotSpectrogram(const QString &title=QString())
Definition qwt_plot_spectrogram.cpp:108
QwtPlotSpectrogram::data
const QwtRasterData * data() const
Definition qwt_plot_spectrogram.cpp:409
QwtPlotSpectrogram::colorMap
const QwtColorMap * colorMap() const
Definition qwt_plot_spectrogram.cpp:200
QwtPlotSpectrogram::testDisplayMode
bool testDisplayMode(DisplayMode) const
Definition qwt_plot_spectrogram.cpp:161
QwtPlotSpectrogram::draw
virtual void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const override
Draw the spectrogram.
Definition qwt_plot_spectrogram.cpp:754
QwtPlotSpectrogram::setConrecFlag
void setConrecFlag(QwtRasterData::ConrecFlag, bool on)
Definition qwt_plot_spectrogram.cpp:324
QwtPlotSpectrogram::rtti
virtual int rtti() const override
Definition qwt_plot_spectrogram.cpp:126
QwtPlotSpectrogram::~QwtPlotSpectrogram
virtual ~QwtPlotSpectrogram()
Destructor.
Definition qwt_plot_spectrogram.cpp:120
QwtPlotSpectrogram::setDefaultContourPen
void setDefaultContourPen(const QColor &, qreal width=0.0, Qt::PenStyle=Qt::SolidLine)
Definition qwt_plot_spectrogram.cpp:256
QwtPlotSpectrogram::renderImage
virtual QImage renderImage(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize) const override
Render an image from data and color map.
Definition qwt_plot_spectrogram.cpp:480
QwtPlotSpectrogram::defaultContourPen
QPen defaultContourPen() const
Definition qwt_plot_spectrogram.cpp:287
QwtRasterData
QwtRasterData defines an interface to any type of raster data.
Definition qwt_raster_data.h:43
QwtRasterData::pixelHint
virtual QRectF pixelHint(const QRectF &) const
Pixel hint.
Definition qwt_raster_data.cpp:267
QwtRasterData::testAttribute
bool testAttribute(Attribute) const
Definition qwt_raster_data.cpp:201
QwtRasterData::ContourLines
QMap< double, QPolygonF > ContourLines
Contour lines.
Definition qwt_raster_data.h:46
QwtRasterData::ConrecFlags
QFlags< ConrecFlag > ConrecFlags
Definition qwt_raster_data.h:86
QwtRasterData::discardRaster
virtual void discardRaster()
Discard a raster.
Definition qwt_raster_data.cpp:237
QwtRasterData::value
virtual double value(double x, double y) const =0
QwtRasterData::initRaster
virtual void initRaster(const QRectF &, const QSize &raster)
Initialize a raster.
Definition qwt_raster_data.cpp:221
QwtRasterData::contourLines
virtual ContourLines contourLines(const QRectF &rect, const QSize &raster, const QList< double > &levels, ConrecFlags) const
Definition qwt_raster_data.cpp:286
QwtRasterData::WithoutGaps
@ WithoutGaps
Definition qwt_raster_data.h:71
QwtRasterData::interval
virtual QwtInterval interval(Qt::Axis) const =0
QwtRasterData::ConrecFlag
ConrecFlag
Flags to modify the contour algorithm.
Definition qwt_raster_data.h:78
QwtRasterData::IgnoreOutOfRange
@ IgnoreOutOfRange
Ignore all values, that are out of range.
Definition qwt_raster_data.h:83
QwtRasterData::IgnoreAllVerticesOnLevel
@ IgnoreAllVerticesOnLevel
Ignore all vertices on the same level.
Definition qwt_raster_data.h:80
QwtScaleMap
A scale map.
Definition qwt_scale_map.h:27
QwtScaleMap::transform
double transform(double s) const
Definition qwt_scale_map.h:137
QwtScaleMap::invTransform
double invTransform(double p) const
Definition qwt_scale_map.h:154