qwt_plot_spectrogram.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_plot_spectrogram.h"
11 #include "qwt_painter.h"
12 #include "qwt_interval.h"
13 #include "qwt_scale_map.h"
14 #include "qwt_color_map.h"
15 #include <qimage.h>
16 #include <qpen.h>
17 #include <qpainter.h>
18 #include <qmath.h>
19 #include <qalgorithms.h>
20 #include <qthread.h>
21 #include <qfuture.h>
22 #include <qtconcurrentrun.h>
23 
24 #define DEBUG_RENDER 0
25 
26 #if DEBUG_RENDER
27 #include <QElapsedTimer>
28 #endif
29 
30 static inline bool qwtIsNaN( double d )
31 {
32  // qt_is_nan is private header and qIsNaN is not inlined
33  // so we need these code here too
34 
35  const uchar *ch = (const uchar *)&d;
36  if ( QSysInfo::ByteOrder == QSysInfo::BigEndian )
37  {
38  return (ch[0] & 0x7f) == 0x7f && ch[1] > 0xf0;
39  }
40  else
41  {
42  return (ch[7] & 0x7f) == 0x7f && ch[6] > 0xf0;
43  }
44 }
45 
47 {
48 public:
50  data( NULL ),
52  {
55 
57 #if 0
59 #endif
60  }
62  {
63  delete data;
64  delete colorMap;
65  }
66 
68  {
70  {
72  }
73  else
74  {
75  if ( maxRGBColorTableSize == 0 )
76  colorTable.clear();
77  else
79  }
80  }
81 
85 
86  QList<double> contourLevels;
89 
91  QVector<QRgb> colorTable;
92 };
93 
106  QwtPlotRasterItem( title )
107 {
108  d_data = new PrivateData();
109 
112 
113  setZ( 8.0 );
114 }
115 
118 {
119  delete d_data;
120 }
121 
124 {
126 }
127 
139 {
140  if ( on != bool( mode & d_data->displayMode ) )
141  {
142  if ( on )
143  d_data->displayMode |= mode;
144  else
145  d_data->displayMode &= ~mode;
146  }
147 
148  legendChanged();
149  itemChanged();
150 }
151 
159 {
160  return ( d_data->displayMode & mode );
161 }
162 
175 {
176  if ( colorMap == NULL )
177  return;
178 
179  if ( colorMap != d_data->colorMap )
180  {
181  delete d_data->colorMap;
183  }
184 
186 
187  invalidateCache();
188 
189  legendChanged();
190  itemChanged();
191 }
192 
198 {
199  return d_data->colorMap;
200 }
201 
203 {
204  numColors = qMax( numColors, 0 );
205  if ( numColors != d_data->maxRGBColorTableSize )
206  {
207  d_data->maxRGBColorTableSize = numColors;
209  invalidateCache();
210  }
211 }
212 
214 {
216 }
217 
232  const QColor &color, qreal width, Qt::PenStyle style )
233 {
234  setDefaultContourPen( QPen( color, width, style ) );
235 }
236 
248 {
249  if ( pen != d_data->defaultContourPen )
250  {
251  d_data->defaultContourPen = pen;
252 
253  legendChanged();
254  itemChanged();
255  }
256 }
257 
263 {
264  return d_data->defaultContourPen;
265 }
266 
278 QPen QwtPlotSpectrogram::contourPen( double level ) const
279 {
280  if ( d_data->data == NULL || d_data->colorMap == NULL )
281  return QPen();
282 
283  const QwtInterval intensityRange = d_data->data->interval(Qt::ZAxis);
284  const QColor c( d_data->colorMap->rgb( intensityRange, level ) );
285 
286  return QPen( c );
287 }
288 
300  QwtRasterData::ConrecFlag flag, bool on )
301 {
302  if ( bool( d_data->conrecFlags & flag ) == on )
303  return;
304 
305  if ( on )
306  d_data->conrecFlags |= flag;
307  else
308  d_data->conrecFlags &= ~flag;
309 
310  itemChanged();
311 }
312 
326  QwtRasterData::ConrecFlag flag ) const
327 {
328  return d_data->conrecFlags & flag;
329 }
330 
340 void QwtPlotSpectrogram::setContourLevels( const QList<double> &levels )
341 {
342  d_data->contourLevels = levels;
343  qSort( d_data->contourLevels );
344 
345  legendChanged();
346  itemChanged();
347 }
348 
358 {
359  return d_data->contourLevels;
360 }
361 
369 {
370  if ( data != d_data->data )
371  {
372  delete d_data->data;
373  d_data->data = data;
374 
375  invalidateCache();
376  itemChanged();
377  }
378 }
379 
385 {
386  return d_data->data;
387 }
388 
394 {
395  return d_data->data;
396 }
397 
408 {
409  if ( d_data->data == NULL )
410  return QwtInterval();
411 
412  return d_data->data->interval( axis );
413 }
414 
431 QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const
432 {
433  if ( d_data->data == NULL )
434  return QRectF();
435 
436  return d_data->data->pixelHint( area );
437 }
438 
456  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
457  const QRectF &area, const QSize &imageSize ) const
458 {
459  if ( imageSize.isEmpty() || d_data->data == NULL
460  || d_data->colorMap == NULL )
461  {
462  return QImage();
463  }
464 
465  const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis );
466  if ( !intensityRange.isValid() )
467  return QImage();
468 
469  const QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB )
470  ? QImage::Format_ARGB32 : QImage::Format_Indexed8;
471 
472  QImage image( imageSize, format );
473 
475  image.setColorTable( d_data->colorMap->colorTable256() );
476 
477  d_data->data->initRaster( area, image.size() );
478 
479 #if DEBUG_RENDER
480  QElapsedTimer time;
481  time.start();
482 #endif
483 
484 #if !defined(QT_NO_QFUTURE)
485  uint numThreads = renderThreadCount();
486 
487  if ( numThreads <= 0 )
488  numThreads = QThread::idealThreadCount();
489 
490  if ( numThreads <= 0 )
491  numThreads = 1;
492 
493  const int numRows = imageSize.height() / numThreads;
494 
495  QVector< QFuture<void> > futures;
496  futures.reserve( numThreads - 1 );
497 
498  for ( uint i = 0; i < numThreads; i++ )
499  {
500  QRect tile( 0, i * numRows, image.width(), numRows );
501  if ( i == numThreads - 1 )
502  {
503  tile.setHeight( image.height() - i * numRows );
504  renderTile( xMap, yMap, tile, &image );
505  }
506  else
507  {
508  futures += QtConcurrent::run(
510  xMap, yMap, tile, &image );
511  }
512  }
513  for ( int i = 0; i < futures.size(); i++ )
514  futures[i].waitForFinished();
515 
516 #else
517  const QRect tile( 0, 0, image.width(), image.height() );
518  renderTile( xMap, yMap, tile, &image );
519 #endif
520 
521 #if DEBUG_RENDER
522  const qint64 elapsed = time.elapsed();
523  qDebug() << "renderImage" << imageSize << elapsed;
524 #endif
525 
527 
528  return image;
529 }
530 
543  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
544  const QRect &tile, QImage *image ) const
545 {
546  const QwtInterval range = d_data->data->interval( Qt::ZAxis );
547  if ( range.width() <= 0.0 )
548  return;
549 
550  const bool hasGaps = !d_data->data->testAttribute( QwtRasterData::WithoutGaps );
551 
552  if ( d_data->colorMap->format() == QwtColorMap::RGB )
553  {
554  const int numColors = d_data->colorTable.size();
555  const QRgb *rgbTable = d_data->colorTable.constData();
557 
558  for ( int y = tile.top(); y <= tile.bottom(); y++ )
559  {
560  const double ty = yMap.invTransform( y );
561 
562  QRgb *line = reinterpret_cast<QRgb *>( image->scanLine( y ) );
563  line += tile.left();
564 
565  for ( int x = tile.left(); x <= tile.right(); x++ )
566  {
567  const double tx = xMap.invTransform( x );
568 
569  const double value = d_data->data->value( tx, ty );
570 
571  if ( hasGaps && qwtIsNaN( value ) )
572  {
573  *line++ = 0u;
574  }
575  else if ( numColors == 0 )
576  {
577  *line++ = colorMap->rgb( range, value );
578  }
579  else
580  {
581  const uint index = colorMap->colorIndex( numColors, range, value );
582  *line++ = rgbTable[index];
583  }
584  }
585  }
586  }
587  else if ( d_data->colorMap->format() == QwtColorMap::Indexed )
588  {
589  for ( int y = tile.top(); y <= tile.bottom(); y++ )
590  {
591  const double ty = yMap.invTransform( y );
592 
593  unsigned char *line = image->scanLine( y );
594  line += tile.left();
595 
596  for ( int x = tile.left(); x <= tile.right(); x++ )
597  {
598  const double tx = xMap.invTransform( x );
599 
600  const double value = d_data->data->value( tx, ty );
601 
602  if ( hasGaps && qwtIsNaN( value ) )
603  {
604  *line++ = 0;
605  }
606  else
607  {
608  const uint index = d_data->colorMap->colorIndex( 256, range, value );
609  *line++ = static_cast<unsigned char>( index );
610  }
611  }
612  }
613  }
614 }
615 
634  const QRectF &area, const QRect &rect ) const
635 {
636  QSize raster = rect.size() / 2;
637 
638  const QRectF pixelRect = pixelHint( area );
639  if ( !pixelRect.isEmpty() )
640  {
641  const QSize res( qCeil( rect.width() / pixelRect.width() ),
642  qCeil( rect.height() / pixelRect.height() ) );
643  raster = raster.boundedTo( res );
644  }
645 
646  return raster;
647 }
648 
660  const QRectF &rect, const QSize &raster ) const
661 {
662  if ( d_data->data == NULL )
664 
665  return d_data->data->contourLines( rect, raster,
667 }
668 
679 void QwtPlotSpectrogram::drawContourLines( QPainter *painter,
680  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
681  const QwtRasterData::ContourLines &contourLines ) const
682 {
683  if ( d_data->data == NULL )
684  return;
685 
686  const int numLevels = d_data->contourLevels.size();
687  for ( int l = 0; l < numLevels; l++ )
688  {
689  const double level = d_data->contourLevels[l];
690 
691  QPen pen = defaultContourPen();
692  if ( pen.style() == Qt::NoPen )
693  pen = contourPen( level );
694 
695  if ( pen.style() == Qt::NoPen )
696  continue;
697 
698  painter->setPen( pen );
699 
700  const QPolygonF &lines = contourLines[level];
701  for ( int i = 0; i < lines.size(); i += 2 )
702  {
703  const QPointF p1( xMap.transform( lines[i].x() ),
704  yMap.transform( lines[i].y() ) );
705  const QPointF p2( xMap.transform( lines[i+1].x() ),
706  yMap.transform( lines[i+1].y() ) );
707 
708  QwtPainter::drawLine( painter, p1, p2 );
709  }
710  }
711 }
712 
724 void QwtPlotSpectrogram::draw( QPainter *painter,
725  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
726  const QRectF &canvasRect ) const
727 {
728  if ( d_data->displayMode & ImageMode )
729  QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect );
730 
731  if ( d_data->displayMode & ContourMode )
732  {
733  // Add some pixels at the borders
734  const int margin = 2;
735  QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin,
736  canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin );
737 
738  QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect );
739 
740  const QRectF br = boundingRect();
741  if ( br.isValid() )
742  {
743  area &= br;
744  if ( area.isEmpty() )
745  return;
746 
747  rasterRect = QwtScaleMap::transform( xMap, yMap, area );
748  }
749 
750  QSize raster = contourRasterSize( area, rasterRect.toRect() );
751  raster = raster.boundedTo( rasterRect.toRect().size() );
752  if ( raster.isValid() )
753  {
754  const QwtRasterData::ContourLines lines =
755  renderContourLines( area, raster );
756 
757  drawContourLines( painter, xMap, yMap, lines );
758  }
759  }
760 }
virtual void discardRaster()
Discard a raster.
virtual void legendChanged()
virtual void drawContourLines(QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtRasterData::ContourLines &lines) const
For QwtPlotSpectrogram.
The data is displayed using contour lines.
virtual QRectF boundingRect() const
static void drawLine(QPainter *, double x1, double y1, double x2, double y2)
Wrapper for QPainter::drawLine()
Definition: qwt_painter.h:147
virtual QRectF pixelHint(const QRectF &) const
Pixel hint.
virtual ~QwtPlotSpectrogram()
Destructor.
virtual QVector< QRgb > colorTable256() const
A class representing an interval.
Definition: qwt_interval.h:26
A class, which displays raster data.
void setDefaultContourPen(const QColor &, qreal width=0.0, Qt::PenStyle=Qt::SolidLine)
ConrecFlag
Flags to modify the contour algorithm.
void setMaxRGBTableSize(int numColors)
void setData(QwtRasterData *data)
virtual void initRaster(const QRectF &, const QSize &raster)
Initialize a raster.
virtual void draw(QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect) const
Draw the raster data.
QFlags< DisplayMode > DisplayModes
Display modes.
TFSIMD_FORCE_INLINE const tfScalar & y() const
Ignore all vertices on the same level.
bool testConrecFlag(QwtRasterData::ConrecFlag) const
void setDisplayMode(DisplayMode, bool on=true)
QMap< double, QPolygonF > ContourLines
Contour lines.
virtual QwtInterval interval(Qt::Axis) const =0
The item is represented on the legend.
virtual QwtInterval interval(Qt::Axis) const
The values are mapped to colors using a color map.
virtual QVector< QRgb > colorTable(int numColors) const
virtual uint colorIndex(int numColors, const QwtInterval &interval, double value) const
Map a value of a given interval into a color index.
virtual ContourLines contourLines(const QRectF &rect, const QSize &raster, const QList< double > &levels, ConrecFlags) const
void setColorMap(QwtColorMap *)
T value
bool isValid() const
Definition: qwt_interval.h:211
virtual QwtRasterData::ContourLines renderContourLines(const QRectF &rect, const QSize &raster) const
Ignore all values, that are out of range.
void setZ(double z)
Set the z value.
virtual QPen contourPen(double level) const
Calculate the pen for a contour line.
QwtColorMap is used to map values into colors.
Definition: qwt_color_map.h:33
virtual QSize contourRasterSize(const QRectF &, const QRect &) const
Return the raster to be used by the CONREC contour algorithm.
QwtRasterData::ConrecFlags conrecFlags
QwtPlotSpectrogram(const QString &title=QString())
std::string format(const std::string &, const time_point< seconds > &, const femtoseconds &, const time_zone &)
TFSIMD_FORCE_INLINE const tfScalar & x() const
const QwtRasterData * data() const
const QwtColorMap * colorMap() const
virtual double value(double x, double y) const =0
QwtLinearColorMap builds a color map from color stops.
Definition: qwt_color_map.h:95
A scale map.
Definition: qwt_scale_map.h:30
QList< double > contourLevels() const
double invTransform(double p) const
The map is intended to map into RGB values.
Definition: qwt_color_map.h:44
virtual int rtti() const
virtual void draw(QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &rect) const
Draw the spectrogram.
virtual void itemChanged()
uint renderThreadCount() const
virtual QRectF pixelHint(const QRectF &) const
Pixel hint.
QFlags< ConrecFlag > ConrecFlags
Flags to modify the contour algorithm.
bool testAttribute(Attribute) const
QwtRasterData defines an interface to any type of raster data.
virtual QRgb rgb(const QwtInterval &interval, double value) const =0
static bool qwtIsNaN(double d)
void setItemAttribute(ItemAttribute, bool on=true)
double transform(double s) const
int i
void setContourLevels(const QList< double > &)
double width() const
Return the width of an interval.
Definition: qwt_interval.h:228
Format format() const
void setConrecFlag(QwtRasterData::ConrecFlag, bool on)
bool testDisplayMode(DisplayMode) const
virtual QImage renderImage(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize) const
Render an image from data and color map.
const QwtText & title() const
void renderTile(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &imageRect, QImage *image) const
Render a tile of an image.


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17