Loading...
Searching...
No Matches
qwt_polar_spectrogram.cpp
/******************************************************************************
* QwtPolar Widget Library
* Copyright (C) 2008 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_polar_spectrogram.h"
#include "qwt_polar.h"
#include "qwt_polar_plot.h"
#include "qwt_color_map.h"
#include "qwt_scale_map.h"
#include "qwt_raster_data.h"
#include "qwt_math.h"
#include "qwt_clipper.h"
#include <qpainter.h>
#include <qpainterpath.h>
#include <qthread.h>
#include <qfuture.h>
#include <qtconcurrentrun.h>
#include <qnumeric.h>
class QwtPolarSpectrogram::TileInfo
{
public:
QPoint imagePos;
QRect rect;
QImage* image;
};
class QwtPolarSpectrogram::PrivateData
{
public:
PrivateData()
: data( NULL )
{
colorMap = new QwtLinearColorMap();
}
~PrivateData()
{
delete data;
delete colorMap;
}
QwtRasterData* data;
QwtColorMap* colorMap;
QwtPolarSpectrogram::PaintAttributes paintAttributes;
};
QwtPolarSpectrogram::QwtPolarSpectrogram()
: QwtPolarItem( QwtText( "Spectrogram" ) )
{
m_data = new PrivateData;
setItemAttribute( QwtPolarItem::AutoScale );
setItemAttribute( QwtPolarItem::Legend, false );
setZ( 20.0 );
}
QwtPolarSpectrogram::~QwtPolarSpectrogram()
{
delete m_data;
}
int QwtPolarSpectrogram::rtti() const
{
return QwtPolarItem::Rtti_PolarSpectrogram;
}
void QwtPolarSpectrogram::setData( QwtRasterData* data )
{
if ( data != m_data->data )
{
delete m_data->data;
m_data->data = data;
itemChanged();
}
}
const QwtRasterData* QwtPolarSpectrogram::data() const
{
return m_data->data;
}
void QwtPolarSpectrogram::setColorMap( QwtColorMap* colorMap )
{
if ( m_data->colorMap != colorMap )
{
delete m_data->colorMap;
m_data->colorMap = colorMap;
}
itemChanged();
}
const QwtColorMap* QwtPolarSpectrogram::colorMap() const
{
return m_data->colorMap;
}
void QwtPolarSpectrogram::setPaintAttribute( PaintAttribute attribute, bool on )
{
if ( on )
m_data->paintAttributes |= attribute;
else
m_data->paintAttributes &= ~attribute;
}
bool QwtPolarSpectrogram::testPaintAttribute( PaintAttribute attribute ) const
{
return ( m_data->paintAttributes & attribute );
}
void QwtPolarSpectrogram::draw( QPainter* painter,
const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
const QPointF& pole, double,
const QRectF& canvasRect ) const
{
const QRectF plotRect = plot()->plotRect( canvasRect.toRect() );
QRect imageRect = canvasRect.toRect();
painter->save();
painter->setClipRect( canvasRect );
QPainterPath clipPathCanvas;
clipPathCanvas.addEllipse( plotRect );
painter->setClipPath( clipPathCanvas, Qt::IntersectClip );
imageRect &= plotRect.toAlignedRect(); // outer rect
const QwtInterval radialInterval = boundingInterval( QwtPolar::ScaleRadius );
if ( radialInterval.isValid() )
{
const double radius = radialMap.transform( radialInterval.maxValue() ) -
radialMap.transform( radialInterval.minValue() );
QRectF clipRect( 0, 0, 2 * radius, 2 * radius );
clipRect.moveCenter( pole );
imageRect &= clipRect.toRect(); // inner rect, we don't have points outside
QPainterPath clipPathRadial;
clipPathRadial.addEllipse( clipRect );
painter->setClipPath( clipPathRadial, Qt::IntersectClip );
}
const QImage image = renderImage( azimuthMap, radialMap, pole, imageRect );
painter->drawImage( imageRect, image );
painter->restore();
}
QImage QwtPolarSpectrogram::renderImage(
const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
const QPointF& pole, const QRect& rect ) const
{
if ( m_data->data == NULL || m_data->colorMap == NULL )
return QImage();
QImage image( rect.size(), m_data->colorMap->format() == QwtColorMap::RGB
? QImage::Format_ARGB32 : QImage::Format_Indexed8 );
const QwtInterval intensityRange = m_data->data->interval( Qt::ZAxis );
if ( !intensityRange.isValid() )
return image;
if ( m_data->colorMap->format() == QwtColorMap::Indexed )
image.setColorTable( m_data->colorMap->colorTable256() );
/*
For the moment we only announce the composition of the image by
calling initRaster(), but we don't pass any useful parameters.
( How to map rect into something, that is useful to initialize a matrix
of values in polar coordinates ? )
*/
m_data->data->initRaster( QRectF(), QSize() );
#if !defined( QT_NO_QFUTURE )
uint numThreads = renderThreadCount();
if ( numThreads <= 0 )
numThreads = QThread::idealThreadCount();
if ( numThreads <= 0 )
numThreads = 1;
const int numRows = rect.height() / numThreads;
QVector< TileInfo > tileInfos;
for ( uint i = 0; i < numThreads; i++ )
{
QRect tile( rect.x(), rect.y() + i * numRows, rect.width(), numRows );
if ( i == numThreads - 1 )
tile.setHeight( rect.height() - i * numRows );
TileInfo tileInfo;
tileInfo.imagePos = rect.topLeft();
tileInfo.rect = tile;
tileInfo.image = &image;
tileInfos += tileInfo;
}
QVector< QFuture< void > > futures;
for ( int i = 0; i < tileInfos.size(); i++ )
{
if ( i == tileInfos.size() - 1 )
{
renderTileInfo( azimuthMap, radialMap, pole, &tileInfos[i] );
}
else
{
futures += QtConcurrent::run(
#if QT_VERSION >= 0x060000
&QwtPolarSpectrogram::renderTileInfo, this,
#else
this, &QwtPolarSpectrogram::renderTileInfo,
#endif
azimuthMap, radialMap, pole, &tileInfos[i] );
}
}
for ( int i = 0; i < futures.size(); i++ )
futures[i].waitForFinished();
#else
renderTile( azimuthMap, radialMap, pole, rect.topLeft(), rect, &image );
#endif
m_data->data->discardRaster();
return image;
}
void QwtPolarSpectrogram::renderTileInfo(
const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
const QPointF& pole, TileInfo* tileInfo ) const
{
renderTile( azimuthMap, radialMap, pole,
tileInfo->imagePos, tileInfo->rect, tileInfo->image );
}
void QwtPolarSpectrogram::renderTile(
const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
const QPointF& pole, const QPoint& imagePos,
const QRect& tile, QImage* image ) const
{
const QwtInterval intensityRange = m_data->data->interval( Qt::ZAxis );
if ( !intensityRange.isValid() )
return;
const bool doFastAtan = testPaintAttribute( ApproximatedAtan );
const int y0 = imagePos.y();
const int y1 = tile.top();
const int y2 = tile.bottom();
const int x0 = imagePos.x();
const int x1 = tile.left();
const int x2 = tile.right();
if ( m_data->colorMap->format() == QwtColorMap::RGB )
{
for ( int y = y1; y <= y2; y++ )
{
const double dy = pole.y() - y;
const double dy2 = qwtSqr( dy );
QRgb* line = reinterpret_cast< QRgb* >( image->scanLine( y - y0 ) );
line += x1 - x0;
for ( int x = x1; x <= x2; x++ )
{
const double dx = x - pole.x();
double a = doFastAtan ? qwtFastAtan2( dy, dx ) : qAtan2( dy, dx );
if ( a < 0.0 )
a += 2 * M_PI;
if ( a < azimuthMap.p1() )
a += 2 * M_PI;
const double r = qSqrt( qwtSqr( dx ) + dy2 );
const double azimuth = azimuthMap.invTransform( a );
const double radius = radialMap.invTransform( r );
const double value = m_data->data->value( azimuth, radius );
if ( qIsNaN( value ) )
{
*line++ = 0u;
}
else
{
*line++ = m_data->colorMap->rgb( intensityRange, value );
}
}
}
}
else if ( m_data->colorMap->format() == QwtColorMap::Indexed )
{
for ( int y = y1; y <= y2; y++ )
{
const double dy = pole.y() - y;
const double dy2 = qwtSqr( dy );
unsigned char* line = image->scanLine( y - y0 );
line += x1 - x0;
for ( int x = x1; x <= x2; x++ )
{
const double dx = x - pole.x();
double a = doFastAtan ? qwtFastAtan2( dy, dx ) : qAtan2( dy, dx );
if ( a < 0.0 )
a += 2 * M_PI;
if ( a < azimuthMap.p1() )
a += 2 * M_PI;
const double r = qSqrt( qwtSqr( dx ) + dy2 );
const double azimuth = azimuthMap.invTransform( a );
const double radius = radialMap.invTransform( r );
const double value = m_data->data->value( azimuth, radius );
const uint index = m_data->colorMap->colorIndex( 256, intensityRange, value );
*line++ = static_cast< unsigned char >( index );
}
}
}
}
QwtInterval QwtPolarSpectrogram::boundingInterval( int scaleId ) const
{
if ( scaleId == QwtPolar::ScaleRadius )
return m_data->data->interval( Qt::YAxis );
return QwtPolarItem::boundingInterval( scaleId );
}
QVector
Definition qwt_clipper.h:23
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::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::minValue
double minValue() const
Definition qwt_interval.h:192
QwtInterval::maxValue
double maxValue() const
Definition qwt_interval.h:198
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
QwtPolarItem
Base class for items on a polar plot.
Definition qwt_polar_item.h:38
QwtPolarItem::boundingInterval
virtual QwtInterval boundingInterval(int scaleId) const
Definition qwt_polar_item.cpp:381
QwtPolarItem::itemChanged
virtual void itemChanged()
Definition qwt_polar_item.cpp:355
QwtPolarItem::Legend
@ Legend
The item is represented on the legend.
Definition qwt_polar_item.h:77
QwtPolarItem::AutoScale
@ AutoScale
Definition qwt_polar_item.h:83
QwtPolarItem::Rtti_PolarSpectrogram
@ Rtti_PolarSpectrogram
For QwtPolarSpectrogram.
Definition qwt_polar_item.h:61
QwtPolarItem::plot
QwtPolarPlot * plot() const
Definition qwt_polar_item.cpp:118
QwtPolarItem::renderThreadCount
uint renderThreadCount() const
Definition qwt_polar_item.cpp:282
QwtPolarItem::setItemAttribute
void setItemAttribute(ItemAttribute, bool on=true)
Definition qwt_polar_item.cpp:201
QwtPolarItem::setZ
void setZ(double z)
Set the z value.
Definition qwt_polar_item.cpp:142
QwtPolarPlot::plotRect
QRectF plotRect() const
Definition qwt_polar_plot.cpp:1120
QwtPolarSpectrogram::QwtPolarSpectrogram
QwtPolarSpectrogram()
Constructor.
Definition qwt_polar_spectrogram.cpp:55
QwtPolarSpectrogram::colorMap
const QwtColorMap * colorMap() const
Definition qwt_polar_spectrogram.cpp:134
QwtPolarSpectrogram::data
const QwtRasterData * data() const
Definition qwt_polar_spectrogram.cpp:103
QwtPolarSpectrogram::PaintAttribute
PaintAttribute
Definition qwt_polar_spectrogram.h:38
QwtPolarSpectrogram::ApproximatedAtan
@ ApproximatedAtan
Definition qwt_polar_spectrogram.h:44
QwtPolarSpectrogram::setData
void setData(QwtRasterData *data)
Definition qwt_polar_spectrogram.cpp:88
QwtPolarSpectrogram::~QwtPolarSpectrogram
virtual ~QwtPolarSpectrogram()
Destructor.
Definition qwt_polar_spectrogram.cpp:67
QwtPolarSpectrogram::rtti
virtual int rtti() const override
Definition qwt_polar_spectrogram.cpp:73
QwtPolarSpectrogram::setColorMap
void setColorMap(QwtColorMap *)
Definition qwt_polar_spectrogram.cpp:119
QwtPolarSpectrogram::renderImage
virtual QImage renderImage(const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap, const QPointF &pole, const QRect &rect) const
Render an image from the data and color map.
Definition qwt_polar_spectrogram.cpp:232
QwtPolarSpectrogram::setPaintAttribute
void setPaintAttribute(PaintAttribute, bool on=true)
Definition qwt_polar_spectrogram.cpp:146
QwtPolarSpectrogram::testPaintAttribute
bool testPaintAttribute(PaintAttribute) const
Definition qwt_polar_spectrogram.cpp:159
QwtPolarSpectrogram::PaintAttributes
QFlags< PaintAttribute > PaintAttributes
Definition qwt_polar_spectrogram.h:47
QwtPolarSpectrogram::renderTile
virtual void renderTile(const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap, const QPointF &pole, const QPoint &imagePos, const QRect &tile, QImage *image) const
Render a sub-rectangle of an image.
Definition qwt_polar_spectrogram.cpp:340
QwtPolarSpectrogram::boundingInterval
virtual QwtInterval boundingInterval(int scaleId) const override
Definition qwt_polar_spectrogram.cpp:440
QwtPolarSpectrogram::draw
virtual void draw(QPainter *painter, const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap, const QPointF &pole, double radius, const QRectF &canvasRect) const override
Definition qwt_polar_spectrogram.cpp:174
QwtRasterData
QwtRasterData defines an interface to any type of raster data.
Definition qwt_raster_data.h:43
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::interval
virtual QwtInterval interval(Qt::Axis) const =0
QwtScaleMap
A scale map.
Definition qwt_scale_map.h:27
QwtScaleMap::p1
double p1() const
Definition qwt_scale_map.h:99
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
QwtText
A class representing a text.
Definition qwt_text.h:52