00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <qimage.h>
00011 #include <qpen.h>
00012 #include <qpainter.h>
00013 #include "qwt_painter.h"
00014 #include "qwt_double_interval.h"
00015 #include "qwt_scale_map.h"
00016 #include "qwt_color_map.h"
00017 #include "qwt_plot_spectrogram.h"
00018
00019 #if QT_VERSION < 0x040000
00020 typedef QValueVector<QRgb> QwtColorTable;
00021 #else
00022 typedef QVector<QRgb> QwtColorTable;
00023 #endif
00024
00025 class QwtPlotSpectrogramImage: public QImage
00026 {
00027
00028 public:
00029 QwtPlotSpectrogramImage(const QSize &size, QwtColorMap::Format format):
00030 #if QT_VERSION < 0x040000
00031 QImage(size, format == QwtColorMap::RGB ? 32 : 8)
00032 #else
00033 QImage(size, format == QwtColorMap::RGB
00034 ? QImage::Format_ARGB32 : QImage::Format_Indexed8 )
00035 #endif
00036 {
00037 }
00038
00039 QwtPlotSpectrogramImage(const QImage &other):
00040 QImage(other)
00041 {
00042 }
00043
00044 void initColorTable(const QImage& other)
00045 {
00046 #if QT_VERSION < 0x040000
00047 const unsigned int numColors = other.numColors();
00048
00049 setNumColors(numColors);
00050 for ( unsigned int i = 0; i < numColors; i++ )
00051 setColor(i, other.color(i));
00052 #else
00053 setColorTable(other.colorTable());
00054 #endif
00055 }
00056
00057 #if QT_VERSION < 0x040000
00058
00059 void setColorTable(const QwtColorTable &colorTable)
00060 {
00061 setNumColors(colorTable.size());
00062 for ( unsigned int i = 0; i < colorTable.size(); i++ )
00063 setColor(i, colorTable[i]);
00064 }
00065
00066 QwtColorTable colorTable() const
00067 {
00068 QwtColorTable table(numColors());
00069 for ( int i = 0; i < numColors(); i++ )
00070 table[i] = color(i);
00071
00072 return table;
00073 }
00074 #endif
00075 };
00076
00077 class QwtPlotSpectrogram::PrivateData
00078 {
00079 public:
00080 class DummyData: public QwtRasterData
00081 {
00082 public:
00083 virtual QwtRasterData *copy() const
00084 {
00085 return new DummyData();
00086 }
00087
00088 virtual double value(double, double) const
00089 {
00090 return 0.0;
00091 }
00092
00093 virtual QwtDoubleInterval range() const
00094 {
00095 return QwtDoubleInterval(0.0, 1.0);
00096 }
00097 };
00098
00099 PrivateData()
00100 {
00101 data = new DummyData();
00102 colorMap = new QwtLinearColorMap();
00103 displayMode = ImageMode;
00104
00105 conrecAttributes = QwtRasterData::IgnoreAllVerticesOnLevel;
00106 conrecAttributes |= QwtRasterData::IgnoreOutOfRange;
00107 }
00108 ~PrivateData()
00109 {
00110 delete data;
00111 delete colorMap;
00112 }
00113
00114 QwtRasterData *data;
00115 QwtColorMap *colorMap;
00116 int displayMode;
00117
00118 QwtValueList contourLevels;
00119 QPen defaultContourPen;
00120 int conrecAttributes;
00121 };
00122
00134 QwtPlotSpectrogram::QwtPlotSpectrogram(const QString &title):
00135 QwtPlotRasterItem(title)
00136 {
00137 d_data = new PrivateData();
00138
00139 setItemAttribute(QwtPlotItem::AutoScale, true);
00140 setItemAttribute(QwtPlotItem::Legend, false);
00141
00142 setZ(8.0);
00143 }
00144
00146 QwtPlotSpectrogram::~QwtPlotSpectrogram()
00147 {
00148 delete d_data;
00149 }
00150
00152 int QwtPlotSpectrogram::rtti() const
00153 {
00154 return QwtPlotItem::Rtti_PlotSpectrogram;
00155 }
00156
00167 void QwtPlotSpectrogram::setDisplayMode(DisplayMode mode, bool on)
00168 {
00169 if ( on != bool(mode & d_data->displayMode) )
00170 {
00171 if ( on )
00172 d_data->displayMode |= mode;
00173 else
00174 d_data->displayMode &= ~mode;
00175 }
00176
00177 itemChanged();
00178 }
00179
00186 bool QwtPlotSpectrogram::testDisplayMode(DisplayMode mode) const
00187 {
00188 return (d_data->displayMode & mode);
00189 }
00190
00202 void QwtPlotSpectrogram::setColorMap(const QwtColorMap &colorMap)
00203 {
00204 delete d_data->colorMap;
00205 d_data->colorMap = colorMap.copy();
00206
00207 invalidateCache();
00208 itemChanged();
00209 }
00210
00215 const QwtColorMap &QwtPlotSpectrogram::colorMap() const
00216 {
00217 return *d_data->colorMap;
00218 }
00219
00230 void QwtPlotSpectrogram::setDefaultContourPen(const QPen &pen)
00231 {
00232 if ( pen != d_data->defaultContourPen )
00233 {
00234 d_data->defaultContourPen = pen;
00235 itemChanged();
00236 }
00237 }
00238
00243 QPen QwtPlotSpectrogram::defaultContourPen() const
00244 {
00245 return d_data->defaultContourPen;
00246 }
00247
00259 QPen QwtPlotSpectrogram::contourPen(double level) const
00260 {
00261 const QwtDoubleInterval intensityRange = d_data->data->range();
00262 const QColor c(d_data->colorMap->rgb(intensityRange, level));
00263
00264 return QPen(c);
00265 }
00266
00276 void QwtPlotSpectrogram::setConrecAttribute(
00277 QwtRasterData::ConrecAttribute attribute, bool on)
00278 {
00279 if ( bool(d_data->conrecAttributes & attribute) == on )
00280 return;
00281
00282 if ( on )
00283 d_data->conrecAttributes |= attribute;
00284 else
00285 d_data->conrecAttributes &= ~attribute;
00286
00287 itemChanged();
00288 }
00289
00299 bool QwtPlotSpectrogram::testConrecAttribute(
00300 QwtRasterData::ConrecAttribute attribute) const
00301 {
00302 return d_data->conrecAttributes & attribute;
00303 }
00304
00313 void QwtPlotSpectrogram::setContourLevels(const QwtValueList &levels)
00314 {
00315 d_data->contourLevels = levels;
00316 #if QT_VERSION >= 0x040000
00317 qSort(d_data->contourLevels);
00318 #else
00319 qHeapSort(d_data->contourLevels);
00320 #endif
00321 itemChanged();
00322 }
00323
00331 QwtValueList QwtPlotSpectrogram::contourLevels() const
00332 {
00333 return d_data->contourLevels;
00334 }
00335
00342 void QwtPlotSpectrogram::setData(const QwtRasterData &data)
00343 {
00344 delete d_data->data;
00345 d_data->data = data.copy();
00346
00347 invalidateCache();
00348 itemChanged();
00349 }
00350
00355 const QwtRasterData &QwtPlotSpectrogram::data() const
00356 {
00357 return *d_data->data;
00358 }
00359
00364 QwtDoubleRect QwtPlotSpectrogram::boundingRect() const
00365 {
00366 return d_data->data->boundingRect();
00367 }
00368
00378 QSize QwtPlotSpectrogram::rasterHint(const QwtDoubleRect &rect) const
00379 {
00380 return d_data->data->rasterHint(rect);
00381 }
00382
00400 QImage QwtPlotSpectrogram::renderImage(
00401 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00402 const QwtDoubleRect &area) const
00403 {
00404 if ( area.isEmpty() )
00405 return QImage();
00406
00407 QRect rect = transform(xMap, yMap, area);
00408
00409 QwtScaleMap xxMap = xMap;
00410 QwtScaleMap yyMap = yMap;
00411
00412 const QSize res = d_data->data->rasterHint(area);
00413 if ( res.isValid() )
00414 {
00415
00416
00417
00418
00419
00420
00421 rect.setSize(rect.size().boundedTo(res));
00422
00423 int px1 = rect.x();
00424 int px2 = rect.x() + rect.width();
00425 if ( xMap.p1() > xMap.p2() )
00426 qSwap(px1, px2);
00427
00428 double sx1 = area.x();
00429 double sx2 = area.x() + area.width();
00430 if ( xMap.s1() > xMap.s2() )
00431 qSwap(sx1, sx2);
00432
00433 int py1 = rect.y();
00434 int py2 = rect.y() + rect.height();
00435 if ( yMap.p1() > yMap.p2() )
00436 qSwap(py1, py2);
00437
00438 double sy1 = area.y();
00439 double sy2 = area.y() + area.height();
00440 if ( yMap.s1() > yMap.s2() )
00441 qSwap(sy1, sy2);
00442
00443 xxMap.setPaintInterval(px1, px2);
00444 xxMap.setScaleInterval(sx1, sx2);
00445 yyMap.setPaintInterval(py1, py2);
00446 yyMap.setScaleInterval(sy1, sy2);
00447 }
00448
00449 QwtPlotSpectrogramImage image(rect.size(), d_data->colorMap->format());
00450
00451 const QwtDoubleInterval intensityRange = d_data->data->range();
00452 if ( !intensityRange.isValid() )
00453 return image;
00454
00455 d_data->data->initRaster(area, rect.size());
00456
00457 if ( d_data->colorMap->format() == QwtColorMap::RGB )
00458 {
00459 for ( int y = rect.top(); y <= rect.bottom(); y++ )
00460 {
00461 const double ty = yyMap.invTransform(y);
00462
00463 QRgb *line = (QRgb *)image.scanLine(y - rect.top());
00464 for ( int x = rect.left(); x <= rect.right(); x++ )
00465 {
00466 const double tx = xxMap.invTransform(x);
00467
00468 *line++ = d_data->colorMap->rgb(intensityRange,
00469 d_data->data->value(tx, ty));
00470 }
00471 }
00472 }
00473 else if ( d_data->colorMap->format() == QwtColorMap::Indexed )
00474 {
00475 image.setColorTable(d_data->colorMap->colorTable(intensityRange));
00476
00477 for ( int y = rect.top(); y <= rect.bottom(); y++ )
00478 {
00479 const double ty = yyMap.invTransform(y);
00480
00481 unsigned char *line = image.scanLine(y - rect.top());
00482 for ( int x = rect.left(); x <= rect.right(); x++ )
00483 {
00484 const double tx = xxMap.invTransform(x);
00485
00486 *line++ = d_data->colorMap->colorIndex(intensityRange,
00487 d_data->data->value(tx, ty));
00488 }
00489 }
00490 }
00491
00492 d_data->data->discardRaster();
00493
00494
00495
00496 const bool hInvert = xxMap.p1() > xxMap.p2();
00497 const bool vInvert = yyMap.p1() < yyMap.p2();
00498 if ( hInvert || vInvert )
00499 {
00500 #ifdef __GNUC__
00501 #endif
00502 #if QT_VERSION < 0x040000
00503 image = image.mirror(hInvert, vInvert);
00504 #else
00505 image = image.mirrored(hInvert, vInvert);
00506 #endif
00507 }
00508
00509 return image;
00510 }
00511
00529 QSize QwtPlotSpectrogram::contourRasterSize(const QwtDoubleRect &area,
00530 const QRect &rect) const
00531 {
00532 QSize raster = rect.size() / 2;
00533
00534 const QSize rasterHint = d_data->data->rasterHint(area);
00535 if ( rasterHint.isValid() )
00536 raster = raster.boundedTo(rasterHint);
00537
00538 return raster;
00539 }
00540
00549 QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines(
00550 const QwtDoubleRect &rect, const QSize &raster) const
00551 {
00552 return d_data->data->contourLines(rect, raster,
00553 d_data->contourLevels, d_data->conrecAttributes );
00554 }
00555
00566 void QwtPlotSpectrogram::drawContourLines(QPainter *painter,
00567 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00568 const QwtRasterData::ContourLines &contourLines) const
00569 {
00570 const QwtDoubleInterval intensityRange = d_data->data->range();
00571
00572 const int numLevels = (int)d_data->contourLevels.size();
00573 for (int l = 0; l < numLevels; l++)
00574 {
00575 const double level = d_data->contourLevels[l];
00576
00577 QPen pen = defaultContourPen();
00578 if ( pen.style() == Qt::NoPen )
00579 pen = contourPen(level);
00580
00581 if ( pen.style() == Qt::NoPen )
00582 continue;
00583
00584 painter->setPen(pen);
00585
00586 #if QT_VERSION >= 0x040000
00587 const QPolygonF &lines = contourLines[level];
00588 #else
00589 const QwtArray<QwtDoublePoint> &lines = contourLines[level];
00590 #endif
00591 for ( int i = 0; i < (int)lines.size(); i += 2 )
00592 {
00593 const QPoint p1( xMap.transform(lines[i].x()),
00594 yMap.transform(lines[i].y()) );
00595 const QPoint p2( xMap.transform(lines[i+1].x()),
00596 yMap.transform(lines[i+1].y()) );
00597
00598 QwtPainter::drawLine(painter, p1, p2);
00599 }
00600 }
00601 }
00602
00615 void QwtPlotSpectrogram::draw(QPainter *painter,
00616 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00617 const QRect &canvasRect) const
00618 {
00619 if ( d_data->displayMode & ImageMode )
00620 QwtPlotRasterItem::draw(painter, xMap, yMap, canvasRect);
00621
00622 if ( d_data->displayMode & ContourMode )
00623 {
00624
00625 const int margin = 2;
00626 QRect rasterRect(canvasRect.x() - margin, canvasRect.y() - margin,
00627 canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin);
00628
00629 QwtDoubleRect area = invTransform(xMap, yMap, rasterRect);
00630
00631 const QwtDoubleRect br = boundingRect();
00632 if ( br.isValid() && br.contains(area) )
00633 {
00634 area &= br;
00635 rasterRect = transform(xMap, yMap, area);
00636 }
00637
00638 QSize raster = contourRasterSize(area, rasterRect);
00639 raster = raster.boundedTo(rasterRect.size());
00640 if ( raster.isValid() )
00641 {
00642 const QwtRasterData::ContourLines lines =
00643 renderContourLines(area, raster);
00644
00645 drawContourLines(painter, xMap, yMap, lines);
00646 }
00647 }
00648 }
00649