svgui
1.9
|
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