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
00277 void QwtPlotSpectrogram::setConrecAttribute(
00278 QwtRasterData::ConrecAttribute attribute, bool on)
00279 {
00280 if ( bool(d_data->conrecAttributes & attribute) == on )
00281 return;
00282
00283 if ( on )
00284 d_data->conrecAttributes |= attribute;
00285 else
00286 d_data->conrecAttributes &= ~attribute;
00287
00288 itemChanged();
00289 }
00290
00301 bool QwtPlotSpectrogram::testConrecAttribute(
00302 QwtRasterData::ConrecAttribute attribute) const
00303 {
00304 return d_data->conrecAttributes & attribute;
00305 }
00306
00316 void QwtPlotSpectrogram::setContourLevels(const QwtValueList &levels)
00317 {
00318 d_data->contourLevels = levels;
00319 #if QT_VERSION >= 0x040000
00320 qSort(d_data->contourLevels);
00321 #else
00322 qHeapSort(d_data->contourLevels);
00323 #endif
00324 itemChanged();
00325 }
00326
00335 QwtValueList QwtPlotSpectrogram::contourLevels() const
00336 {
00337 return d_data->contourLevels;
00338 }
00339
00346 void QwtPlotSpectrogram::setData(const QwtRasterData &data)
00347 {
00348 delete d_data->data;
00349 d_data->data = data.copy();
00350
00351 invalidateCache();
00352 itemChanged();
00353 }
00354
00359 const QwtRasterData &QwtPlotSpectrogram::data() const
00360 {
00361 return *d_data->data;
00362 }
00363
00368 QwtDoubleRect QwtPlotSpectrogram::boundingRect() const
00369 {
00370 return d_data->data->boundingRect();
00371 }
00372
00382 QSize QwtPlotSpectrogram::rasterHint(const QwtDoubleRect &rect) const
00383 {
00384 return d_data->data->rasterHint(rect);
00385 }
00386
00404 QImage QwtPlotSpectrogram::renderImage(
00405 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00406 const QwtDoubleRect &area) const
00407 {
00408 if ( area.isEmpty() )
00409 return QImage();
00410
00411 QRect rect = transform(xMap, yMap, area);
00412
00413 QwtScaleMap xxMap = xMap;
00414 QwtScaleMap yyMap = yMap;
00415
00416 const QSize res = d_data->data->rasterHint(area);
00417 if ( res.isValid() )
00418 {
00419
00420
00421
00422
00423
00424
00425 rect.setSize(rect.size().boundedTo(res));
00426
00427 int px1 = rect.x();
00428 int px2 = rect.x() + rect.width();
00429 if ( xMap.p1() > xMap.p2() )
00430 qSwap(px1, px2);
00431
00432 double sx1 = area.x();
00433 double sx2 = area.x() + area.width();
00434 if ( xMap.s1() > xMap.s2() )
00435 qSwap(sx1, sx2);
00436
00437 int py1 = rect.y();
00438 int py2 = rect.y() + rect.height();
00439 if ( yMap.p1() > yMap.p2() )
00440 qSwap(py1, py2);
00441
00442 double sy1 = area.y();
00443 double sy2 = area.y() + area.height();
00444 if ( yMap.s1() > yMap.s2() )
00445 qSwap(sy1, sy2);
00446
00447 xxMap.setPaintInterval(px1, px2);
00448 xxMap.setScaleInterval(sx1, sx2);
00449 yyMap.setPaintInterval(py1, py2);
00450 yyMap.setScaleInterval(sy1, sy2);
00451 }
00452
00453 QwtPlotSpectrogramImage image(rect.size(), d_data->colorMap->format());
00454
00455 const QwtDoubleInterval intensityRange = d_data->data->range();
00456 if ( !intensityRange.isValid() )
00457 return image;
00458
00459 d_data->data->initRaster(area, rect.size());
00460
00461 if ( d_data->colorMap->format() == QwtColorMap::RGB )
00462 {
00463 for ( int y = rect.top(); y <= rect.bottom(); y++ )
00464 {
00465 const double ty = yyMap.invTransform(y);
00466
00467 QRgb *line = (QRgb *)image.scanLine(y - rect.top());
00468 for ( int x = rect.left(); x <= rect.right(); x++ )
00469 {
00470 const double tx = xxMap.invTransform(x);
00471
00472 *line++ = d_data->colorMap->rgb(intensityRange,
00473 d_data->data->value(tx, ty));
00474 }
00475 }
00476 }
00477 else if ( d_data->colorMap->format() == QwtColorMap::Indexed )
00478 {
00479 image.setColorTable(d_data->colorMap->colorTable(intensityRange));
00480
00481 for ( int y = rect.top(); y <= rect.bottom(); y++ )
00482 {
00483 const double ty = yyMap.invTransform(y);
00484
00485 unsigned char *line = image.scanLine(y - rect.top());
00486 for ( int x = rect.left(); x <= rect.right(); x++ )
00487 {
00488 const double tx = xxMap.invTransform(x);
00489
00490 *line++ = d_data->colorMap->colorIndex(intensityRange,
00491 d_data->data->value(tx, ty));
00492 }
00493 }
00494 }
00495
00496 d_data->data->discardRaster();
00497
00498
00499
00500 const bool hInvert = xxMap.p1() > xxMap.p2();
00501 const bool vInvert = yyMap.p1() < yyMap.p2();
00502 if ( hInvert || vInvert )
00503 {
00504 #ifdef __GNUC__
00505 #endif
00506 #if QT_VERSION < 0x040000
00507 image = image.mirror(hInvert, vInvert);
00508 #else
00509 image = image.mirrored(hInvert, vInvert);
00510 #endif
00511 }
00512
00513 return image;
00514 }
00515
00533 QSize QwtPlotSpectrogram::contourRasterSize(const QwtDoubleRect &area,
00534 const QRect &rect) const
00535 {
00536 QSize raster = rect.size() / 2;
00537
00538 const QSize rasterHint = d_data->data->rasterHint(area);
00539 if ( rasterHint.isValid() )
00540 raster = raster.boundedTo(rasterHint);
00541
00542 return raster;
00543 }
00544
00554 QwtRasterData::ContourLines QwtPlotSpectrogram::renderContourLines(
00555 const QwtDoubleRect &rect, const QSize &raster) const
00556 {
00557 return d_data->data->contourLines(rect, raster,
00558 d_data->contourLevels, d_data->conrecAttributes );
00559 }
00560
00571 void QwtPlotSpectrogram::drawContourLines(QPainter *painter,
00572 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00573 const QwtRasterData::ContourLines &contourLines) const
00574 {
00575 const QwtDoubleInterval intensityRange = d_data->data->range();
00576
00577 const int numLevels = (int)d_data->contourLevels.size();
00578 for (int l = 0; l < numLevels; l++)
00579 {
00580 const double level = d_data->contourLevels[l];
00581
00582 QPen pen = defaultContourPen();
00583 if ( pen.style() == Qt::NoPen )
00584 pen = contourPen(level);
00585
00586 if ( pen.style() == Qt::NoPen )
00587 continue;
00588
00589 painter->setPen(QwtPainter::scaledPen(pen));
00590
00591 #if QT_VERSION >= 0x040000
00592 const QPolygonF &lines = contourLines[level];
00593 #else
00594 const QwtArray<QwtDoublePoint> &lines = contourLines[level];
00595 #endif
00596 for ( int i = 0; i < (int)lines.size(); i += 2 )
00597 {
00598 const QPoint p1( xMap.transform(lines[i].x()),
00599 yMap.transform(lines[i].y()) );
00600 const QPoint p2( xMap.transform(lines[i+1].x()),
00601 yMap.transform(lines[i+1].y()) );
00602
00603 QwtPainter::drawLine(painter, p1, p2);
00604 }
00605 }
00606 }
00607
00620 void QwtPlotSpectrogram::draw(QPainter *painter,
00621 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00622 const QRect &canvasRect) const
00623 {
00624 if ( d_data->displayMode & ImageMode )
00625 QwtPlotRasterItem::draw(painter, xMap, yMap, canvasRect);
00626
00627 if ( d_data->displayMode & ContourMode )
00628 {
00629
00630 const int margin = 2;
00631 QRect rasterRect(canvasRect.x() - margin, canvasRect.y() - margin,
00632 canvasRect.width() + 2 * margin, canvasRect.height() + 2 * margin);
00633
00634 QwtDoubleRect area = invTransform(xMap, yMap, rasterRect);
00635
00636 const QwtDoubleRect br = boundingRect();
00637 if ( br.isValid() )
00638 {
00639 area &= br;
00640 if ( area.isEmpty() )
00641 return;
00642
00643 rasterRect = transform(xMap, yMap, area);
00644 }
00645
00646 QSize raster = contourRasterSize(area, rasterRect);
00647 raster = raster.boundedTo(rasterRect.size());
00648 if ( raster.isValid() )
00649 {
00650 const QwtRasterData::ContourLines lines =
00651 renderContourLines(area, raster);
00652
00653 drawContourLines(painter, xMap, yMap, lines);
00654 }
00655 }
00656 }
00657