Colour3DPlotLayer.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "Colour3DPlotLayer.h"
00017 
00018 #include "view/View.h"
00019 #include "base/Profiler.h"
00020 #include "base/LogRange.h"
00021 #include "base/ColourMapper.h"
00022 
00023 #include <QPainter>
00024 #include <QImage>
00025 #include <QRect>
00026 #include <QTextStream>
00027 
00028 #include <iostream>
00029 
00030 #include <cassert>
00031 
00032 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
00033 
00034 
00035 Colour3DPlotLayer::Colour3DPlotLayer() :
00036     m_model(0),
00037     m_cache(0),
00038     m_cacheStart(0),
00039     m_colourScale(LinearScale),
00040     m_colourMap(0),
00041     m_normalizeColumns(false),
00042     m_normalizeVisibleArea(false),
00043     m_invertVertical(false)
00044 {
00045     
00046 }
00047 
00048 Colour3DPlotLayer::~Colour3DPlotLayer()
00049 {
00050 }
00051 
00052 void
00053 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
00054 {
00055     if (m_model == model) return;
00056     const DenseThreeDimensionalModel *oldModel = m_model;
00057     m_model = model;
00058     if (!m_model || !m_model->isOK()) return;
00059 
00060     connectSignals(m_model);
00061 
00062     connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid()));
00063     connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
00064             this, SLOT(cacheInvalid(size_t, size_t)));
00065 
00066     emit modelReplaced();
00067     emit sliceableModelReplaced(oldModel, model);
00068 }
00069 
00070 void
00071 Colour3DPlotLayer::cacheInvalid()
00072 {
00073     delete m_cache; 
00074     m_cache = 0;
00075 }
00076 
00077 void
00078 Colour3DPlotLayer::cacheInvalid(size_t, size_t)
00079 {
00080     cacheInvalid();
00081 }
00082 
00083 Layer::PropertyList
00084 Colour3DPlotLayer::getProperties() const
00085 {
00086     PropertyList list;
00087     list.push_back("Colour");
00088     list.push_back("Colour Scale");
00089     list.push_back("Normalize Columns");
00090     list.push_back("Normalize Visible Area");
00091     list.push_back("Invert Vertical Scale");
00092     return list;
00093 }
00094 
00095 QString
00096 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
00097 {
00098     if (name == "Colour") return tr("Colour");
00099     if (name == "Colour Scale") return tr("Scale");
00100     if (name == "Normalize Columns") return tr("Normalize Columns");
00101     if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
00102     if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
00103     return "";
00104 }
00105 
00106 QString
00107 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
00108 {
00109     if (name == "Normalize Columns") return "normalise-columns";
00110     if (name == "Normalize Visible Area") return "normalise";
00111     if (name == "Invert Vertical Scale") return "invert-vertical";
00112     return "";
00113 }
00114 
00115 Layer::PropertyType
00116 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
00117 {
00118     if (name == "Normalize Columns") return ToggleProperty;
00119     if (name == "Normalize Visible Area") return ToggleProperty;
00120     if (name == "Invert Vertical Scale") return ToggleProperty;
00121     return ValueProperty;
00122 }
00123 
00124 QString
00125 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
00126 {
00127     if (name == "Normalize Columns" ||
00128         name == "Normalize Visible Area" ||
00129         name == "Invert Vertical Scale" ||
00130         name == "Colour Scale") return tr("Scale");
00131     return QString();
00132 }
00133 
00134 int
00135 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name,
00136                                             int *min, int *max, int *deflt) const
00137 {
00138     int val = 0;
00139 
00140     int garbage0, garbage1, garbage2;
00141     if (!min) min = &garbage0;
00142     if (!max) max = &garbage1;
00143     if (!deflt) deflt = &garbage2;
00144 
00145     if (name == "Colour Scale") {
00146 
00147         *min = 0;
00148         *max = 2;
00149         *deflt = (int)LinearScale;
00150 
00151         val = (int)m_colourScale;
00152 
00153     } else if (name == "Colour") {
00154 
00155         *min = 0;
00156         *max = ColourMapper::getColourMapCount() - 1;
00157         *deflt = 0;
00158 
00159         val = m_colourMap;
00160 
00161     } else if (name == "Normalize Columns") {
00162         
00163         *deflt = 0;
00164         val = (m_normalizeColumns ? 1 : 0);
00165 
00166     } else if (name == "Normalize Visible Area") {
00167         
00168         *deflt = 0;
00169         val = (m_normalizeVisibleArea ? 1 : 0);
00170 
00171     } else if (name == "Invert Vertical Scale") {
00172         
00173         *deflt = 0;
00174         val = (m_invertVertical ? 1 : 0);
00175 
00176     } else {
00177         val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
00178     }
00179 
00180     return val;
00181 }
00182 
00183 QString
00184 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name,
00185                                     int value) const
00186 {
00187     if (name == "Colour") {
00188         return ColourMapper::getColourMapName(value);
00189     }
00190     if (name == "Colour Scale") {
00191         switch (value) {
00192         default:
00193         case 0: return tr("Linear");
00194         case 1: return tr("Log");
00195         case 2: return tr("+/-1");
00196         }
00197     }
00198     return tr("<unknown>");
00199 }
00200 
00201 void
00202 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
00203 {
00204     if (name == "Colour Scale") {
00205         switch (value) {
00206         default:
00207         case 0: setColourScale(LinearScale); break;
00208         case 1: setColourScale(LogScale); break;
00209         case 2: setColourScale(PlusMinusOneScale); break;
00210         }
00211     } else if (name == "Colour") {
00212         setColourMap(value);
00213     } else if (name == "Normalize Columns") {
00214         setNormalizeColumns(value ? true : false);
00215     } else if (name == "Normalize Visible Area") {
00216         setNormalizeVisibleArea(value ? true : false);
00217     } else if (name == "Invert Vertical Scale") {
00218         setInvertVertical(value ? true : false);
00219     }
00220 }
00221 
00222 void
00223 Colour3DPlotLayer::setColourScale(ColourScale scale)
00224 {
00225     if (m_colourScale == scale) return;
00226     m_colourScale = scale;
00227     cacheInvalid();
00228     emit layerParametersChanged();
00229 }
00230 
00231 void
00232 Colour3DPlotLayer::setColourMap(int map)
00233 {
00234     if (m_colourMap == map) return;
00235     m_colourMap = map;
00236     cacheInvalid();
00237     emit layerParametersChanged();
00238 }
00239 
00240 void
00241 Colour3DPlotLayer::setNormalizeColumns(bool n)
00242 {
00243     if (m_normalizeColumns == n) return;
00244     m_normalizeColumns = n;
00245     cacheInvalid();
00246     emit layerParametersChanged();
00247 }
00248 
00249 bool
00250 Colour3DPlotLayer::getNormalizeColumns() const
00251 {
00252     return m_normalizeColumns;
00253 }
00254 
00255 void
00256 Colour3DPlotLayer::setNormalizeVisibleArea(bool n)
00257 {
00258     if (m_normalizeVisibleArea == n) return;
00259     m_normalizeVisibleArea = n;
00260     cacheInvalid();
00261     emit layerParametersChanged();
00262 }
00263 
00264 bool
00265 Colour3DPlotLayer::getNormalizeVisibleArea() const
00266 {
00267     return m_normalizeVisibleArea;
00268 }
00269 
00270 void
00271 Colour3DPlotLayer::setInvertVertical(bool n)
00272 {
00273     if (m_invertVertical == n) return;
00274     m_invertVertical = n;
00275     cacheInvalid();
00276     emit layerParametersChanged();
00277 }
00278 
00279 bool
00280 Colour3DPlotLayer::getInvertVertical() const
00281 {
00282     return m_invertVertical;
00283 }
00284 
00285 bool
00286 Colour3DPlotLayer::isLayerScrollable(const View *v) const
00287 {
00288     if (m_normalizeVisibleArea) return false;
00289     QPoint discard;
00290     return !v->shouldIlluminateLocalFeatures(this, discard);
00291 }
00292 
00293 QString
00294 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const
00295 {
00296     if (!m_model) return "";
00297 
00298     int x = pos.x();
00299     int y = pos.y();
00300 
00301     size_t modelStart = m_model->getStartFrame();
00302     size_t modelResolution = m_model->getResolution();
00303 
00304     float srRatio =
00305         float(v->getViewManager()->getMainModelSampleRate()) /
00306         float(m_model->getSampleRate());
00307 
00308     int sx0 = int((v->getFrameForX(x) / srRatio - long(modelStart)) /
00309                   long(modelResolution));
00310 
00311     int f0 = sx0 * modelResolution;
00312     int f1 =  f0 + modelResolution;
00313 
00314     float binHeight = float(v->height()) / m_model->getHeight();
00315     int sy = int((v->height() - y) / binHeight);
00316 
00317     if (m_invertVertical) sy = m_model->getHeight() - sy - 1;
00318 
00319     float value = m_model->getValueAt(sx0, sy);
00320 
00321 //    std::cerr << "bin value (" << sx0 << "," << sy << ") is " << value << std::endl;
00322     
00323     QString binName = m_model->getBinName(sy);
00324     if (binName == "") binName = QString("[%1]").arg(sy + 1);
00325     else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
00326 
00327     QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
00328         .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
00329              .toText(true).c_str())
00330         .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
00331              .toText(true).c_str())
00332         .arg(binName)
00333         .arg(value);
00334 
00335     return text;
00336 }
00337 
00338 int
00339 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const
00340 {
00341     int cw = 20;
00342     return cw;
00343 }
00344 
00345 int
00346 Colour3DPlotLayer::getVerticalScaleWidth(View *, QPainter &paint) const
00347 {
00348     if (!m_model) return 0;
00349 
00350     QString sampleText = QString("[%1]").arg(m_model->getHeight());
00351     int tw = paint.fontMetrics().width(sampleText);
00352     bool another = false;
00353 
00354     for (size_t i = 0; i < m_model->getHeight(); ++i) {
00355         if (m_model->getBinName(i).length() > sampleText.length()) {
00356             sampleText = m_model->getBinName(i);
00357             another = true;
00358         }
00359     }
00360     if (another) {
00361         tw = std::max(tw, paint.fontMetrics().width(sampleText));
00362     }
00363 
00364     return tw + 13 + getColourScaleWidth(paint);
00365 }
00366 
00367 void
00368 Colour3DPlotLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
00369 {
00370     if (!m_model) return;
00371 
00372     int h = rect.height(), w = rect.width();
00373     float binHeight = float(v->height()) / m_model->getHeight();
00374 
00375     int cw = getColourScaleWidth(paint);
00376     
00377     int ch = h - 20;
00378     if (ch > 20 && m_cache) {
00379 
00380         paint.setPen(v->getForeground());
00381         paint.drawRect(4, 10, cw - 8, ch - 19);
00382 
00383         for (int y = 0; y < ch - 20; ++y) {
00384             QRgb c = m_cache->color(((ch - 20 - y) * 255) / (ch - 20));
00385 //            std::cerr << "y = " << y << ": rgb " << qRed(c) << "," << qGreen(c) << "," << qBlue(c) << std::endl;
00386             paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c)));
00387             paint.drawLine(5, 11 + y, cw - 5, 11 + y);
00388         }
00389     }
00390 
00391     paint.setPen(v->getForeground());
00392 
00393     int count = v->height() / paint.fontMetrics().height();
00394     int step = m_model->getHeight() / count;
00395     if (step == 0) step = 1;
00396 
00397     for (size_t i = 0; i < m_model->getHeight(); ++i) {
00398 
00399         size_t idx = i;
00400         if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
00401 
00402         if ((idx % step) != 0) continue;
00403 
00404         int y0 = int(v->height() - (i * binHeight) - 1);
00405         
00406         QString text = m_model->getBinName(idx);
00407         if (text == "") text = QString("[%1]").arg(idx + 1);
00408 
00409         paint.drawLine(cw, y0, w, y0);
00410 
00411         int cy = int(y0 - (step * binHeight)/2);
00412         int ty = cy + paint.fontMetrics().ascent()/2;
00413 
00414         paint.drawText(cw + 5, ty, text);
00415     }
00416 }
00417 
00418 void
00419 Colour3DPlotLayer::getColumn(size_t col,
00420                              DenseThreeDimensionalModel::Column &values) const
00421 {
00422     m_model->getColumn(col, values);
00423 
00424     float colMax = 0.f, colMin = 0.f;
00425 
00426     float min = 0.f, max = 0.f;
00427     if (m_normalizeColumns) {
00428         min = m_model->getMinimumLevel();
00429         max = m_model->getMaximumLevel();
00430     }
00431 
00432     if (m_normalizeColumns) {
00433         for (size_t y = 0; y < values.size(); ++y) {
00434             if (y == 0 || values[y] > colMax) colMax = values[y];
00435             if (y == 0 || values[y] < colMin) colMin = values[y];
00436         }
00437         if (colMin == colMax) colMax = colMin + 1;
00438     }
00439     
00440     for (size_t y = 0; y < values.size(); ++y) {
00441         
00442         float value = min;
00443 
00444         value = values[y];
00445 
00446         if (m_normalizeColumns) {
00447             float norm = (value - colMin) / (colMax - colMin);
00448             value = min + (max - min) * norm;
00449         }
00450 
00451         values[y] = value;
00452     }    
00453 }
00454     
00455 void
00456 Colour3DPlotLayer::fillCache(size_t firstBin, size_t lastBin) const
00457 {
00458     size_t modelStart = m_model->getStartFrame();
00459     size_t modelEnd = m_model->getEndFrame();
00460     size_t modelResolution = m_model->getResolution();
00461 
00462 //    std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl;
00463 
00464     if (!m_normalizeVisibleArea || m_normalizeColumns) {
00465         firstBin = modelStart / modelResolution;
00466         lastBin = modelEnd / modelResolution;
00467     }
00468 
00469     size_t cacheWidth = lastBin - firstBin + 1;
00470     size_t cacheHeight = m_model->getHeight();
00471 
00472     if (m_cache &&
00473         (m_cacheStart != firstBin ||
00474          m_cache->width() != int(cacheWidth) ||
00475          m_cache->height() != int(cacheHeight))) {
00476 
00477         delete m_cache;
00478         m_cache = 0;
00479     }
00480 
00481     if (m_cache) return;
00482 
00483     m_cache = new QImage(cacheWidth, cacheHeight, QImage::Format_Indexed8);
00484     m_cacheStart = firstBin;
00485 
00486 //    std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " starting " << m_cacheStart << std::endl;
00487 
00488     m_cache->setNumColors(256);
00489     DenseThreeDimensionalModel::Column values;
00490 
00491     float min = m_model->getMinimumLevel();
00492     float max = m_model->getMaximumLevel();
00493 
00494     if (m_colourScale == LogScale) {
00495         LogRange::mapRange(min, max);
00496     } else if (m_colourScale == PlusMinusOneScale) {
00497         min = -1.f;
00498         max = 1.f;
00499     }
00500     
00501     if (max == min) max = min + 1.0;
00502     
00503     ColourMapper mapper(m_colourMap, 0.f, 255.f);
00504     
00505     for (int index = 0; index < 256; ++index) {
00506         
00507         QColor colour = mapper.map(index);
00508         m_cache->setColor(index, qRgb(colour.red(), colour.green(), colour.blue()));
00509     }
00510     
00511     m_cache->fill(0);
00512 
00513     float visibleMax = 0.f, visibleMin = 0.f;
00514 
00515     if (m_normalizeVisibleArea && !m_normalizeColumns) {
00516         
00517         for (size_t c = firstBin; c <= lastBin; ++c) {
00518         
00519             values.clear();
00520             getColumn(c, values);
00521 
00522             float colMax = 0.f, colMin = 0.f;
00523 
00524             for (size_t y = 0; y < m_model->getHeight(); ++y) {
00525                 if (y >= values.size()) break;
00526                 if (y == 0 || values[y] > colMax) colMax = values[y];
00527                 if (y == 0 || values[y] < colMin) colMin = values[y];
00528             }
00529 
00530             if (c == firstBin || colMax > visibleMax) visibleMax = colMax;
00531             if (c == firstBin || colMin < visibleMin) visibleMin = colMin;
00532         }
00533     }
00534     
00535     if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
00536 
00537     for (size_t c = firstBin; c <= lastBin; ++c) {
00538         
00539         values.clear();
00540         getColumn(c, values);
00541 
00542         for (size_t y = 0; y < m_model->getHeight(); ++y) {
00543 
00544             float value = min;
00545             if (y < values.size()) {
00546                 value = values[y];
00547             }
00548             
00549             if (m_normalizeVisibleArea && !m_normalizeColumns) {
00550                 float norm = (value - visibleMin) / (visibleMax - visibleMin);
00551                 value = min + (max - min) * norm;
00552             }
00553 
00554             if (m_colourScale == LogScale) {
00555                 value = LogRange::map(value);
00556             }
00557 
00558             int pixel = int(((value - min) * 256) / (max - min));
00559             if (pixel < 0) pixel = 0;
00560             if (pixel > 255) pixel = 255;
00561 
00562             if (m_invertVertical) {
00563                 m_cache->setPixel(c - firstBin, m_model->getHeight() - y - 1,
00564                                   pixel);
00565             } else {
00566                 m_cache->setPixel(c - firstBin, y, pixel);
00567             }
00568         }
00569     }
00570 }
00571 
00572 void
00573 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const
00574 {
00575 //    Profiler profiler("Colour3DPlotLayer::paint");
00576 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00577     std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl;
00578 #endif
00579 
00580     int completion = 0;
00581     if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
00582         if (completion > 0) {
00583             paint.fillRect(0, 10, v->width() * completion / 100,
00584                            10, QColor(120, 120, 120));
00585         }
00586         return;
00587     }
00588 
00589     if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect();
00590 
00591     size_t modelStart = m_model->getStartFrame();
00592     size_t modelEnd = m_model->getEndFrame();
00593     size_t modelResolution = m_model->getResolution();
00594 
00595     // The cache is from the model's start frame to the model's end
00596     // frame at the model's window increment frames per pixel.  We
00597     // want to draw from our start frame + x0 * zoomLevel to our start
00598     // frame + x1 * zoomLevel at zoomLevel frames per pixel.
00599 
00600     //  We have quite different paint mechanisms for rendering "large"
00601     //  bins (more than one bin per pixel in both directions) and
00602     //  "small".  This is "large"; see paintDense below for "small".
00603 
00604     int x0 = rect.left();
00605     int x1 = rect.right() + 1;
00606 
00607     int h = v->height();
00608 
00609     float srRatio =
00610         float(v->getViewManager()->getMainModelSampleRate()) /
00611         float(m_model->getSampleRate());
00612 
00613     int sx0 = int((v->getFrameForX(x0) / srRatio - long(modelStart))
00614                   / long(modelResolution));
00615     int sx1 = int((v->getFrameForX(x1) / srRatio - long(modelStart))
00616                   / long(modelResolution));
00617     int sh = m_model->getHeight();
00618 
00619     if (sx0 > 0) --sx0;
00620     fillCache(sx0 < 0 ? 0 : sx0,
00621               sx1 < 0 ? 0 : sx1);
00622 
00623 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00624     std::cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << std::endl;
00625 #endif
00626 
00627     if (int(m_model->getHeight()) >= v->height() ||
00628         int(modelResolution * m_model->getSampleRate()) < v->getZoomLevel() / 2) {
00629 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00630         std::cerr << "calling paintDense" << std::endl;
00631 #endif
00632         paintDense(v, paint, rect);
00633         return;
00634     }
00635 
00636 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00637     std::cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << std::endl;
00638     std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << std::endl;
00639 #endif
00640 
00641     QPoint illuminatePos;
00642     bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
00643     char labelbuf[10];
00644 
00645     for (int sx = sx0; sx <= sx1; ++sx) {
00646 
00647         int scx = 0;
00648         if (sx > int(m_cacheStart)) scx = sx - m_cacheStart;
00649         
00650         int fx = sx * int(modelResolution);
00651 
00652         if (fx + int(modelResolution) <= int(modelStart) ||
00653             fx > int(modelEnd)) continue;
00654 
00655         int rx0 = v->getXForFrame(int((fx + int(modelStart)) * srRatio));
00656         int rx1 = v->getXForFrame(int((fx + int(modelStart) + int(modelResolution) + 1) * srRatio));
00657 
00658         int rw = rx1 - rx0;
00659         if (rw < 1) rw = 1;
00660 
00661         bool showLabel = (rw > 10 &&
00662                           paint.fontMetrics().width("0.000000") < rw - 3 &&
00663                           paint.fontMetrics().height() < (h / sh));
00664         
00665         for (int sy = 0; sy < sh; ++sy) {
00666 
00667             int ry0 = h - (sy * h) / sh - 1;
00668             QRgb pixel = qRgb(255, 255, 255);
00669             if (scx >= 0 && scx < m_cache->width() &&
00670                 sy >= 0 && sy < m_cache->height()) {
00671                 pixel = m_cache->pixel(scx, sy);
00672             }
00673 
00674             QRect r(rx0, ry0 - h / sh - 1, rw, h / sh + 1);
00675 
00676             if (rw == 1) {
00677                 paint.setPen(pixel);
00678                 paint.setBrush(Qt::NoBrush);
00679                 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
00680                 continue;
00681             }
00682 
00683             QColor pen(255, 255, 255, 80);
00684             QColor brush(pixel);
00685 
00686             if (rw > 3 && r.height() > 3) {
00687                 brush.setAlpha(160);
00688             }
00689 
00690             paint.setPen(Qt::NoPen);
00691             paint.setBrush(brush);
00692 
00693             if (illuminate) {
00694                 if (r.contains(illuminatePos)) {
00695                     paint.setPen(v->getForeground());
00696                 }
00697             }
00698             
00699 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00700             std::cerr << "rect " << r.x() << "," << r.y() << " "
00701                       << r.width() << "x" << r.height() << std::endl;
00702 #endif
00703 
00704             paint.drawRect(r);
00705 
00706             if (showLabel) {
00707                 if (scx >= 0 && scx < m_cache->width() &&
00708                     sy >= 0 && sy < m_cache->height()) {
00709                     float value = m_model->getValueAt(scx, sy);
00710                     sprintf(labelbuf, "%06f", value);
00711                     QString text(labelbuf);
00712                     paint.setPen(v->getBackground());
00713                     paint.drawText(rx0 + 2,
00714                                    ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
00715                                    text);
00716                 }
00717             }
00718         }
00719     }
00720 }
00721 
00722 void
00723 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const
00724 {
00725     size_t modelStart = m_model->getStartFrame();
00726     size_t modelResolution = m_model->getResolution();
00727 
00728     float srRatio =
00729         float(v->getViewManager()->getMainModelSampleRate()) /
00730         float(m_model->getSampleRate());
00731 
00732     int x0 = rect.left();
00733     int x1 = rect.right() + 1;
00734 
00735     int w = x1 - x0;
00736     int h = v->height();
00737     int sh = m_model->getHeight();
00738 
00739     QImage img(w, h, QImage::Format_RGB32);
00740 
00741     for (int x = x0; x < x1; ++x) {
00742 
00743         long xf = long(v->getFrameForX(x));
00744         if (xf < 0) {
00745             for (int y = 0; y < h; ++y) {
00746                 img.setPixel(x - x0, y, m_cache->color(0));
00747             }
00748             continue;
00749         }
00750 
00751         xf /= srRatio;
00752 
00753         float sx0 = (float(xf) - modelStart) / modelResolution;
00754         float sx1 = (float(v->getFrameForX(x+1) / srRatio) - modelStart) / modelResolution;
00755             
00756         int sx0i = int(sx0 + 0.001);
00757         int sx1i = int(sx1);
00758 
00759         for (int y = 0; y < h; ++y) {
00760 
00761             float sy0 = (float(h - y - 1) * sh) / h;
00762             float sy1 = (float(h - y) * sh) / h;
00763             
00764             int sy0i = int(sy0 + 0.001);
00765             int sy1i = int(sy1);
00766 
00767             float mag = 0.0, div = 0.0;
00768             int max = 0;
00769 
00770             for (int sx = sx0i; sx <= sx1i; ++sx) {
00771 
00772                 int scx = 0;
00773                 if (sx > int(m_cacheStart)) scx = sx - int(m_cacheStart);
00774         
00775                 if (scx < 0 || scx >= m_cache->width()) continue;
00776 
00777                 for (int sy = sy0i; sy <= sy1i; ++sy) {
00778 
00779                     if (sy < 0 || sy >= m_cache->height()) continue;
00780 
00781                     float prop = 1.0;
00782                     if (sx == sx0i) prop *= (sx + 1) - sx0;
00783                     if (sx == sx1i) prop *= sx1 - sx;
00784                     if (sy == sy0i) prop *= (sy + 1) - sy0;
00785                     if (sy == sy1i) prop *= sy1 - sy;
00786 
00787                     mag += prop * m_cache->pixelIndex(scx, sy);
00788                     max = std::max(max, m_cache->pixelIndex(scx, sy));
00789                     div += prop;
00790                 }
00791             }
00792 
00793             if (div != 0) mag /= div;
00794             if (mag < 0) mag = 0;
00795             if (mag > 255) mag = 255;
00796             if (max < 0) max = 0;
00797             if (max > 255) max = 255;
00798 
00799             img.setPixel(x - x0, y, m_cache->color(int(mag + 0.001)));
00800 //            img.setPixel(x - x0, y, m_cache->color(max));
00801         }
00802     }
00803 
00804     paint.drawImage(x0, 0, img);
00805 }
00806 
00807 bool
00808 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame,
00809                                       size_t &resolution,
00810                                       SnapType snap) const
00811 {
00812     if (!m_model) {
00813         return Layer::snapToFeatureFrame(v, frame, resolution, snap);
00814     }
00815 
00816     resolution = m_model->getResolution();
00817     int left = (frame / resolution) * resolution;
00818     int right = left + resolution;
00819 
00820     switch (snap) {
00821     case SnapLeft:  frame = left;  break;
00822     case SnapRight: frame = right; break;
00823     case SnapNearest:
00824     case SnapNeighbouring:
00825         if (frame - left > right - frame) frame = right;
00826         else frame = left;
00827         break;
00828     }
00829     
00830     return true;
00831 }
00832 
00833 void
00834 Colour3DPlotLayer::toXml(QTextStream &stream,
00835                          QString indent, QString extraAttributes) const
00836 {
00837     QString s = QString("scale=\"%1\" "
00838                         "colourScheme=\"%2\" "
00839                         "normalizeColumns=\"%3\" "
00840                         "normalizeVisibleArea=\"%4\"")
00841         .arg((int)m_colourScale)
00842         .arg(m_colourMap)
00843         .arg(m_normalizeColumns ? "true" : "false")
00844         .arg(m_normalizeVisibleArea ? "true" : "false");
00845 
00846     Layer::toXml(stream, indent, extraAttributes + " " + s);
00847 }
00848 
00849 void
00850 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
00851 {
00852     bool ok = false;
00853 
00854     ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok);
00855     if (ok) setColourScale(scale);
00856 
00857     int colourMap = attributes.value("colourScheme").toInt(&ok);
00858     if (ok) setColourMap(colourMap);
00859 
00860     bool normalizeColumns =
00861         (attributes.value("normalizeColumns").trimmed() == "true");
00862     setNormalizeColumns(normalizeColumns);
00863 
00864     bool normalizeVisibleArea =
00865         (attributes.value("normalizeVisibleArea").trimmed() == "true");
00866     setNormalizeVisibleArea(normalizeVisibleArea);
00867 }
00868 

Generated on Wed Feb 20 15:45:25 2008 for SonicVisualiser by  doxygen 1.5.1