Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
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#include <qnumeric.h>
24
25class QwtPolarSpectrogram::TileInfo
26{
27 public:
28 QPoint imagePos;
29 QRect rect;
30 QImage* image;
31};
32
33class QwtPolarSpectrogram::PrivateData
34{
35 public:
36 PrivateData()
37 : data( NULL )
38 {
39 colorMap = new QwtLinearColorMap();
40 }
41
42 ~PrivateData()
43 {
44 delete data;
45 delete colorMap;
46 }
47
48 QwtRasterData* data;
49 QwtColorMap* colorMap;
50
52};
53
56 : QwtPolarItem( QwtText( "Spectrogram" ) )
57{
58 m_data = new PrivateData;
59
62
63 setZ( 20.0 );
64}
65
71
77
89{
90 if ( data != m_data->data )
91 {
92 delete m_data->data;
93 m_data->data = data;
94
96 }
97}
98
104{
105 return m_data->data;
106}
107
120{
121 if ( m_data->colorMap != colorMap )
122 {
123 delete m_data->colorMap;
124 m_data->colorMap = colorMap;
125 }
126
127 itemChanged();
128}
129
135{
136 return m_data->colorMap;
137}
138
147{
148 if ( on )
149 m_data->paintAttributes |= attribute;
150 else
151 m_data->paintAttributes &= ~attribute;
152}
153
160{
161 return ( m_data->paintAttributes & attribute );
162}
163
174void QwtPolarSpectrogram::draw( QPainter* painter,
175 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
176 const QPointF& pole, double,
177 const QRectF& canvasRect ) const
178{
179 const QRectF plotRect = plot()->plotRect( canvasRect.toRect() );
180 QRect imageRect = canvasRect.toRect();
181
182 painter->save();
183
184 painter->setClipRect( canvasRect );
185
186 QPainterPath clipPathCanvas;
187 clipPathCanvas.addEllipse( plotRect );
188 painter->setClipPath( clipPathCanvas, Qt::IntersectClip );
189
190 imageRect &= plotRect.toAlignedRect(); // outer rect
191
192 const QwtInterval radialInterval = boundingInterval( QwtPolar::ScaleRadius );
193 if ( radialInterval.isValid() )
194 {
195 const double radius = radialMap.transform( radialInterval.maxValue() ) -
196 radialMap.transform( radialInterval.minValue() );
197
198 QRectF clipRect( 0, 0, 2 * radius, 2 * radius );
199 clipRect.moveCenter( pole );
200
201 imageRect &= clipRect.toRect(); // inner rect, we don't have points outside
202
203 QPainterPath clipPathRadial;
204 clipPathRadial.addEllipse( clipRect );
205 painter->setClipPath( clipPathRadial, Qt::IntersectClip );
206 }
207
208 const QImage image = renderImage( azimuthMap, radialMap, pole, imageRect );
209 painter->drawImage( imageRect, image );
210
211 painter->restore();
212}
213
233 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
234 const QPointF& pole, const QRect& rect ) const
235{
236 if ( m_data->data == NULL || m_data->colorMap == NULL )
237 return QImage();
238
239 QImage image( rect.size(), m_data->colorMap->format() == QwtColorMap::RGB
240 ? QImage::Format_ARGB32 : QImage::Format_Indexed8 );
241
242 const QwtInterval intensityRange = m_data->data->interval( Qt::ZAxis );
243 if ( !intensityRange.isValid() )
244 return image;
245
246 if ( m_data->colorMap->format() == QwtColorMap::Indexed )
247 image.setColorTable( m_data->colorMap->colorTable256() );
248
249 /*
250 For the moment we only announce the composition of the image by
251 calling initRaster(), but we don't pass any useful parameters.
252 ( How to map rect into something, that is useful to initialize a matrix
253 of values in polar coordinates ? )
254 */
255 m_data->data->initRaster( QRectF(), QSize() );
256
257
258#if !defined( QT_NO_QFUTURE )
259 uint numThreads = renderThreadCount();
260
261 if ( numThreads <= 0 )
262 numThreads = QThread::idealThreadCount();
263
264 if ( numThreads <= 0 )
265 numThreads = 1;
266
267 const int numRows = rect.height() / numThreads;
268
269
270 QVector< TileInfo > tileInfos;
271 for ( uint i = 0; i < numThreads; i++ )
272 {
273 QRect tile( rect.x(), rect.y() + i * numRows, rect.width(), numRows );
274 if ( i == numThreads - 1 )
275 tile.setHeight( rect.height() - i * numRows );
276
277 TileInfo tileInfo;
278 tileInfo.imagePos = rect.topLeft();
279 tileInfo.rect = tile;
280 tileInfo.image = &image;
281
282 tileInfos += tileInfo;
283 }
284
285 QVector< QFuture< void > > futures;
286 for ( int i = 0; i < tileInfos.size(); i++ )
287 {
288 if ( i == tileInfos.size() - 1 )
289 {
290 renderTileInfo( azimuthMap, radialMap, pole, &tileInfos[i] );
291 }
292 else
293 {
294 futures += QtConcurrent::run(
295#if QT_VERSION >= 0x060000
296 &QwtPolarSpectrogram::renderTileInfo, this,
297#else
298 this, &QwtPolarSpectrogram::renderTileInfo,
299#endif
300 azimuthMap, radialMap, pole, &tileInfos[i] );
301 }
302 }
303
304 for ( int i = 0; i < futures.size(); i++ )
305 futures[i].waitForFinished();
306
307#else
308 renderTile( azimuthMap, radialMap, pole, rect.topLeft(), rect, &image );
309#endif
310
311 m_data->data->discardRaster();
312
313 return image;
314}
315
316void QwtPolarSpectrogram::renderTileInfo(
317 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
318 const QPointF& pole, TileInfo* tileInfo ) const
319{
320 renderTile( azimuthMap, radialMap, pole,
321 tileInfo->imagePos, tileInfo->rect, tileInfo->image );
322}
323
341 const QwtScaleMap& azimuthMap, const QwtScaleMap& radialMap,
342 const QPointF& pole, const QPoint& imagePos,
343 const QRect& tile, QImage* image ) const
344{
345 const QwtInterval intensityRange = m_data->data->interval( Qt::ZAxis );
346 if ( !intensityRange.isValid() )
347 return;
348
349 const bool doFastAtan = testPaintAttribute( ApproximatedAtan );
350
351 const int y0 = imagePos.y();
352 const int y1 = tile.top();
353 const int y2 = tile.bottom();
354
355 const int x0 = imagePos.x();
356 const int x1 = tile.left();
357 const int x2 = tile.right();
358
359 if ( m_data->colorMap->format() == QwtColorMap::RGB )
360 {
361 for ( int y = y1; y <= y2; y++ )
362 {
363 const double dy = pole.y() - y;
364 const double dy2 = qwtSqr( dy );
365
366 QRgb* line = reinterpret_cast< QRgb* >( image->scanLine( y - y0 ) );
367 line += x1 - x0;
368
369 for ( int x = x1; x <= x2; x++ )
370 {
371 const double dx = x - pole.x();
372
373 double a = doFastAtan ? qwtFastAtan2( dy, dx ) : qAtan2( dy, dx );
374
375 if ( a < 0.0 )
376 a += 2 * M_PI;
377
378 if ( a < azimuthMap.p1() )
379 a += 2 * M_PI;
380
381 const double r = qSqrt( qwtSqr( dx ) + dy2 );
382
383 const double azimuth = azimuthMap.invTransform( a );
384 const double radius = radialMap.invTransform( r );
385
386 const double value = m_data->data->value( azimuth, radius );
387 if ( qIsNaN( value ) )
388 {
389 *line++ = 0u;
390 }
391 else
392 {
393 *line++ = m_data->colorMap->rgb( intensityRange, value );
394 }
395 }
396 }
397 }
398 else if ( m_data->colorMap->format() == QwtColorMap::Indexed )
399 {
400 for ( int y = y1; y <= y2; y++ )
401 {
402 const double dy = pole.y() - y;
403 const double dy2 = qwtSqr( dy );
404
405 unsigned char* line = image->scanLine( y - y0 );
406 line += x1 - x0;
407 for ( int x = x1; x <= x2; x++ )
408 {
409 const double dx = x - pole.x();
410
411 double a = doFastAtan ? qwtFastAtan2( dy, dx ) : qAtan2( dy, dx );
412 if ( a < 0.0 )
413 a += 2 * M_PI;
414 if ( a < azimuthMap.p1() )
415 a += 2 * M_PI;
416
417 const double r = qSqrt( qwtSqr( dx ) + dy2 );
418
419 const double azimuth = azimuthMap.invTransform( a );
420 const double radius = radialMap.invTransform( r );
421
422 const double value = m_data->data->value( azimuth, radius );
423
424 const uint index = m_data->colorMap->colorIndex( 256, intensityRange, value );
425 *line++ = static_cast< unsigned char >( index );
426 }
427 }
428 }
429}
430
441{
442 if ( scaleId == QwtPolar::ScaleRadius )
443 return m_data->data->interval( Qt::YAxis );
444
445 return QwtPolarItem::boundingInterval( scaleId );
446}
QwtColorMap is used to map values into colors.
virtual uint colorIndex(int numColors, const QwtInterval &interval, double value) const
Map a value of a given interval into a color index.
@ RGB
The map is intended to map into RGB values.
virtual QVector< QRgb > colorTable256() const
virtual QRgb rgb(const QwtInterval &interval, double value) const =0
A class representing an interval.
double minValue() const
double maxValue() const
bool isValid() const
QwtLinearColorMap builds a color map from color stops.
Base class for items on a polar plot.
virtual QwtInterval boundingInterval(int scaleId) const
virtual void itemChanged()
@ Legend
The item is represented on the legend.
@ Rtti_PolarSpectrogram
For QwtPolarSpectrogram.
QwtPolarPlot * plot() const
uint renderThreadCount() const
void setItemAttribute(ItemAttribute, bool on=true)
void setZ(double z)
Set the z value.
QRectF plotRect() const
const QwtColorMap * colorMap() const
const QwtRasterData * data() const
void setData(QwtRasterData *data)
virtual ~QwtPolarSpectrogram()
Destructor.
virtual int rtti() const override
void setColorMap(QwtColorMap *)
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.
void setPaintAttribute(PaintAttribute, bool on=true)
bool testPaintAttribute(PaintAttribute) const
QFlags< PaintAttribute > PaintAttributes
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.
virtual QwtInterval boundingInterval(int scaleId) const override
virtual void draw(QPainter *painter, const QwtScaleMap &azimuthMap, const QwtScaleMap &radialMap, const QPointF &pole, double radius, const QRectF &canvasRect) const override
QwtRasterData defines an interface to any type of raster data.
virtual void discardRaster()
Discard a raster.
virtual double value(double x, double y) const =0
virtual void initRaster(const QRectF &, const QSize &raster)
Initialize a raster.
virtual QwtInterval interval(Qt::Axis) const =0
A scale map.
double p1() const
double transform(double s) const
double invTransform(double p) const
A class representing a text.
Definition qwt_text.h:52