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