svgui  1.9
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/RangeMapper.h"
00022 #include "ColourMapper.h"
00023 
00024 #include <QPainter>
00025 #include <QImage>
00026 #include <QRect>
00027 #include <QTextStream>
00028 
00029 #include <iostream>
00030 
00031 #include <cassert>
00032 
00033 #ifndef __GNUC__
00034 #include <alloca.h>
00035 #endif
00036 
00037 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
00038 
00039 
00040 Colour3DPlotLayer::Colour3DPlotLayer() :
00041     m_model(0),
00042     m_cache(0),
00043     m_peaksCache(0),
00044     m_cacheValidStart(0),
00045     m_cacheValidEnd(0),
00046     m_colourScale(LinearScale),
00047     m_colourScaleSet(false),
00048     m_colourMap(0),
00049     m_gain(1.0),
00050     m_binScale(LinearBinScale),
00051     m_normalizeColumns(false),
00052     m_normalizeVisibleArea(false),
00053     m_normalizeHybrid(false),
00054     m_invertVertical(false),
00055     m_opaque(false),
00056     m_smooth(false),
00057     m_peakResolution(256),
00058     m_miny(0),
00059     m_maxy(0)
00060 {
00061     
00062 }
00063 
00064 Colour3DPlotLayer::~Colour3DPlotLayer()
00065 {
00066     delete m_cache;
00067     delete m_peaksCache;
00068 }
00069 
00070 void
00071 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
00072 {
00073     if (m_model == model) return;
00074     const DenseThreeDimensionalModel *oldModel = m_model;
00075     m_model = model;
00076     if (!m_model || !m_model->isOK()) return;
00077 
00078     connectSignals(m_model);
00079 
00080     connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
00081     connect(m_model, SIGNAL(modelChangedWithin(int, int)),
00082             this, SLOT(modelChangedWithin(int, int)));
00083 
00084     m_peakResolution = 256;
00085     if (model->getResolution() > 512) {
00086         m_peakResolution = 16;
00087     } else if (model->getResolution() > 128) {
00088         m_peakResolution = 64;
00089     } else if (model->getResolution() > 2) {
00090         m_peakResolution = 128;
00091     }
00092     cacheInvalid();
00093 
00094     emit modelReplaced();
00095     emit sliceableModelReplaced(oldModel, model);
00096 }
00097 
00098 void
00099 Colour3DPlotLayer::cacheInvalid()
00100 {
00101     delete m_cache;
00102     delete m_peaksCache;
00103     m_cache = 0;
00104     m_peaksCache = 0;
00105     m_cacheValidStart = 0;
00106     m_cacheValidEnd = 0;
00107 }
00108 
00109 void
00110 Colour3DPlotLayer::cacheInvalid(int startFrame, int endFrame)
00111 {
00112     if (!m_cache || !m_model) return;
00113 
00114     int modelResolution = m_model->getResolution();
00115     int start = startFrame / modelResolution;
00116     int end = endFrame / modelResolution + 1;
00117     if (m_cacheValidStart < end) m_cacheValidStart = end;
00118     if (m_cacheValidEnd > start) m_cacheValidEnd = start;
00119     if (m_cacheValidStart > m_cacheValidEnd) m_cacheValidEnd = m_cacheValidStart;
00120 }
00121 
00122 void
00123 Colour3DPlotLayer::modelChanged()
00124 {
00125     if (!m_colourScaleSet && m_colourScale == LinearScale) {
00126         if (m_model) {
00127             if (m_model->shouldUseLogValueScale()) {
00128                 setColourScale(LogScale);
00129             } else {
00130                 m_colourScaleSet = true;
00131             }
00132         }
00133     }
00134     cacheInvalid();
00135 }
00136 
00137 void
00138 Colour3DPlotLayer::modelChangedWithin(int startFrame, int endFrame)
00139 {
00140     if (!m_colourScaleSet && m_colourScale == LinearScale) {
00141         if (m_model && m_model->getWidth() > 50) {
00142             if (m_model->shouldUseLogValueScale()) {
00143                 setColourScale(LogScale);
00144             } else {
00145                 m_colourScaleSet = true;
00146             }
00147         }
00148     }
00149     cacheInvalid(startFrame, endFrame);
00150 }
00151 
00152 Layer::PropertyList
00153 Colour3DPlotLayer::getProperties() const
00154 {
00155     PropertyList list;
00156     list.push_back("Colour");
00157     list.push_back("Colour Scale");
00158     list.push_back("Normalize Columns");
00159     list.push_back("Normalize Visible Area");
00160     list.push_back("Gain");
00161     list.push_back("Bin Scale");
00162     list.push_back("Invert Vertical Scale");
00163     list.push_back("Opaque");
00164     list.push_back("Smooth");
00165     return list;
00166 }
00167 
00168 QString
00169 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
00170 {
00171     if (name == "Colour") return tr("Colour");
00172     if (name == "Colour Scale") return tr("Scale");
00173     if (name == "Normalize Columns") return tr("Normalize Columns");
00174     if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
00175     if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
00176     if (name == "Gain") return tr("Gain");
00177     if (name == "Opaque") return tr("Always Opaque");
00178     if (name == "Smooth") return tr("Smooth");
00179     if (name == "Bin Scale") return tr("Bin Scale");
00180     return "";
00181 }
00182 
00183 QString
00184 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
00185 {
00186     if (name == "Normalize Columns") return "normalise-columns";
00187     if (name == "Normalize Visible Area") return "normalise";
00188     if (name == "Invert Vertical Scale") return "invert-vertical";
00189     if (name == "Opaque") return "opaque";
00190     if (name == "Smooth") return "smooth";
00191     return "";
00192 }
00193 
00194 Layer::PropertyType
00195 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
00196 {
00197     if (name == "Gain") return RangeProperty;
00198     if (name == "Normalize Columns") return ToggleProperty;
00199     if (name == "Normalize Visible Area") return ToggleProperty;
00200     if (name == "Invert Vertical Scale") return ToggleProperty;
00201     if (name == "Opaque") return ToggleProperty;
00202     if (name == "Smooth") return ToggleProperty;
00203     return ValueProperty;
00204 }
00205 
00206 QString
00207 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
00208 {
00209     if (name == "Normalize Columns" ||
00210         name == "Normalize Visible Area" ||
00211         name == "Colour Scale" ||
00212         name == "Gain") return tr("Scale");
00213     if (name == "Bin Scale" ||
00214         name == "Invert Vertical Scale") return tr("Bins");
00215     if (name == "Opaque" ||
00216         name == "Smooth" ||
00217         name == "Colour") return tr("Colour");
00218     return QString();
00219 }
00220 
00221 int
00222 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name,
00223                                             int *min, int *max, int *deflt) const
00224 {
00225     int val = 0;
00226 
00227     int garbage0, garbage1, garbage2;
00228     if (!min) min = &garbage0;
00229     if (!max) max = &garbage1;
00230     if (!deflt) deflt = &garbage2;
00231 
00232     if (name == "Gain") {
00233 
00234         *min = -50;
00235         *max = 50;
00236 
00237         *deflt = lrintf(log10(1.f) * 20.0);;
00238         if (*deflt < *min) *deflt = *min;
00239         if (*deflt > *max) *deflt = *max;
00240 
00241         val = lrintf(log10(m_gain) * 20.0);
00242         if (val < *min) val = *min;
00243         if (val > *max) val = *max;
00244 
00245     } else if (name == "Colour Scale") {
00246 
00247         *min = 0;
00248         *max = 3;
00249         *deflt = (int)LinearScale;
00250 
00251         val = (int)m_colourScale;
00252 
00253     } else if (name == "Colour") {
00254 
00255         *min = 0;
00256         *max = ColourMapper::getColourMapCount() - 1;
00257         *deflt = 0;
00258 
00259         val = m_colourMap;
00260 
00261     } else if (name == "Normalize Columns") {
00262         
00263         *deflt = 0;
00264         val = (m_normalizeColumns ? 1 : 0);
00265 
00266     } else if (name == "Normalize Visible Area") {
00267         
00268         *deflt = 0;
00269         val = (m_normalizeVisibleArea ? 1 : 0);
00270 
00271     } else if (name == "Invert Vertical Scale") {
00272         
00273         *deflt = 0;
00274         val = (m_invertVertical ? 1 : 0);
00275 
00276     } else if (name == "Bin Scale") {
00277 
00278         *min = 0;
00279         *max = 1;
00280         *deflt = int(LinearBinScale);
00281         val = (int)m_binScale;
00282 
00283     } else if (name == "Opaque") {
00284         
00285         *deflt = 0;
00286         val = (m_opaque ? 1 : 0);
00287         
00288     } else if (name == "Smooth") {
00289         
00290         *deflt = 0;
00291         val = (m_smooth ? 1 : 0);
00292         
00293     } else {
00294         val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
00295     }
00296 
00297     return val;
00298 }
00299 
00300 QString
00301 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name,
00302                                     int value) const
00303 {
00304     if (name == "Colour") {
00305         return ColourMapper::getColourMapName(value);
00306     }
00307     if (name == "Colour Scale") {
00308         switch (value) {
00309         default:
00310         case 0: return tr("Linear");
00311         case 1: return tr("Log");
00312         case 2: return tr("+/-1");
00313         case 3: return tr("Absolute");
00314         }
00315     }
00316     if (name == "Bin Scale") {
00317         switch (value) {
00318         default:
00319         case 0: return tr("Linear");
00320         case 1: return tr("Log");
00321         }
00322     }
00323     return tr("<unknown>");
00324 }
00325 
00326 RangeMapper *
00327 Colour3DPlotLayer::getNewPropertyRangeMapper(const PropertyName &name) const
00328 {
00329     if (name == "Gain") {
00330         return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
00331     }
00332     return 0;
00333 }
00334 
00335 void
00336 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
00337 {
00338     if (name == "Gain") {
00339         setGain(pow(10, float(value)/20.0));
00340     } else if (name == "Colour Scale") {
00341         switch (value) {
00342         default:
00343         case 0: setColourScale(LinearScale); break;
00344         case 1: setColourScale(LogScale); break;
00345         case 2: setColourScale(PlusMinusOneScale); break;
00346         case 3: setColourScale(AbsoluteScale); break;
00347         }
00348     } else if (name == "Colour") {
00349         setColourMap(value);
00350     } else if (name == "Normalize Columns") {
00351         setNormalizeColumns(value ? true : false);
00352     } else if (name == "Normalize Visible Area") {
00353         setNormalizeVisibleArea(value ? true : false);
00354     } else if (name == "Invert Vertical Scale") {
00355         setInvertVertical(value ? true : false);
00356     } else if (name == "Opaque") {
00357         setOpaque(value ? true : false);
00358     } else if (name == "Smooth") {
00359         setSmooth(value ? true : false);
00360     } else if (name == "Bin Scale") {
00361         switch (value) {
00362         default:
00363         case 0: setBinScale(LinearBinScale); break;
00364         case 1: setBinScale(LogBinScale); break;
00365         }
00366     }
00367 }
00368 
00369 void
00370 Colour3DPlotLayer::setColourScale(ColourScale scale)
00371 {
00372     if (m_colourScale == scale) return;
00373     m_colourScale = scale;
00374     m_colourScaleSet = true;
00375     cacheInvalid();
00376     emit layerParametersChanged();
00377 }
00378 
00379 void
00380 Colour3DPlotLayer::setColourMap(int map)
00381 {
00382     if (m_colourMap == map) return;
00383     m_colourMap = map;
00384     cacheInvalid();
00385     emit layerParametersChanged();
00386 }
00387 
00388 void
00389 Colour3DPlotLayer::setGain(float gain)
00390 {
00391     if (m_gain == gain) return;
00392     m_gain = gain;
00393     cacheInvalid();
00394     emit layerParametersChanged();
00395 }
00396 
00397 float
00398 Colour3DPlotLayer::getGain() const
00399 {
00400     return m_gain;
00401 }
00402 
00403 void
00404 Colour3DPlotLayer::setBinScale(BinScale binScale)
00405 {
00406     if (m_binScale == binScale) return;
00407     m_binScale = binScale;
00408     cacheInvalid();
00409     emit layerParametersChanged();
00410 }
00411 
00412 Colour3DPlotLayer::BinScale
00413 Colour3DPlotLayer::getBinScale() const
00414 {
00415     return m_binScale;
00416 }
00417 
00418 void
00419 Colour3DPlotLayer::setNormalizeColumns(bool n)
00420 {
00421     if (m_normalizeColumns == n) return;
00422     m_normalizeColumns = n;
00423     cacheInvalid();
00424     emit layerParametersChanged();
00425 }
00426 
00427 bool
00428 Colour3DPlotLayer::getNormalizeColumns() const
00429 {
00430     return m_normalizeColumns;
00431 }
00432 
00433 void
00434 Colour3DPlotLayer::setNormalizeHybrid(bool n)
00435 {
00436     if (m_normalizeHybrid == n) return;
00437     m_normalizeHybrid = n;
00438     cacheInvalid();
00439     emit layerParametersChanged();
00440 }
00441 
00442 bool
00443 Colour3DPlotLayer::getNormalizeHybrid() const
00444 {
00445     return m_normalizeHybrid;
00446 }
00447 
00448 void
00449 Colour3DPlotLayer::setNormalizeVisibleArea(bool n)
00450 {
00451     if (m_normalizeVisibleArea == n) return;
00452     m_normalizeVisibleArea = n;
00453     cacheInvalid();
00454     emit layerParametersChanged();
00455 }
00456 
00457 bool
00458 Colour3DPlotLayer::getNormalizeVisibleArea() const
00459 {
00460     return m_normalizeVisibleArea;
00461 }
00462 
00463 void
00464 Colour3DPlotLayer::setInvertVertical(bool n)
00465 {
00466     if (m_invertVertical == n) return;
00467     m_invertVertical = n;
00468     cacheInvalid();
00469     emit layerParametersChanged();
00470 }
00471 
00472 void
00473 Colour3DPlotLayer::setOpaque(bool n)
00474 {
00475     if (m_opaque == n) return;
00476     m_opaque = n;
00477     emit layerParametersChanged();
00478 }
00479 
00480 void
00481 Colour3DPlotLayer::setSmooth(bool n)
00482 {
00483     if (m_smooth == n) return;
00484     m_smooth = n;
00485     emit layerParametersChanged();
00486 }
00487 
00488 bool
00489 Colour3DPlotLayer::getInvertVertical() const
00490 {
00491     return m_invertVertical;
00492 }
00493 
00494 bool
00495 Colour3DPlotLayer::getOpaque() const
00496 {
00497     return m_opaque;
00498 }
00499 
00500 bool
00501 Colour3DPlotLayer::getSmooth() const
00502 {
00503     return m_smooth;
00504 }
00505 
00506 void
00507 Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant)
00508 {
00509     if (dormant) {
00510 
00511 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00512         cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")"
00513                   << endl;
00514 #endif
00515 
00516         if (isLayerDormant(v)) {
00517             return;
00518         }
00519 
00520         Layer::setLayerDormant(v, true);
00521 
00522         cacheInvalid();
00523         
00524     } else {
00525 
00526         Layer::setLayerDormant(v, false);
00527     }
00528 }
00529 
00530 bool
00531 Colour3DPlotLayer::isLayerScrollable(const View *v) const
00532 {
00533     if (m_normalizeVisibleArea) {
00534         return false;
00535     }
00536     if (shouldPaintDenseIn(v)) {
00537         return true;
00538     }
00539     QPoint discard;
00540     return !v->shouldIlluminateLocalFeatures(this, discard);
00541 }
00542 
00543 bool
00544 Colour3DPlotLayer::getValueExtents(float &min, float &max,
00545                                    bool &logarithmic, QString &unit) const
00546 {
00547     if (!m_model) return false;
00548 
00549     min = 0;
00550     max = m_model->getHeight();
00551 
00552     logarithmic = false;
00553     unit = "";
00554 
00555     return true;
00556 }
00557 
00558 bool
00559 Colour3DPlotLayer::getDisplayExtents(float &min, float &max) const
00560 {
00561     if (!m_model) return false;
00562 
00563     min = m_miny;
00564     max = m_maxy;
00565     if (max <= min) {
00566         min = 0;
00567         max = m_model->getHeight();
00568     }
00569     if (min < 0) min = 0;
00570     if (max > m_model->getHeight()) max = m_model->getHeight();
00571 
00572     return true;
00573 }
00574 
00575 bool
00576 Colour3DPlotLayer::setDisplayExtents(float min, float max)
00577 {
00578     if (!m_model) return false;
00579 
00580     m_miny = lrintf(min);
00581     m_maxy = lrintf(max);
00582     
00583     emit layerParametersChanged();
00584     return true;
00585 }
00586 
00587 bool
00588 Colour3DPlotLayer::getYScaleValue(const View *, int,
00589                                   float &, QString &) const
00590 {
00591     return false;
00592 }
00593 
00594 int
00595 Colour3DPlotLayer::getVerticalZoomSteps(int &defaultStep) const
00596 {
00597     if (!m_model) return 0;
00598 
00599     defaultStep = 0;
00600     int h = m_model->getHeight();
00601     return h;
00602 }
00603 
00604 int
00605 Colour3DPlotLayer::getCurrentVerticalZoomStep() const
00606 {
00607     if (!m_model) return 0;
00608 
00609     float min, max;
00610     getDisplayExtents(min, max);
00611     return m_model->getHeight() - lrintf(max - min);
00612 }
00613 
00614 void
00615 Colour3DPlotLayer::setVerticalZoomStep(int step)
00616 {
00617     if (!m_model) return;
00618 
00619 //    SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): before: miny = " << m_miny << ", maxy = " << m_maxy << endl;
00620 
00621     int dist = m_model->getHeight() - step;
00622     if (dist < 1) dist = 1;
00623     float centre = m_miny + (float(m_maxy) - float(m_miny)) / 2.f;
00624     m_miny = lrintf(centre - float(dist)/2);
00625     if (m_miny < 0) m_miny = 0;
00626     m_maxy = m_miny + dist;
00627     if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight();
00628 
00629 //    SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"):  after: miny = " << m_miny << ", maxy = " << m_maxy << endl;
00630     
00631     emit layerParametersChanged();
00632 }
00633 
00634 RangeMapper *
00635 Colour3DPlotLayer::getNewVerticalZoomRangeMapper() const
00636 {
00637     if (!m_model) return 0;
00638 
00639     return new LinearRangeMapper(0, m_model->getHeight(),
00640                                  0, m_model->getHeight(), "");
00641 }
00642 
00643 float
00644 Colour3DPlotLayer::getYForBin(View *v, float bin) const
00645 {
00646     float y = bin;
00647     if (!m_model) return y;
00648     float mn = 0, mx = m_model->getHeight();
00649     getDisplayExtents(mn, mx);
00650     float h = v->height();
00651     if (m_binScale == LinearBinScale) {
00652         y = h - (((bin - mn) * h) / (mx - mn));
00653     } else {
00654         float logmin = mn + 1, logmax = mx + 1;
00655         LogRange::mapRange(logmin, logmax);
00656         y = h - (((LogRange::map(bin + 1) - logmin) * h) / (logmax - logmin));
00657     }
00658     return y;
00659 }
00660 
00661 float
00662 Colour3DPlotLayer::getBinForY(View *v, float y) const
00663 {
00664     float bin = y;
00665     if (!m_model) return bin;
00666     float mn = 0, mx = m_model->getHeight();
00667     getDisplayExtents(mn, mx);
00668     float h = v->height();
00669     if (m_binScale == LinearBinScale) {
00670         bin = mn + ((h - y) * (mx - mn)) / h;
00671     } else {
00672         float logmin = mn + 1, logmax = mx + 1;
00673         LogRange::mapRange(logmin, logmax);
00674         bin = LogRange::unmap(logmin + ((h - y) * (logmax - logmin)) / h) - 1;
00675     }
00676     return bin;
00677 }
00678 
00679 QString
00680 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const
00681 {
00682     if (!m_model) return "";
00683 
00684     int x = pos.x();
00685     int y = pos.y();
00686 
00687     int modelStart = m_model->getStartFrame();
00688     int modelResolution = m_model->getResolution();
00689 
00690     float srRatio =
00691         float(v->getViewManager()->getMainModelSampleRate()) /
00692         float(m_model->getSampleRate());
00693 
00694     int sx0 = int((v->getFrameForX(x) / srRatio - modelStart) /
00695                   modelResolution);
00696 
00697     int f0 = sx0 * modelResolution;
00698     int f1 =  f0 + modelResolution;
00699 
00700     int sh = m_model->getHeight();
00701 
00702     int symin = m_miny;
00703     int symax = m_maxy;
00704     if (symax <= symin) {
00705         symin = 0;
00706         symax = sh;
00707     }
00708     if (symin < 0) symin = 0;
00709     if (symax > sh) symax = sh;
00710 
00711  //    float binHeight = float(v->height()) / (symax - symin);
00712 //    int sy = int((v->height() - y) / binHeight) + symin;
00713 
00714     int sy = getBinForY(v, y);
00715 
00716     if (sy < 0 || sy >= m_model->getHeight()) {
00717         return "";
00718     }
00719 
00720     if (m_invertVertical) sy = m_model->getHeight() - sy - 1;
00721 
00722     float value = m_model->getValueAt(sx0, sy);
00723 
00724 //    cerr << "bin value (" << sx0 << "," << sy << ") is " << value << endl;
00725     
00726     QString binName = m_model->getBinName(sy);
00727     if (binName == "") binName = QString("[%1]").arg(sy + 1);
00728     else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
00729 
00730     QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
00731         .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
00732              .toText(true).c_str())
00733         .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
00734              .toText(true).c_str())
00735         .arg(binName)
00736         .arg(value);
00737 
00738     return text;
00739 }
00740 
00741 int
00742 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const
00743 {
00744     int cw = 20;
00745     return cw;
00746 }
00747 
00748 int
00749 Colour3DPlotLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const
00750 {
00751     if (!m_model) return 0;
00752 
00753     QString sampleText = QString("[%1]").arg(m_model->getHeight());
00754     int tw = paint.fontMetrics().width(sampleText);
00755     bool another = false;
00756 
00757     for (int i = 0; i < m_model->getHeight(); ++i) {
00758         if (m_model->getBinName(i).length() > sampleText.length()) {
00759             sampleText = m_model->getBinName(i);
00760             another = true;
00761         }
00762     }
00763     if (another) {
00764         tw = std::max(tw, paint.fontMetrics().width(sampleText));
00765     }
00766 
00767     return tw + 13 + getColourScaleWidth(paint);
00768 }
00769 
00770 void
00771 Colour3DPlotLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const
00772 {
00773     if (!m_model) return;
00774 
00775     int h = rect.height(), w = rect.width();
00776 
00777     int cw = getColourScaleWidth(paint);
00778     
00779     int ch = h - 20;
00780     if (ch > 20 && m_cache) {
00781 
00782         float min = m_model->getMinimumLevel();
00783         float max = m_model->getMaximumLevel();
00784 
00785         float mmin = min;
00786         float mmax = max;
00787 
00788         if (m_colourScale == LogScale) {
00789             LogRange::mapRange(mmin, mmax);
00790         } else if (m_colourScale == PlusMinusOneScale) {
00791             mmin = -1.f;
00792             mmax = 1.f;
00793         } else if (m_colourScale == AbsoluteScale) {
00794             if (mmin < 0) {
00795                 if (fabsf(mmin) > fabsf(mmax)) mmax = fabsf(mmin);
00796                 else mmax = fabsf(mmax);
00797                 mmin = 0;
00798             } else {
00799                 mmin = fabsf(mmin);
00800                 mmax = fabsf(mmax);
00801             }
00802         }
00803     
00804         if (max == min) max = min + 1.0;
00805         if (mmax == mmin) mmax = mmin + 1.0;
00806     
00807         paint.setPen(v->getForeground());
00808         paint.drawRect(4, 10, cw - 8, ch+1);
00809 
00810         for (int y = 0; y < ch; ++y) {
00811             float value = ((max - min) * (ch - y - 1)) / ch + min;
00812             if (m_colourScale == LogScale) {
00813                 value = LogRange::map(value);
00814             }
00815             int pixel = int(((value - mmin) * 256) / (mmax - mmin));
00816             if (pixel >= 0 && pixel < 256) {
00817                 QRgb c = m_cache->color(pixel);
00818                 paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c)));
00819                 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
00820             } else {
00821                 cerr << "WARNING: Colour3DPlotLayer::paintVerticalScale: value " << value << ", mmin " << mmin << ", mmax " << mmax << " leads to invalid pixel " << pixel << endl;
00822             }
00823         }
00824 
00825         QString minstr = QString("%1").arg(min);
00826         QString maxstr = QString("%1").arg(max);
00827         
00828         paint.save();
00829 
00830         QFont font = paint.font();
00831         font.setPixelSize(10);
00832         paint.setFont(font);
00833 
00834         int msw = paint.fontMetrics().width(maxstr);
00835 
00836         QMatrix m;
00837         m.translate(cw - 6, ch + 10);
00838         m.rotate(-90);
00839 
00840         paint.setWorldMatrix(m);
00841 
00842         v->drawVisibleText(paint, 2, 0, minstr, View::OutlinedText);
00843 
00844         m.translate(ch - msw - 2, 0);
00845         paint.setWorldMatrix(m);
00846 
00847         v->drawVisibleText(paint, 0, 0, maxstr, View::OutlinedText);
00848 
00849         paint.restore();
00850     }
00851 
00852     paint.setPen(v->getForeground());
00853 
00854     int sh = m_model->getHeight();
00855 
00856     int symin = m_miny;
00857     int symax = m_maxy;
00858     if (symax <= symin) {
00859         symin = 0;
00860         symax = sh;
00861     }
00862     if (symin < 0) symin = 0;
00863     if (symax > sh) symax = sh;
00864 
00865     paint.save();
00866 
00867     int py = h;
00868 
00869     for (int i = symin; i <= symax; ++i) {
00870 
00871         int y0;
00872 
00873         y0 = lrintf(getYForBin(v, i));
00874         int h = py - y0;
00875 
00876         if (i > symin) {
00877             if (paint.fontMetrics().height() >= h) {
00878                 if (h >= 8) {
00879                     QFont tf = paint.font();
00880                     tf.setPixelSize(h-2);
00881                     paint.setFont(tf);
00882                 } else {
00883                     continue;
00884                 }
00885             }
00886         }
00887         
00888         py = y0;
00889 
00890         if (i < symax) {
00891             paint.drawLine(cw, y0, w, y0);
00892         }
00893 
00894         if (i > symin) {
00895 
00896             int idx = i - 1;
00897             if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
00898 
00899             QString text = m_model->getBinName(idx);
00900             if (text == "") text = QString("[%1]").arg(idx + 1);
00901 
00902             int ty = y0 + (h/2) - (paint.fontMetrics().height()/2) +
00903                 paint.fontMetrics().ascent() + 1;
00904 
00905             paint.drawText(cw + 5, ty, text);
00906         }
00907     }
00908 
00909     paint.restore();
00910 }
00911 
00912 DenseThreeDimensionalModel::Column
00913 Colour3DPlotLayer::getColumn(int col) const
00914 {
00915     Profiler profiler("Colour3DPlotLayer::getColumn");
00916 
00917     DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
00918     while (values.size() < m_model->getHeight()) values.push_back(0.f);
00919     if (!m_normalizeColumns && !m_normalizeHybrid) return values;
00920 
00921     float colMax = 0.f, colMin = 0.f;
00922     float min = 0.f, max = 0.f;
00923 
00924     min = m_model->getMinimumLevel();
00925     max = m_model->getMaximumLevel();
00926 
00927     for (int y = 0; y < values.size(); ++y) {
00928         if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
00929         if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
00930     }
00931     if (colMin == colMax) colMax = colMin + 1;
00932     
00933     for (int y = 0; y < values.size(); ++y) {
00934     
00935         float value = values.at(y);
00936         float norm = (value - colMin) / (colMax - colMin);
00937         float newvalue = min + (max - min) * norm;
00938 
00939         if (value != newvalue) values[y] = newvalue;
00940     }
00941 
00942     if (m_normalizeHybrid && (colMax > 0.0)) {
00943         float logmax = log10(colMax);
00944         for (int y = 0; y < values.size(); ++y) {
00945             values[y] *= logmax;
00946         }
00947     }
00948 
00949     return values;
00950 }
00951     
00952 void
00953 Colour3DPlotLayer::fillCache(int firstBin, int lastBin) const
00954 {
00955     Profiler profiler("Colour3DPlotLayer::fillCache", true);
00956 
00957     int modelStart = m_model->getStartFrame();
00958     int modelEnd = m_model->getEndFrame();
00959     int modelResolution = m_model->getResolution();
00960 
00961     int modelStartBin = modelStart / modelResolution;
00962     int modelEndBin = modelEnd / modelResolution;
00963 
00964 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00965     cerr << "Colour3DPlotLayer::fillCache: range " << firstBin << " -> " << lastBin << " of model range " << modelStartBin << " -> " << modelEndBin << " (model resolution " << modelResolution << ")" << endl;
00966 #endif
00967 
00968     int cacheWidth = modelEndBin - modelStartBin + 1;
00969     if (lastBin > modelEndBin) cacheWidth = lastBin - modelStartBin + 1;
00970     int cacheHeight = m_model->getHeight();
00971 
00972     if (m_cache && m_cache->height() != cacheHeight) {
00973         // height has changed: delete everything rather than resizing
00974 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00975         cerr << "Colour3DPlotLayer::fillCache: Cache height has changed, recreating" << endl;
00976 #endif
00977         delete m_cache;
00978         delete m_peaksCache;
00979         m_cache = 0;
00980         m_peaksCache = 0;
00981     } 
00982 
00983     if (m_cache && m_cache->width() != cacheWidth) {
00984         // width has changed and we have an existing cache: resize it
00985 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
00986         cerr << "Colour3DPlotLayer::fillCache: Cache width has changed, resizing existing cache" << endl;
00987 #endif
00988         QImage *newCache =
00989             new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight));
00990         delete m_cache;
00991         m_cache = newCache;
00992         if (m_peaksCache) {
00993             QImage *newPeaksCache =
00994                 new QImage(m_peaksCache->copy
00995                            (0, 0, cacheWidth / m_peakResolution + 1, cacheHeight));
00996             delete m_peaksCache;
00997             m_peaksCache = newPeaksCache;
00998         }
00999     }
01000 
01001     if (!m_cache) {
01002 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01003         cerr << "Colour3DPlotLayer::fillCache: Have no cache, making one" << endl;
01004 #endif
01005         m_cache = new QImage
01006             (cacheWidth, cacheHeight, QImage::Format_Indexed8);
01007         m_cache->setColorCount(256);
01008         m_cache->fill(0);
01009         if (!m_normalizeVisibleArea) {
01010             m_peaksCache = new QImage
01011                 (cacheWidth / m_peakResolution + 1, cacheHeight,
01012                  QImage::Format_Indexed8);
01013             m_peaksCache->setColorCount(256);
01014             m_peaksCache->fill(0);
01015         } else if (m_peaksCache) {
01016             delete m_peaksCache;
01017             m_peaksCache = 0;
01018         }
01019         m_cacheValidStart = 0;
01020         m_cacheValidEnd = 0;
01021     }
01022 
01023 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01024     cerr << "cache size = " << m_cache->width() << "x" << m_cache->height()
01025          << " peaks cache size = " << m_peaksCache->width() << "x" << m_peaksCache->height() << endl;
01026 #endif
01027 
01028     if (m_cacheValidStart <= firstBin && m_cacheValidEnd >= lastBin) {
01029 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01030         cerr << "Cache is valid in this region already" << endl;
01031 #endif
01032         return;
01033     }
01034     
01035     int fillStart = firstBin;
01036     int fillEnd = lastBin;
01037 
01038     if (fillStart < modelStartBin) fillStart = modelStartBin;
01039     if (fillStart > modelEndBin) fillStart = modelEndBin;
01040     if (fillEnd < modelStartBin) fillEnd = modelStartBin;
01041     if (fillEnd > modelEndBin) fillEnd = modelEndBin;
01042 
01043     bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns);
01044 
01045     if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) {
01046         
01047         if (m_cacheValidEnd < fillStart) {
01048             fillStart = m_cacheValidEnd + 1;
01049         }
01050         if (m_cacheValidStart > fillEnd) {
01051             fillEnd = m_cacheValidStart - 1;
01052         }
01053         
01054         m_cacheValidStart = std::min(fillStart, m_cacheValidStart);
01055         m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd);
01056 
01057     } else {
01058 
01059         // when normalising the visible area, the only valid area,
01060         // ever, is the currently visible one
01061 
01062         m_cacheValidStart = fillStart;
01063         m_cacheValidEnd = fillEnd;
01064     }
01065 
01066 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01067     cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << " (fillStart = " << fillStart << ", fillEnd = " << fillEnd << ")" << endl;
01068 #endif
01069 
01070     DenseThreeDimensionalModel::Column values;
01071 
01072     float min = m_model->getMinimumLevel();
01073     float max = m_model->getMaximumLevel();
01074 
01075     if (m_colourScale == LogScale) {
01076         LogRange::mapRange(min, max);
01077     } else if (m_colourScale == PlusMinusOneScale) {
01078         min = -1.f;
01079         max = 1.f;
01080     } else if (m_colourScale == AbsoluteScale) {
01081         if (min < 0) {
01082             if (fabsf(min) > fabsf(max)) max = fabsf(min);
01083             else max = fabsf(max);
01084             min = 0;
01085         } else {
01086             min = fabsf(min);
01087             max = fabsf(max);
01088         }
01089     }
01090     
01091     if (max == min) max = min + 1.0;
01092     
01093     ColourMapper mapper(m_colourMap, 0.f, 255.f);
01094     
01095     for (int index = 0; index < 256; ++index) {
01096         QColor colour = mapper.map(index);
01097         m_cache->setColor
01098             (index, qRgb(colour.red(), colour.green(), colour.blue()));
01099         if (m_peaksCache) {
01100             m_peaksCache->setColor
01101                 (index, qRgb(colour.red(), colour.green(), colour.blue()));
01102         }
01103     }
01104     
01105     float visibleMax = 0.f, visibleMin = 0.f;
01106 
01107     if (normalizeVisible) {
01108         
01109         for (int c = fillStart; c <= fillEnd; ++c) {
01110         
01111             values = getColumn(c);
01112 
01113             float colMax = 0.f, colMin = 0.f;
01114 
01115             for (int y = 0; y < cacheHeight; ++y) {
01116                 if (y >= values.size()) break;
01117                 if (y == 0 || values[y] > colMax) colMax = values[y];
01118                 if (y == 0 || values[y] < colMin) colMin = values[y];
01119             }
01120 
01121             if (c == fillStart || colMax > visibleMax) visibleMax = colMax;
01122             if (c == fillStart || colMin < visibleMin) visibleMin = colMin;
01123         }
01124 
01125         if (m_colourScale == LogScale) {
01126             visibleMin = LogRange::map(visibleMin);
01127             visibleMax = LogRange::map(visibleMax);
01128             if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax);
01129         } else if (m_colourScale == AbsoluteScale) {
01130             if (visibleMin < 0) {
01131                 if (fabsf(visibleMin) > fabsf(visibleMax)) visibleMax = fabsf(visibleMin);
01132                 else visibleMax = fabsf(visibleMax);
01133                 visibleMin = 0;
01134             } else {
01135                 visibleMin = fabsf(visibleMin);
01136                 visibleMax = fabsf(visibleMax);
01137             }
01138         }
01139     }
01140     
01141     if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
01142 
01143     int *peaks = 0;
01144     if (m_peaksCache) {
01145         peaks = new int[cacheHeight];
01146         for (int y = 0; y < cacheHeight; ++y) {
01147             peaks[y] = 0;
01148         }
01149     }
01150 
01151     Profiler profiler2("Colour3DPlotLayer::fillCache: filling", true);
01152 
01153     for (int c = fillStart; c <= fillEnd; ++c) {
01154         
01155         values = getColumn(c);
01156 
01157         if (c >= m_cache->width()) {
01158             cerr << "ERROR: column " << c << " >= cache width "
01159                  << m_cache->width() << endl;
01160             continue;
01161         }
01162 
01163         for (int y = 0; y < cacheHeight; ++y) {
01164 
01165             float value = min;
01166             if (y < values.size()) {
01167                 value = values.at(y);
01168             }
01169 
01170             value = value * m_gain;
01171 
01172             if (m_colourScale == LogScale) {
01173                 value = LogRange::map(value);
01174             } else if (m_colourScale == AbsoluteScale) {
01175                 value = fabsf(value);
01176             }
01177             
01178             if (normalizeVisible) {
01179                 float norm = (value - visibleMin) / (visibleMax - visibleMin);
01180                 value = min + (max - min) * norm;
01181             }
01182 
01183             int pixel = int(((value - min) * 256) / (max - min));
01184             if (pixel < 0) pixel = 0;
01185             if (pixel > 255) pixel = 255;
01186             if (peaks && (pixel > peaks[y])) peaks[y] = pixel;
01187 
01188             if (m_invertVertical) {
01189                 m_cache->setPixel(c, cacheHeight - y - 1, pixel);
01190             } else {
01191                 if (y >= m_cache->height()) {
01192                     cerr << "ERROR: row " << y << " >= cache height " << m_cache->height() << endl;
01193                 } else {
01194                     m_cache->setPixel(c, y, pixel);
01195                 }
01196             }
01197         }
01198 
01199         if (peaks) {
01200             int notch = (c % m_peakResolution);
01201             if (notch == m_peakResolution-1 || c == fillEnd) {
01202                 int pc = c / m_peakResolution;
01203                 if (pc >= m_peaksCache->width()) {
01204                     cerr << "ERROR: peak column " << pc
01205                          << " (from col " << c << ") >= peaks cache width "
01206                          << m_peaksCache->width() << endl;
01207                     continue;
01208                 }
01209                 for (int y = 0; y < cacheHeight; ++y) {
01210                     if (m_invertVertical) {
01211                         m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]);
01212                     } else {
01213                         if (y >= m_peaksCache->height()) {
01214                             cerr << "ERROR: row " << y
01215                                  << " >= peaks cache height "
01216                                  << m_peaksCache->height() << endl;
01217                         } else {
01218                             m_peaksCache->setPixel(pc, y, peaks[y]);
01219                         }
01220                     }
01221                 }
01222                 for (int y = 0; y < cacheHeight; ++y) {
01223                     peaks[y] = 0;
01224                 }
01225             }
01226         }
01227     }
01228 
01229     delete[] peaks;
01230 }
01231 
01232 bool
01233 Colour3DPlotLayer::shouldPaintDenseIn(const View *v) const
01234 {
01235     if (!m_model || !v || !(v->getViewManager())) {
01236         return false;
01237     }
01238     float srRatio =
01239         float(v->getViewManager()->getMainModelSampleRate()) /
01240         float(m_model->getSampleRate());
01241     if (m_opaque || 
01242         m_smooth ||
01243         m_model->getHeight() >= v->height() ||
01244         ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) {
01245         return true;
01246     }
01247     return false;
01248 }
01249 
01250 void
01251 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const
01252 {
01253 /*
01254     if (m_model) {
01255         SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
01256     }
01257 */
01258     Profiler profiler("Colour3DPlotLayer::paint");
01259 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01260     cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", rect is (" << rect.x() << "," << rect.y() << ") " << rect.width() << "x" << rect.height() << endl;
01261 #endif
01262 
01263     int completion = 0;
01264     if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
01265         if (completion > 0) {
01266             paint.fillRect(0, 10, v->width() * completion / 100,
01267                            10, QColor(120, 120, 120));
01268         }
01269         return;
01270     }
01271 
01272     if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect();
01273 
01274     int modelStart = m_model->getStartFrame();
01275     int modelEnd = m_model->getEndFrame();
01276     int modelResolution = m_model->getResolution();
01277 
01278     // The cache is from the model's start frame to the model's end
01279     // frame at the model's window increment frames per pixel.  We
01280     // want to draw from our start frame + x0 * zoomLevel to our start
01281     // frame + x1 * zoomLevel at zoomLevel frames per pixel.
01282 
01283     //  We have quite different paint mechanisms for rendering "large"
01284     //  bins (more than one bin per pixel in both directions) and
01285     //  "small".  This is "large"; see paintDense below for "small".
01286 
01287     int x0 = rect.left();
01288     int x1 = rect.right() + 1;
01289 
01290     int h = v->height();
01291 
01292     float srRatio =
01293         float(v->getViewManager()->getMainModelSampleRate()) /
01294         float(m_model->getSampleRate());
01295 
01296     int sx0 = int((v->getFrameForX(x0) / srRatio - modelStart)
01297                   / modelResolution);
01298     int sx1 = int((v->getFrameForX(x1) / srRatio - modelStart)
01299                   / modelResolution);
01300     int sh = m_model->getHeight();
01301 
01302     int symin = m_miny;
01303     int symax = m_maxy;
01304     if (symax <= symin) {
01305         symin = 0;
01306         symax = sh;
01307     }
01308     if (symin < 0) symin = 0;
01309     if (symax > sh) symax = sh;
01310 
01311     if (sx0 > 0) --sx0;
01312     fillCache(sx0 < 0 ? 0 : sx0,
01313               sx1 < 0 ? 0 : sx1);
01314 
01315 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01316     cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << endl;
01317 #endif
01318 
01319     if (shouldPaintDenseIn(v)) {
01320 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01321         cerr << "calling paintDense" << endl;
01322 #endif
01323         paintDense(v, paint, rect);
01324         return;
01325     }
01326 
01327 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01328     cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << endl;
01329     cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << endl;
01330 #endif
01331 
01332     QPoint illuminatePos;
01333     bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
01334     char labelbuf[10];
01335 
01336     for (int sx = sx0; sx <= sx1; ++sx) {
01337 
01338         int fx = sx * modelResolution;
01339 
01340         if (fx + modelResolution <= modelStart || fx > modelEnd) continue;
01341 
01342         int rx0 = v->getXForFrame(int((fx + modelStart) * srRatio));
01343         int rx1 = v->getXForFrame(int((fx + modelStart + modelResolution + 1) * srRatio));
01344 
01345         int rw = rx1 - rx0;
01346         if (rw < 1) rw = 1;
01347 
01348         bool showLabel = (rw > 10 &&
01349                           paint.fontMetrics().width("0.000000") < rw - 3 &&
01350                           paint.fontMetrics().height() < (h / sh));
01351         
01352         for (int sy = symin; sy < symax; ++sy) {
01353 
01354             int ry0 = getYForBin(v, sy);
01355             int ry1 = getYForBin(v, sy + 1);
01356             QRect r(rx0, ry1, rw, ry0 - ry1);
01357 
01358             QRgb pixel = qRgb(255, 255, 255);
01359             if (sx >= 0 && sx < m_cache->width() &&
01360                 sy >= 0 && sy < m_cache->height()) {
01361                 pixel = m_cache->pixel(sx, sy);
01362             }
01363 
01364             if (rw == 1) {
01365                 paint.setPen(pixel);
01366                 paint.setBrush(Qt::NoBrush);
01367                 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
01368                 continue;
01369             }
01370 
01371             QColor pen(255, 255, 255, 80);
01372             QColor brush(pixel);
01373 
01374             if (rw > 3 && r.height() > 3) {
01375                 brush.setAlpha(160);
01376             }
01377 
01378             paint.setPen(Qt::NoPen);
01379             paint.setBrush(brush);
01380 
01381             if (illuminate) {
01382                 if (r.contains(illuminatePos)) {
01383                     paint.setPen(v->getForeground());
01384                 }
01385             }
01386             
01387 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01388 //            cerr << "rect " << r.x() << "," << r.y() << " "
01389 //                      << r.width() << "x" << r.height() << endl;
01390 #endif
01391 
01392             paint.drawRect(r);
01393 
01394             if (showLabel) {
01395                 if (sx >= 0 && sx < m_cache->width() &&
01396                     sy >= 0 && sy < m_cache->height()) {
01397                     float value = m_model->getValueAt(sx, sy);
01398                     sprintf(labelbuf, "%06f", value);
01399                     QString text(labelbuf);
01400                     paint.setPen(v->getBackground());
01401                     paint.drawText(rx0 + 2,
01402                                    ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
01403                                    text);
01404                 }
01405             }
01406         }
01407     }
01408 }
01409 
01410 void
01411 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const
01412 {
01413     Profiler profiler("Colour3DPlotLayer::paintDense", true);
01414     if (!m_cache) return;
01415 
01416     float modelStart = m_model->getStartFrame();
01417     float modelResolution = m_model->getResolution();
01418 
01419     int mmsr = v->getViewManager()->getMainModelSampleRate();
01420     int msr = m_model->getSampleRate();
01421     float srRatio = float(mmsr) / float(msr);
01422 
01423     int x0 = rect.left();
01424     int x1 = rect.right() + 1;
01425 
01426     const int w = x1 - x0; // const so it can be used as array size below
01427     int h = v->height(); // we always paint full height
01428     int sh = m_model->getHeight();
01429 
01430     int symin = m_miny;
01431     int symax = m_maxy;
01432     if (symax <= symin) {
01433         symin = 0;
01434         symax = sh;
01435     }
01436     if (symin < 0) symin = 0;
01437     if (symax > sh) symax = sh;
01438 
01439     QImage img(w, h, QImage::Format_Indexed8);
01440     img.setColorTable(m_cache->colorTable());
01441 
01442     uchar *peaks = new uchar[w];
01443     memset(peaks, 0, w);
01444 
01445     int zoomLevel = v->getZoomLevel();
01446     
01447     QImage *source = m_cache;
01448 
01449 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT    
01450     cerr << "modelResolution " << modelResolution << ", srRatio "
01451          << srRatio << ", m_peakResolution " << m_peakResolution
01452          << ", zoomLevel " << zoomLevel << ", result "
01453          << ((modelResolution * srRatio * m_peakResolution) / zoomLevel)
01454          << endl;
01455 #endif
01456 
01457     if (m_peaksCache) {
01458         if (((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
01459 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT    
01460             cerr << "using peaks cache" << endl;
01461 #endif
01462             source = m_peaksCache;
01463             modelResolution *= m_peakResolution;
01464         } else {
01465 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT    
01466             cerr << "not using peaks cache" << endl;
01467 #endif
01468         }
01469     } else {
01470 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT    
01471         cerr << "have no peaks cache" << endl;
01472 #endif
01473     }
01474 
01475     int sw = source->width();
01476     
01477     int xf = -1;
01478     int nxf = v->getFrameForX(x0);
01479 
01480     float epsilon = 0.000001;
01481 
01482 #ifdef __GNUC__
01483     float sxa[w * 2];
01484 #else
01485     float *sxa = (float *)alloca(w * 2 * sizeof(float));
01486 #endif
01487     for (int x = 0; x < w; ++x) {
01488 
01489         xf = nxf;
01490         nxf = xf + zoomLevel;
01491 
01492         float sx0 = (float(xf) / srRatio - modelStart) / modelResolution;
01493         float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution;
01494 
01495         sxa[x*2] = sx0;
01496         sxa[x*2 + 1] = sx1;
01497     }
01498 
01499     float logmin = symin+1, logmax = symax+1;
01500     LogRange::mapRange(logmin, logmax);
01501 
01502 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
01503     cerr << "m_smooth = " << m_smooth << ", w = " << w << ", h = " << h << endl;
01504 #endif
01505 
01506     if (m_smooth) {
01507         
01508         for (int y = 0; y < h; ++y) {
01509 
01510             float sy = getBinForY(v, y) - 0.5;
01511             int syi = int(sy + epsilon);
01512             if (syi < 0 || syi >= source->height()) continue;
01513 
01514             uchar *targetLine = img.scanLine(y);
01515             uchar *sourceLine = source->scanLine(syi);
01516             uchar *nextSource;
01517             if (syi + 1 < source->height()) {
01518                 nextSource = source->scanLine(syi + 1);
01519             } else {
01520                 nextSource = sourceLine;
01521             }
01522 
01523             for (int x = 0; x < w; ++x) {
01524 
01525                 targetLine[x] = 0;
01526 
01527                 float sx0 = sxa[x*2];
01528                 if (sx0 < 0) continue;
01529                 int sx0i = int(sx0 + epsilon);
01530                 if (sx0i >= sw) break;
01531 
01532                 float a = float(sourceLine[sx0i]);
01533                 float b = a;
01534                 float value;
01535 
01536                 float sx1 = sxa[x*2+1];
01537                 if (sx1 > sx0 + 1.f) {
01538                     int sx1i = int(sx1);
01539                     bool have = false;
01540                     for (int sx = sx0i; sx <= sx1i; ++sx) {
01541                         if (sx < 0 || sx >= sw) continue;
01542                         if (!have) {
01543                             a = float(sourceLine[sx]);
01544                             b = float(nextSource[sx]);
01545                             have = true;
01546                         } else {
01547                             a = std::max(a, float(sourceLine[sx]));
01548                             b = std::max(b, float(nextSource[sx]));
01549                         }
01550                     }
01551                     float yprop = sy - syi;
01552                     value = (a * (1.f - yprop) + b * yprop);
01553                 } else {
01554                     a = float(sourceLine[sx0i]);
01555                     b = float(nextSource[sx0i]);
01556                     float yprop = sy - syi;
01557                     value = (a * (1.f - yprop) + b * yprop);
01558                     int oi = sx0i + 1;
01559                     float xprop = sx0 - sx0i;
01560                     xprop -= 0.5;
01561                     if (xprop < 0) {
01562                         oi = sx0i - 1;
01563                         xprop = -xprop;
01564                     }
01565                     if (oi < 0 || oi >= sw) oi = sx0i;
01566                     a = float(sourceLine[oi]);
01567                     b = float(nextSource[oi]);
01568                     value = (value * (1.f - xprop) +
01569                              (a * (1.f - yprop) + b * yprop) * xprop);
01570                 }
01571                 
01572                 int vi = lrintf(value);
01573                 if (vi > 255) vi = 255;
01574                 if (vi < 0) vi = 0;
01575                 targetLine[x] = uchar(vi);
01576             }
01577         }
01578     } else {
01579 
01580         float sy0 = getBinForY(v, 0);
01581 
01582         int psy0i = -1, psy1i = -1;
01583 
01584         for (int y = 0; y < h; ++y) {
01585 
01586             float sy1 = sy0;
01587             sy0 = getBinForY(v, y + 1);
01588 
01589             int sy0i = int(sy0 + epsilon);
01590             int sy1i = int(sy1);
01591 
01592             uchar *targetLine = img.scanLine(y);
01593 
01594             if (sy0i == psy0i && sy1i == psy1i) {
01595                 // same source scan line as just computed
01596                 goto copy;
01597             }
01598 
01599             psy0i = sy0i;
01600             psy1i = sy1i;
01601 
01602             for (int x = 0; x < w; ++x) {
01603                 peaks[x] = 0;
01604             }
01605         
01606             for (int sy = sy0i; sy <= sy1i; ++sy) {
01607 
01608                 if (sy < 0 || sy >= source->height()) continue;
01609 
01610                 uchar *sourceLine = source->scanLine(sy);
01611             
01612                 for (int x = 0; x < w; ++x) {
01613 
01614                     float sx1 = sxa[x*2 + 1];
01615                     if (sx1 < 0) continue;
01616                     int sx1i = int(sx1);
01617 
01618                     float sx0 = sxa[x*2];
01619                     if (sx0 < 0) continue;
01620                     int sx0i = int(sx0 + epsilon);
01621                     if (sx0i >= sw) break;
01622 
01623                     uchar peak = 0;
01624                     for (int sx = sx0i; sx <= sx1i; ++sx) {
01625                         if (sx < 0 || sx >= sw) continue;
01626                         if (sourceLine[sx] > peak) peak = sourceLine[sx];
01627                     }
01628                     peaks[x] = peak;
01629                 }
01630             }
01631         
01632         copy:
01633             for (int x = 0; x < w; ++x) {
01634                 targetLine[x] = peaks[x];
01635             }
01636         }
01637     }
01638 
01639     delete[] peaks;
01640 
01641     paint.drawImage(x0, 0, img);
01642 }
01643 
01644 bool
01645 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame,
01646                                       int &resolution,
01647                                       SnapType snap) const
01648 {
01649     if (!m_model) {
01650         return Layer::snapToFeatureFrame(v, frame, resolution, snap);
01651     }
01652 
01653     resolution = m_model->getResolution();
01654     int left = (frame / resolution) * resolution;
01655     int right = left + resolution;
01656 
01657     switch (snap) {
01658     case SnapLeft:  frame = left;  break;
01659     case SnapRight: frame = right; break;
01660     case SnapNearest:
01661     case SnapNeighbouring:
01662         if (frame - left > right - frame) frame = right;
01663         else frame = left;
01664         break;
01665     }
01666     
01667     return true;
01668 }
01669 
01670 void
01671 Colour3DPlotLayer::toXml(QTextStream &stream,
01672                          QString indent, QString extraAttributes) const
01673 {
01674     QString s = QString("scale=\"%1\" "
01675                         "colourScheme=\"%2\" "
01676                         "normalizeColumns=\"%3\" "
01677                         "normalizeVisibleArea=\"%4\" "
01678                         "minY=\"%5\" "
01679                         "maxY=\"%6\" "
01680                         "invertVertical=\"%7\" "
01681                         "opaque=\"%8\" %9")
01682         .arg((int)m_colourScale)
01683         .arg(m_colourMap)
01684         .arg(m_normalizeColumns ? "true" : "false")
01685         .arg(m_normalizeVisibleArea ? "true" : "false")
01686         .arg(m_miny)
01687         .arg(m_maxy)
01688         .arg(m_invertVertical ? "true" : "false")
01689         .arg(m_opaque ? "true" : "false")
01690         .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
01691              .arg((int)m_binScale)
01692              .arg(m_smooth ? "true" : "false")
01693              .arg(m_gain));
01694     
01695     Layer::toXml(stream, indent, extraAttributes + " " + s);
01696 }
01697 
01698 void
01699 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
01700 {
01701     bool ok = false, alsoOk = false;
01702 
01703     ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok);
01704     if (ok) setColourScale(scale);
01705 
01706     int colourMap = attributes.value("colourScheme").toInt(&ok);
01707     if (ok) setColourMap(colourMap);
01708 
01709     BinScale binscale = (BinScale)attributes.value("binScale").toInt(&ok);
01710     if (ok) setBinScale(binscale);
01711 
01712     bool normalizeColumns =
01713         (attributes.value("normalizeColumns").trimmed() == "true");
01714     setNormalizeColumns(normalizeColumns);
01715 
01716     bool normalizeVisibleArea =
01717         (attributes.value("normalizeVisibleArea").trimmed() == "true");
01718     setNormalizeVisibleArea(normalizeVisibleArea);
01719 
01720     bool invertVertical =
01721         (attributes.value("invertVertical").trimmed() == "true");
01722     setInvertVertical(invertVertical);
01723 
01724     bool opaque =
01725         (attributes.value("opaque").trimmed() == "true");
01726     setOpaque(opaque);
01727 
01728     bool smooth =
01729         (attributes.value("smooth").trimmed() == "true");
01730     setSmooth(smooth);
01731 
01732     float gain = attributes.value("gain").toFloat(&ok);
01733     if (ok) setGain(gain);
01734 
01735     float min = attributes.value("minY").toFloat(&ok);
01736     float max = attributes.value("maxY").toFloat(&alsoOk);
01737     if (ok && alsoOk) setDisplayExtents(min, max);
01738 }
01739