Qwt User's Guide 6.2.0

qwt_polar_spectrogram.cpp
1 /******************************************************************************
2 * QwtPolar Widget Library
3 * Copyright (C) 2008 Uwe Rathmann
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the Qwt License, Version 1.0
7 *****************************************************************************/
8
9 #include "qwt_polar_spectrogram.h"
10 #include "qwt_polar.h"
11 #include "qwt_polar_plot.h"
12 #include "qwt_color_map.h"
13 #include "qwt_scale_map.h"
14 #include "qwt_raster_data.h"
15 #include "qwt_math.h"
16 #include "qwt_clipper.h"
17
18 #include <qpainter.h>
19 #include <qpainterpath.h>
20 #include <qthread.h>
21 #include <qfuture.h>
22 #include <qtconcurrentrun.h>
23
24 #if QT_VERSION < 0x050000
25 #include <qnumeric.h>
26 #endif
27
28 class QwtPolarSpectrogram::TileInfo
29 {
30 public:
31 QPoint imagePos;
32 QRect rect;
33 QImage* image;
34 };
35
36 class QwtPolarSpectrogram::PrivateData
37 {
38 public:
39 PrivateData()
40 : data( NULL )
41 {
42 colorMap = new QwtLinearColorMap();
43 }
44
45 ~PrivateData()
46 {
47 delete data;
48 delete colorMap;
49 }
50
51 QwtRasterData* data;
52 QwtColorMap* colorMap;
53
54 QwtPolarSpectrogram::PaintAttributes paintAttributes;
55 };
56
58 QwtPolarSpectrogram::QwtPolarSpectrogram()
59 : QwtPolarItem( QwtText( "Spectrogram" ) )
60 {
61 m_data = new PrivateData;
62
63 setItemAttribute( QwtPolarItem::AutoScale );
64 setItemAttribute( QwtPolarItem::Legend, false );
65
66 setZ( 20.0 );
67 }
68
70 QwtPolarSpectrogram::~QwtPolarSpectrogram()
71 {
72 delete m_data;
73 }
74
76 int QwtPolarSpectrogram::rtti() const
77 {
78 return QwtPolarItem::Rtti_PolarSpectrogram;
79 }
80
91 void QwtPolarSpectrogram::setData( QwtRasterData* data )
92 {
93 if ( data != m_data->data )
94 {
95 delete m_data->data;
96 m_data->data = data;
97
98 itemChanged();
99 }
100 }
101
106 const QwtRasterData* QwtPolarSpectrogram::data() const
107 {
108 return m_data->data;
109 }
110
122 void QwtPolarSpectrogram::setColorMap( QwtColorMap* colorMap )
123 {
124 if ( m_data->colorMap != colorMap )
125 {
126 delete m_data->colorMap;
127 m_data->colorMap = colorMap;
128 }
129
130 itemChanged();
131 }
132
137 const QwtColorMap* QwtPolarSpectrogram::colorMap() const
138 {
139 return m_data->colorMap;
140 }
141
149 void QwtPolarSpectrogram::setPaintAttribute( PaintAttribute attribute, bool on )
150 {
151 if ( on )
152 m_data->paintAttributes |= attribute;
153 else
154 m_data->paintAttributes &= ~attribute;
155 }
156
162 bool QwtPolarSpectrogram::testPaintAttribute( PaintAttribute attribute ) const
163 {
164 return ( m_data->paintAttributes & attribute );
165 }
166
177 void QwtPolarSpectrogram::draw( QPainter* painter,
178 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
179 const QPointF& pole, double,
180 const QRectF& canvasRect ) const
181 {
182 const QRectF plotRect = plot()->plotRect( canvasRect.toRect() );
183 QRect imageRect = canvasRect.toRect();
184
185 painter->save();
186
187 painter->setClipRect( canvasRect );
188
189 QPainterPath clipPathCanvas;
190 clipPathCanvas.addEllipse( plotRect );
191 painter->setClipPath( clipPathCanvas, Qt::IntersectClip );
192
193 imageRect &= plotRect.toAlignedRect(); // outer rect
194
195 const QwtInterval radialInterval = boundingInterval( QwtPolar::ScaleRadius );
196 if ( radialInterval.isValid() )
197 {
198 const double radius = radialMap.transform( radialInterval.maxValue() ) -
199 radialMap.transform( radialInterval.minValue() );
200
201 QRectF clipRect( 0, 0, 2 * radius, 2 * radius );
202 clipRect.moveCenter( pole );
203
204 imageRect &= clipRect.toRect(); // inner rect, we don't have points outside
205
206 QPainterPath clipPathRadial;
207 clipPathRadial.addEllipse( clipRect );
208 painter->setClipPath( clipPathRadial, Qt::IntersectClip );
209 }
210
211 const QImage image = renderImage( azimuthMap, radialMap, pole, imageRect );
212 painter->drawImage( imageRect, image );
213
214 painter->restore();
215 }
216
235 QImage QwtPolarSpectrogram::renderImage(
236 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
237 const QPointF& pole, const QRect& rect ) const
238 {
239 if ( m_data->data == NULL || m_data->colorMap == NULL )
240 return QImage();
241
242 QImage image( rect.size(), m_data->colorMap->format() == QwtColorMap::RGB
243 ? QImage::Format_ARGB32 : QImage::Format_Indexed8 );
244
245 const QwtInterval intensityRange = m_data->data->interval( Qt::ZAxis );
246 if ( !intensityRange.isValid() )
247 return image;
248
249 if ( m_data->colorMap->format() == QwtColorMap::Indexed )
250 image.setColorTable( m_data->colorMap->colorTable256() );
251
252 /*
253 For the moment we only announce the composition of the image by
254 calling initRaster(), but we don't pass any useful parameters.
255 ( How to map rect into something, that is useful to initialize a matrix
256 of values in polar coordinates ? )
257 */
258 m_data->data->initRaster( QRectF(), QSize() );
259
260
261 #if !defined( QT_NO_QFUTURE )
262 uint numThreads = renderThreadCount();
263
264 if ( numThreads <= 0 )
265 numThreads = QThread::idealThreadCount();
266
267 if ( numThreads <= 0 )
268 numThreads = 1;
269
270 const int numRows = rect.height() / numThreads;
271
272
273 QVector< TileInfo > tileInfos;
274 for ( uint i = 0; i < numThreads; i++ )
275 {
276 QRect tile( rect.x(), rect.y() + i * numRows, rect.width(), numRows );
277 if ( i == numThreads - 1 )
278 tile.setHeight( rect.height() - i * numRows );
279
280 TileInfo tileInfo;
281 tileInfo.imagePos = rect.topLeft();
282 tileInfo.rect = tile;
283 tileInfo.image = &image;
284
285 tileInfos += tileInfo;
286 }
287
288 QVector< QFuture< void > > futures;
289 for ( int i = 0; i < tileInfos.size(); i++ )
290 {
291 if ( i == tileInfos.size() - 1 )
292 {
293 renderTileInfo( azimuthMap, radialMap, pole, &tileInfos[i] );
294 }
295 else
296 {
297 futures += QtConcurrent::run(
298 #if QT_VERSION >= 0x060000
299 &QwtPolarSpectrogram::renderTileInfo, this,
300 #else
301 this, &QwtPolarSpectrogram::renderTileInfo,
302 #endif
303 azimuthMap, radialMap, pole, &tileInfos[i] );
304 }
305 }
306
307 for ( int i = 0; i < futures.size(); i++ )
308 futures[i].waitForFinished();
309
310 #else
311 renderTile( azimuthMap, radialMap, pole, rect.topLeft(), rect, &image );
312 #endif
313
314 m_data->data->discardRaster();
315
316 return image;
317 }
318
319 void QwtPolarSpectrogram::renderTileInfo(
320 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
321 const QPointF& pole, TileInfo* tileInfo ) const
322 {
323 renderTile( azimuthMap, radialMap, pole,
324 tileInfo->imagePos, tileInfo->rect, tileInfo->image );
325 }
326
343 void QwtPolarSpectrogram::renderTile(
344 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
345 const QPointF& pole, const QPoint& imagePos,
346 const QRect& tile, QImage* image ) const
347 {
348 const QwtInterval intensityRange = m_data->data->interval( Qt::ZAxis );
349 if ( !intensityRange.isValid() )
350 return;
351
352 const bool doFastAtan = testPaintAttribute( ApproximatedAtan );
353
354 const int y0 = imagePos.y();
355 const int y1 = tile.top();
356 const int y2 = tile.bottom();
357
358 const int x0 = imagePos.x();
359 const int x1 = tile.left();
360 const int x2 = tile.right();
361
362 if ( m_data->colorMap->format() == QwtColorMap::RGB )
363 {
364 for ( int y = y1; y <= y2; y++ )
365 {
366 const double dy = pole.y() - y;
367 const double dy2 = qwtSqr( dy );
368
369 QRgb* line = reinterpret_cast< QRgb* >( image->scanLine( y - y0 ) );
370 line += x1 - x0;
371
372 for ( int x = x1; x <= x2; x++ )
373 {
374 const double dx = x - pole.x();
375
376 double a = doFastAtan ? qwtFastAtan2( dy, dx ) : qAtan2( dy, dx );
377
378 if ( a < 0.0 )
379 a += 2 * M_PI;
380
381 if ( a < azimuthMap.p1() )
382 a += 2 * M_PI;
383
384 const double r = qSqrt( qwtSqr( dx ) + dy2 );
385
386 const double azimuth = azimuthMap.invTransform( a );
387 const double radius = radialMap.invTransform( r );
388
389 const double value = m_data->data->value( azimuth, radius );
390 if ( qIsNaN( value ) )
391 {
392 *line++ = 0u;
393 }
394 else
395 {
396 *line++ = m_data->colorMap->rgb( intensityRange, value );
397 }
398 }
399 }
400 }
401 else if ( m_data->colorMap->format() == QwtColorMap::Indexed )
402 {
403 for ( int y = y1; y <= y2; y++ )
404 {
405 const double dy = pole.y() - y;
406 const double dy2 = qwtSqr( dy );
407
408 unsigned char* line = image->scanLine( y - y0 );
409 line += x1 - x0;
410 for ( int x = x1; x <= x2; x++ )
411 {
412 const double dx = x - pole.x();
413
414 double a = doFastAtan ? qwtFastAtan2( dy, dx ) : qAtan2( dy, dx );
415 if ( a < 0.0 )
416 a += 2 * M_PI;
417 if ( a < azimuthMap.p1() )
418 a += 2 * M_PI;
419
420 const double r = qSqrt( qwtSqr( dx ) + dy2 );
421
422 const double azimuth = azimuthMap.invTransform( a );
423 const double radius = radialMap.invTransform( r );
424
425 const double value = m_data->data->value( azimuth, radius );
426
427 const uint index = m_data->colorMap->colorIndex( 256, intensityRange, value );
428 *line++ = static_cast< unsigned char >( index );
429 }
430 }
431 }
432 }
433
443 QwtInterval QwtPolarSpectrogram::boundingInterval( int scaleId ) const
444 {
445 if ( scaleId == QwtPolar::ScaleRadius )
446 return m_data->data->interval( Qt::YAxis );
447
448 return QwtPolarItem::boundingInterval( scaleId );
449 }
QVector
Definition: qwt_clipper.h:23
QwtColorMap
QwtColorMap is used to map values into colors.
Definition: qwt_color_map.h:38
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
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:58
QwtPolarSpectrogram::colorMap
const QwtColorMap * colorMap() const
Definition: qwt_polar_spectrogram.cpp:137
QwtPolarSpectrogram::data
const QwtRasterData * data() const
Definition: qwt_polar_spectrogram.cpp:106
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:91
QwtPolarSpectrogram::~QwtPolarSpectrogram
virtual ~QwtPolarSpectrogram()
Destructor.
Definition: qwt_polar_spectrogram.cpp:70
QwtPolarSpectrogram::rtti
virtual int rtti() const override
Definition: qwt_polar_spectrogram.cpp:76
QwtPolarSpectrogram::setColorMap
void setColorMap(QwtColorMap *)
Definition: qwt_polar_spectrogram.cpp:122
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:235
QwtPolarSpectrogram::setPaintAttribute
void setPaintAttribute(PaintAttribute, bool on=true)
Definition: qwt_polar_spectrogram.cpp:149
QwtPolarSpectrogram::testPaintAttribute
bool testPaintAttribute(PaintAttribute) const
Definition: qwt_polar_spectrogram.cpp:162
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:343
QwtPolarSpectrogram::boundingInterval
virtual QwtInterval boundingInterval(int scaleId) const override
Definition: qwt_polar_spectrogram.cpp:443
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:177
QwtRasterData
QwtRasterData defines an interface to any type of raster data.
Definition: qwt_raster_data.h:43
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