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 "qwt_math.h"
16 
17 #include <qimage.h>
18 #include <qpen.h>
19 #include <qpainter.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.h>
28 #endif
29 
30 #include <algorithm>
31 
32 static inline bool qwtIsNaN( double d )
33 {
34  // qt_is_nan is private header and qIsNaN is not inlined
35  // so we need these code here too
36 
37  const uchar *ch = (const uchar *)&d;
38  if ( QSysInfo::ByteOrder == QSysInfo::BigEndian )
39  {
40  return (ch[0] & 0x7f) == 0x7f && ch[1] > 0xf0;
41  }
42  else
43  {
44  return (ch[7] & 0x7f) == 0x7f && ch[6] > 0xf0;
45  }
46 }
47 
49 {
50 public:
52  data( NULL ),
54  {
57 
59 #if 0
61 #endif
62  }
64  {
65  delete data;
66  delete colorMap;
67  }
68 
70  {
72  {
74  }
75  else
76  {
77  if ( maxRGBColorTableSize == 0 )
78  colorTable.clear();
79  else
81  }
82  }
83 
87 
91 
94 };
95 
108  QwtPlotRasterItem( title )
109 {
110  d_data = new PrivateData();
111 
114 
115  setZ( 8.0 );
116 }
117 
120 {
121  delete d_data;
122 }
123 
126 {
128 }
129 
141 {
142  if ( on != bool( mode & d_data->displayMode ) )
143  {
144  if ( on )
145  d_data->displayMode |= mode;
146  else
147  d_data->displayMode &= ~mode;
148  }
149 
150  legendChanged();
151  itemChanged();
152 }
153 
161 {
162  return ( d_data->displayMode & mode );
163 }
164 
177 {
178  if ( colorMap == NULL )
179  return;
180 
181  if ( colorMap != d_data->colorMap )
182  {
183  delete d_data->colorMap;
185  }
186 
188 
189  invalidateCache();
190 
191  legendChanged();
192  itemChanged();
193 }
194 
200 {
201  return d_data->colorMap;
202 }
203 
205 {
206  numColors = qMax( numColors, 0 );
207  if ( numColors != d_data->maxRGBColorTableSize )
208  {
209  d_data->maxRGBColorTableSize = numColors;
211  invalidateCache();
212  }
213 }
214 
216 {
218 }
219 
234  const QColor &color, qreal width, Qt::PenStyle style )
235 {
236  setDefaultContourPen( QPen( color, width, style ) );
237 }
238 
250 {
251  if ( pen != d_data->defaultContourPen )
252  {
253  d_data->defaultContourPen = pen;
254 
255  legendChanged();
256  itemChanged();
257  }
258 }
259 
265 {
266  return d_data->defaultContourPen;
267 }
268 
280 QPen QwtPlotSpectrogram::contourPen( double level ) const
281 {
282  if ( d_data->data == NULL || d_data->colorMap == NULL )
283  return QPen();
284 
285  const QwtInterval intensityRange = d_data->data->interval(Qt::ZAxis);
286  const QColor c( d_data->colorMap->rgb( intensityRange, level ) );
287 
288  return QPen( c );
289 }
290 
302  QwtRasterData::ConrecFlag flag, bool on )
303 {
304  if ( bool( d_data->conrecFlags & flag ) == on )
305  return;
306 
307  if ( on )
308  d_data->conrecFlags |= flag;
309  else
310  d_data->conrecFlags &= ~flag;
311 
312  itemChanged();
313 }
314 
328  QwtRasterData::ConrecFlag flag ) const
329 {
330  return d_data->conrecFlags & flag;
331 }
332 
343 {
344  d_data->contourLevels = levels;
345  std::sort( d_data->contourLevels.begin(), d_data->contourLevels.end() );
346 
347  legendChanged();
348  itemChanged();
349 }
350 
360 {
361  return d_data->contourLevels;
362 }
363 
371 {
372  if ( data != d_data->data )
373  {
374  delete d_data->data;
375  d_data->data = data;
376 
377  invalidateCache();
378  itemChanged();
379  }
380 }
381 
387 {
388  return d_data->data;
389 }
390 
396 {
397  return d_data->data;
398 }
399 
410 {
411  if ( d_data->data == NULL )
412  return QwtInterval();
413 
414  return d_data->data->interval( axis );
415 }
416 
433 QRectF QwtPlotSpectrogram::pixelHint( const QRectF &area ) const
434 {
435  if ( d_data->data == NULL )
436  return QRectF();
437 
438  return d_data->data->pixelHint( area );
439 }
440 
458  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
459  const QRectF &area, const QSize &imageSize ) const
460 {
461  if ( imageSize.isEmpty() || d_data->data == NULL
462  || d_data->colorMap == NULL )
463  {
464  return QImage();
465  }
466 
467  const QwtInterval intensityRange = d_data->data->interval( Qt::ZAxis );
468  if ( !intensityRange.isValid() )
469  return QImage();
470 
471  const QImage::Format format = ( d_data->colorMap->format() == QwtColorMap::RGB )
472  ? QImage::Format_ARGB32 : QImage::Format_Indexed8;
473 
474  QImage image( imageSize, format );
475 
477  image.setColorTable( d_data->colorMap->colorTable256() );
478 
479  d_data->data->initRaster( area, image.size() );
480 
481 #if DEBUG_RENDER
482  QElapsedTimer time;
483  time.start();
484 #endif
485 
486 #if !defined(QT_NO_QFUTURE)
487  uint numThreads = renderThreadCount();
488 
489  if ( numThreads <= 0 )
490  numThreads = QThread::idealThreadCount();
491 
492  if ( numThreads <= 0 )
493  numThreads = 1;
494 
495  const int numRows = imageSize.height() / numThreads;
496 
497  QVector< QFuture<void> > futures;
498  futures.reserve( numThreads - 1 );
499 
500  for ( uint i = 0; i < numThreads; i++ )
501  {
502  QRect tile( 0, i * numRows, image.width(), numRows );
503  if ( i == numThreads - 1 )
504  {
505  tile.setHeight( image.height() - i * numRows );
506  renderTile( xMap, yMap, tile, &image );
507  }
508  else
509  {
510  futures += QtConcurrent::run(
512  xMap, yMap, tile, &image );
513  }
514  }
515  for ( int i = 0; i < futures.size(); i++ )
516  futures[i].waitForFinished();
517 
518 #else
519  const QRect tile( 0, 0, image.width(), image.height() );
520  renderTile( xMap, yMap, tile, &image );
521 #endif
522 
523 #if DEBUG_RENDER
524  const qint64 elapsed = time.elapsed();
525  qDebug() << "renderImage" << imageSize << elapsed;
526 #endif
527 
529 
530  return image;
531 }
532 
545  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
546  const QRect &tile, QImage *image ) const
547 {
548  const QwtInterval range = d_data->data->interval( Qt::ZAxis );
549  if ( range.width() <= 0.0 )
550  return;
551 
552  const bool hasGaps = !d_data->data->testAttribute( QwtRasterData::WithoutGaps );
553 
554  if ( d_data->colorMap->format() == QwtColorMap::RGB )
555  {
556  const int numColors = d_data->colorTable.size();
557  const QRgb *rgbTable = d_data->colorTable.constData();
559 
560  for ( int y = tile.top(); y <= tile.bottom(); y++ )
561  {
562  const double ty = yMap.invTransform( y );
563 
564  QRgb *line = reinterpret_cast<QRgb *>( image->scanLine( y ) );
565  line += tile.left();
566 
567  for ( int x = tile.left(); x <= tile.right(); x++ )
568  {
569  const double tx = xMap.invTransform( x );
570 
571  const double value = d_data->data->value( tx, ty );
572 
573  if ( hasGaps && qwtIsNaN( value ) )
574  {
575  *line++ = 0u;
576  }
577  else if ( numColors == 0 )
578  {
579  *line++ = colorMap->rgb( range, value );
580  }
581  else
582  {
583  const uint index = colorMap->colorIndex( numColors, range, value );
584  *line++ = rgbTable[index];
585  }
586  }
587  }
588  }
589  else if ( d_data->colorMap->format() == QwtColorMap::Indexed )
590  {
591  for ( int y = tile.top(); y <= tile.bottom(); y++ )
592  {
593  const double ty = yMap.invTransform( y );
594 
595  unsigned char *line = image->scanLine( y );
596  line += tile.left();
597 
598  for ( int x = tile.left(); x <= tile.right(); x++ )
599  {
600  const double tx = xMap.invTransform( x );
601 
602  const double value = d_data->data->value( tx, ty );
603 
604  if ( hasGaps && qwtIsNaN( value ) )
605  {
606  *line++ = 0;
607  }
608  else
609  {
610  const uint index = d_data->colorMap->colorIndex( 256, range, value );
611  *line++ = static_cast<unsigned char>( index );
612  }
613  }
614  }
615  }
616 }
617 
636  const QRectF &area, const QRect &rect ) const
637 {
638  QSize raster = rect.size() / 2;
639 
640  const QRectF pixelRect = pixelHint( area );
641  if ( !pixelRect.isEmpty() )
642  {
643  const QSize res( qwtCeil( rect.width() / pixelRect.width() ),
644  qwtCeil( rect.height() / pixelRect.height() ) );
645  raster = raster.boundedTo( res );
646  }
647 
648  return raster;
649 }
650 
662  const QRectF &rect, const QSize &raster ) const
663 {
664  if ( d_data->data == NULL )
666 
667  return d_data->data->contourLines( rect, raster,
669 }
670 
681 void QwtPlotSpectrogram::drawContourLines( QPainter *painter,
682  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
683  const QwtRasterData::ContourLines &contourLines ) const
684 {
685  if ( d_data->data == NULL )
686  return;
687 
688  const int numLevels = d_data->contourLevels.size();
689  for ( int l = 0; l < numLevels; l++ )
690  {
691  const double level = d_data->contourLevels[l];
692 
693  QPen pen = defaultContourPen();
694  if ( pen.style() == Qt::NoPen )
695  pen = contourPen( level );
696 
697  if ( pen.style() == Qt::NoPen )
698  continue;
699 
700  painter->setPen( pen );
701 
702  const QPolygonF &lines = contourLines[level];
703  for ( int i = 0; i < lines.size(); i += 2 )
704  {
705  const QPointF p1( xMap.transform( lines[i].x() ),
706  yMap.transform( lines[i].y() ) );
707  const QPointF p2( xMap.transform( lines[i+1].x() ),
708  yMap.transform( lines[i+1].y() ) );
709 
710  QwtPainter::drawLine( painter, p1, p2 );
711  }
712  }
713 }
714 
726 void QwtPlotSpectrogram::draw( QPainter *painter,
727  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
728  const QRectF &canvasRect ) const
729 {
730  if ( d_data->displayMode & ImageMode )
731  QwtPlotRasterItem::draw( painter, xMap, yMap, canvasRect );
732 
733  if ( d_data->displayMode & ContourMode )
734  {
735  // Add some pixels at the borders
736  const int margin = 2;
737  QRectF rasterRect( canvasRect.x() - margin, canvasRect.y() - margin,
738  canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin );
739 
740  QRectF area = QwtScaleMap::invTransform( xMap, yMap, rasterRect );
741 
742  const QRectF br = boundingRect();
743  if ( br.isValid() )
744  {
745  area &= br;
746  if ( area.isEmpty() )
747  return;
748 
749  rasterRect = QwtScaleMap::transform( xMap, yMap, area );
750  }
751 
752  QSize raster = contourRasterSize( area, rasterRect.toRect() );
753  raster = raster.boundedTo( rasterRect.toRect().size() );
754  if ( raster.isValid() )
755  {
756  const QwtRasterData::ContourLines lines =
757  renderContourLines( area, raster );
758 
759  drawContourLines( painter, xMap, yMap, lines );
760  }
761  }
762 }
virtual void discardRaster()
Discard a raster.
virtual void legendChanged()
For QwtPlotSpectrogram.
enum MQTTPropertyCodes value
The data is displayed using contour lines.
FMT_INLINE std::basic_string< Char > format(const S &format_str, Args &&...args)
Definition: core.h:2081
virtual QRectF pixelHint(const QRectF &) const
Pixel hint.
virtual ~QwtPlotSpectrogram()
Destructor.
virtual QVector< QRgb > colorTable256() const
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
Definition: qwt_painter.h:152
A class representing an interval.
Definition: qwt_interval.h:22
A class, which displays raster data.
MQTTClient d
Definition: test10.c:1656
virtual QRectF pixelHint(const QRectF &) const QWT_OVERRIDE
Pixel hint.
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)
long elapsed(START_TIME_TYPE start_time)
Definition: test1.c:233
virtual void initRaster(const QRectF &, const QSize &raster)
Initialize a raster.
virtual int rtti() const QWT_OVERRIDE
QFlags< DisplayMode > DisplayModes
Display modes.
Ignore all vertices on the same level.
bool testConrecFlag(QwtRasterData::ConrecFlag) const
virtual QwtInterval interval(Qt::Axis) const QWT_OVERRIDE
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 void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const QWT_OVERRIDE
Draw the raster data.
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
virtual QRectF boundingRect() const QWT_OVERRIDE
void setColorMap(QwtColorMap *)
virtual void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) const QWT_OVERRIDE
Draw the spectrogram.
void renderTile(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &tile, QImage *) const
Render a tile of an image.
bool isValid() const
Definition: qwt_interval.h:208
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:34
virtual QSize contourRasterSize(const QRectF &, const QRect &) const
Return the raster to be used by the CONREC contour algorithm.
static int sort(lua_State *L)
Definition: ltablib.c:397
QwtRasterData::ConrecFlags conrecFlags
QwtPlotSpectrogram(const QString &title=QString())
const QwtRasterData * data() const
const QwtColorMap * colorMap() const
virtual double value(double x, double y) const =0
virtual QImage renderImage(const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &area, const QSize &imageSize) const QWT_OVERRIDE
Render an image from data and color map.
QwtLinearColorMap builds a color map from color stops.
Definition: qwt_color_map.h:96
A scale map.
Definition: qwt_scale_map.h:26
QList< double > contourLevels() const
double invTransform(double p) const
The map is intended to map into RGB values.
Definition: qwt_color_map.h:45
virtual void itemChanged()
def run()
Definition: mqttsas.py:276
uint renderThreadCount() const
MQTTClient c
Definition: test10.c:1656
float time
Definition: mqtt_test.py:17
QFlags< ConrecFlag > ConrecFlags
Flags to modify the contour algorithm.
bool testAttribute(Attribute) const
QwtRasterData defines an interface to any type of raster data.
#define uchar(c)
Definition: lstrlib.c:40
virtual QRgb rgb(const QwtInterval &interval, double value) const =0
virtual void drawContourLines(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QwtRasterData::ContourLines &) const
static bool qwtIsNaN(double d)
void setItemAttribute(ItemAttribute, bool on=true)
double transform(double s) const
void setContourLevels(const QList< double > &)
double width() const
Return the width of an interval.
Definition: qwt_interval.h:225
Format format() const
void setConrecFlag(QwtRasterData::ConrecFlag, bool on)
bool testDisplayMode(DisplayMode) const
int qwtCeil(qreal value)
Definition: qwt_math.h:262
const QwtText & title() const


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:48:10