| Chris@58 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@0 | 2 | 
| Chris@0 | 3 /* | 
| Chris@59 | 4     Sonic Visualiser | 
| Chris@59 | 5     An audio file viewer and annotation editor. | 
| Chris@59 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@182 | 7     This file copyright 2006 Chris Cannam and QMUL. | 
| Chris@0 | 8 | 
| Chris@59 | 9     This program is free software; you can redistribute it and/or | 
| Chris@59 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@59 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@59 | 12     License, or (at your option) any later version.  See the file | 
| Chris@59 | 13     COPYING included with this distribution for more information. | 
| Chris@0 | 14 */ | 
| Chris@0 | 15 | 
| Chris@0 | 16 #include "Colour3DPlotLayer.h" | 
| Chris@0 | 17 | 
| Chris@128 | 18 #include "view/View.h" | 
| Chris@0 | 19 #include "base/Profiler.h" | 
| Chris@197 | 20 #include "base/LogRange.h" | 
| Chris@444 | 21 #include "base/RangeMapper.h" | 
| Chris@376 | 22 #include "ColourMapper.h" | 
| Chris@0 | 23 | 
| Chris@0 | 24 #include <QPainter> | 
| Chris@0 | 25 #include <QImage> | 
| Chris@0 | 26 #include <QRect> | 
| Chris@316 | 27 #include <QTextStream> | 
| Chris@0 | 28 | 
| Chris@0 | 29 #include <iostream> | 
| Chris@0 | 30 | 
| Chris@0 | 31 #include <cassert> | 
| Chris@0 | 32 | 
| Chris@545 | 33 #ifndef __GNUC__ | 
| Chris@545 | 34 #include <alloca.h> | 
| Chris@545 | 35 #endif | 
| Chris@545 | 36 | 
| Chris@353 | 37 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1 | 
| Chris@125 | 38 | 
| Chris@0 | 39 | 
| Chris@44 | 40 Colour3DPlotLayer::Colour3DPlotLayer() : | 
| Chris@0 | 41     m_model(0), | 
| Chris@159 | 42     m_cache(0), | 
| Chris@469 | 43     m_peaksCache(0), | 
| Chris@461 | 44     m_cacheValidStart(0), | 
| Chris@461 | 45     m_cacheValidEnd(0), | 
| Chris@197 | 46     m_colourScale(LinearScale), | 
| Chris@461 | 47     m_colourScaleSet(false), | 
| Chris@197 | 48     m_colourMap(0), | 
| Chris@534 | 49     m_gain(1.0), | 
| Chris@531 | 50     m_binScale(LinearBinScale), | 
| Chris@197 | 51     m_normalizeColumns(false), | 
| Chris@357 | 52     m_normalizeVisibleArea(false), | 
| Chris@719 | 53     m_normalizeHybrid(false), | 
| Chris@444 | 54     m_invertVertical(false), | 
| Chris@465 | 55     m_opaque(false), | 
| Chris@535 | 56     m_smooth(false), | 
| Chris@805 | 57     m_peakResolution(256), | 
| Chris@444 | 58     m_miny(0), | 
| Chris@444 | 59     m_maxy(0) | 
| Chris@0 | 60 { | 
| Chris@44 | 61 | 
| Chris@0 | 62 } | 
| Chris@0 | 63 | 
| Chris@0 | 64 Colour3DPlotLayer::~Colour3DPlotLayer() | 
| Chris@0 | 65 { | 
| Chris@461 | 66     delete m_cache; | 
| Chris@469 | 67     delete m_peaksCache; | 
| Chris@0 | 68 } | 
| Chris@0 | 69 | 
| Chris@0 | 70 void | 
| Chris@0 | 71 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model) | 
| Chris@0 | 72 { | 
| Chris@193 | 73     if (m_model == model) return; | 
| Chris@193 | 74     const DenseThreeDimensionalModel *oldModel = m_model; | 
| Chris@0 | 75     m_model = model; | 
| Chris@0 | 76     if (!m_model || !m_model->isOK()) return; | 
| Chris@0 | 77 | 
| Chris@320 | 78     connectSignals(m_model); | 
| Chris@0 | 79 | 
| Chris@461 | 80     connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged())); | 
| Chris@823 | 81     connect(m_model, SIGNAL(modelChangedWithin(int, int)), | 
| Chris@823 | 82 	    this, SLOT(modelChangedWithin(int, int))); | 
| Chris@0 | 83 | 
| Chris@474 | 84     m_peakResolution = 256; | 
| Chris@474 | 85     if (model->getResolution() > 512) { | 
| Chris@474 | 86         m_peakResolution = 16; | 
| Chris@474 | 87     } else if (model->getResolution() > 128) { | 
| Chris@474 | 88         m_peakResolution = 64; | 
| Chris@474 | 89     } else if (model->getResolution() > 2) { | 
| Chris@474 | 90         m_peakResolution = 128; | 
| Chris@474 | 91     } | 
| Chris@474 | 92     cacheInvalid(); | 
| Chris@474 | 93 | 
| Chris@0 | 94     emit modelReplaced(); | 
| Chris@193 | 95     emit sliceableModelReplaced(oldModel, model); | 
| Chris@0 | 96 } | 
| Chris@0 | 97 | 
| Chris@0 | 98 void | 
| Chris@0 | 99 Colour3DPlotLayer::cacheInvalid() | 
| Chris@0 | 100 { | 
| Chris@469 | 101     delete m_cache; | 
| Chris@469 | 102     delete m_peaksCache; | 
| Chris@0 | 103     m_cache = 0; | 
| Chris@469 | 104     m_peaksCache = 0; | 
| Chris@461 | 105     m_cacheValidStart = 0; | 
| Chris@461 | 106     m_cacheValidEnd = 0; | 
| Chris@0 | 107 } | 
| Chris@0 | 108 | 
| Chris@0 | 109 void | 
| Chris@805 | 110 Colour3DPlotLayer::cacheInvalid(int startFrame, int endFrame) | 
| Chris@0 | 111 { | 
| Chris@843 | 112     if (!m_cache || !m_model) return; | 
| Chris@461 | 113 | 
| Chris@805 | 114     int modelResolution = m_model->getResolution(); | 
| Chris@805 | 115     int start = startFrame / modelResolution; | 
| Chris@805 | 116     int end = endFrame / modelResolution + 1; | 
| Chris@461 | 117     if (m_cacheValidStart < end) m_cacheValidStart = end; | 
| Chris@461 | 118     if (m_cacheValidEnd > start) m_cacheValidEnd = start; | 
| Chris@461 | 119     if (m_cacheValidStart > m_cacheValidEnd) m_cacheValidEnd = m_cacheValidStart; | 
| Chris@461 | 120 } | 
| Chris@461 | 121 | 
| Chris@461 | 122 void | 
| Chris@461 | 123 Colour3DPlotLayer::modelChanged() | 
| Chris@461 | 124 { | 
| Chris@461 | 125     if (!m_colourScaleSet && m_colourScale == LinearScale) { | 
| Chris@461 | 126         if (m_model) { | 
| Chris@461 | 127             if (m_model->shouldUseLogValueScale()) { | 
| Chris@461 | 128                 setColourScale(LogScale); | 
| Chris@461 | 129             } else { | 
| Chris@461 | 130                 m_colourScaleSet = true; | 
| Chris@461 | 131             } | 
| Chris@461 | 132         } | 
| Chris@461 | 133     } | 
| Chris@0 | 134     cacheInvalid(); | 
| Chris@0 | 135 } | 
| Chris@0 | 136 | 
| Chris@461 | 137 void | 
| Chris@823 | 138 Colour3DPlotLayer::modelChangedWithin(int startFrame, int endFrame) | 
| Chris@461 | 139 { | 
| Chris@461 | 140     if (!m_colourScaleSet && m_colourScale == LinearScale) { | 
| Chris@461 | 141         if (m_model && m_model->getWidth() > 50) { | 
| Chris@461 | 142             if (m_model->shouldUseLogValueScale()) { | 
| Chris@461 | 143                 setColourScale(LogScale); | 
| Chris@461 | 144             } else { | 
| Chris@461 | 145                 m_colourScaleSet = true; | 
| Chris@461 | 146             } | 
| Chris@461 | 147         } | 
| Chris@461 | 148     } | 
| Chris@461 | 149     cacheInvalid(startFrame, endFrame); | 
| Chris@461 | 150 } | 
| Chris@461 | 151 | 
| Chris@159 | 152 Layer::PropertyList | 
| Chris@159 | 153 Colour3DPlotLayer::getProperties() const | 
| Chris@159 | 154 { | 
| Chris@159 | 155     PropertyList list; | 
| Chris@197 | 156     list.push_back("Colour"); | 
| Chris@159 | 157     list.push_back("Colour Scale"); | 
| Chris@197 | 158     list.push_back("Normalize Columns"); | 
| Chris@197 | 159     list.push_back("Normalize Visible Area"); | 
| Chris@534 | 160     list.push_back("Gain"); | 
| Chris@531 | 161     list.push_back("Bin Scale"); | 
| Chris@357 | 162     list.push_back("Invert Vertical Scale"); | 
| Chris@465 | 163     list.push_back("Opaque"); | 
| Chris@535 | 164     list.push_back("Smooth"); | 
| Chris@159 | 165     return list; | 
| Chris@159 | 166 } | 
| Chris@159 | 167 | 
| Chris@159 | 168 QString | 
| Chris@159 | 169 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const | 
| Chris@159 | 170 { | 
| Chris@197 | 171     if (name == "Colour") return tr("Colour"); | 
| Chris@197 | 172     if (name == "Colour Scale") return tr("Scale"); | 
| Chris@197 | 173     if (name == "Normalize Columns") return tr("Normalize Columns"); | 
| Chris@197 | 174     if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); | 
| Chris@357 | 175     if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); | 
| Chris@534 | 176     if (name == "Gain") return tr("Gain"); | 
| Chris@465 | 177     if (name == "Opaque") return tr("Always Opaque"); | 
| Chris@535 | 178     if (name == "Smooth") return tr("Smooth"); | 
| Chris@531 | 179     if (name == "Bin Scale") return tr("Bin Scale"); | 
| Chris@159 | 180     return ""; | 
| Chris@159 | 181 } | 
| Chris@159 | 182 | 
| Chris@346 | 183 QString | 
| Chris@346 | 184 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const | 
| Chris@346 | 185 { | 
| Chris@346 | 186     if (name == "Normalize Columns") return "normalise-columns"; | 
| Chris@346 | 187     if (name == "Normalize Visible Area") return "normalise"; | 
| Chris@357 | 188     if (name == "Invert Vertical Scale") return "invert-vertical"; | 
| Chris@465 | 189     if (name == "Opaque") return "opaque"; | 
| Chris@535 | 190     if (name == "Smooth") return "smooth"; | 
| Chris@346 | 191     return ""; | 
| Chris@346 | 192 } | 
| Chris@346 | 193 | 
| Chris@159 | 194 Layer::PropertyType | 
| Chris@159 | 195 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const | 
| Chris@159 | 196 { | 
| Chris@534 | 197     if (name == "Gain") return RangeProperty; | 
| Chris@197 | 198     if (name == "Normalize Columns") return ToggleProperty; | 
| Chris@197 | 199     if (name == "Normalize Visible Area") return ToggleProperty; | 
| Chris@357 | 200     if (name == "Invert Vertical Scale") return ToggleProperty; | 
| Chris@465 | 201     if (name == "Opaque") return ToggleProperty; | 
| Chris@535 | 202     if (name == "Smooth") return ToggleProperty; | 
| Chris@159 | 203     return ValueProperty; | 
| Chris@159 | 204 } | 
| Chris@159 | 205 | 
| Chris@159 | 206 QString | 
| Chris@159 | 207 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const | 
| Chris@159 | 208 { | 
| Chris@197 | 209     if (name == "Normalize Columns" || | 
| Chris@197 | 210         name == "Normalize Visible Area" || | 
| Chris@534 | 211 	name == "Colour Scale" || | 
| Chris@534 | 212         name == "Gain") return tr("Scale"); | 
| Chris@531 | 213     if (name == "Bin Scale" || | 
| Chris@531 | 214         name == "Invert Vertical Scale") return tr("Bins"); | 
| Chris@465 | 215     if (name == "Opaque" || | 
| Chris@535 | 216         name == "Smooth" || | 
| Chris@465 | 217         name == "Colour") return tr("Colour"); | 
| Chris@159 | 218     return QString(); | 
| Chris@159 | 219 } | 
| Chris@159 | 220 | 
| Chris@159 | 221 int | 
| Chris@159 | 222 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name, | 
| Chris@216 | 223                                             int *min, int *max, int *deflt) const | 
| Chris@159 | 224 { | 
| Chris@216 | 225     int val = 0; | 
| Chris@159 | 226 | 
| Chris@216 | 227     int garbage0, garbage1, garbage2; | 
| Chris@159 | 228     if (!min) min = &garbage0; | 
| Chris@159 | 229     if (!max) max = &garbage1; | 
| Chris@216 | 230     if (!deflt) deflt = &garbage2; | 
| Chris@159 | 231 | 
| Chris@534 | 232     if (name == "Gain") { | 
| Chris@534 | 233 | 
| Chris@534 | 234 	*min = -50; | 
| Chris@534 | 235 	*max = 50; | 
| Chris@534 | 236 | 
| Chris@902 | 237         *deflt = int(lrint(log10(1.0) * 20.0)); | 
| Chris@534 | 238 	if (*deflt < *min) *deflt = *min; | 
| Chris@534 | 239 	if (*deflt > *max) *deflt = *max; | 
| Chris@534 | 240 | 
| Chris@902 | 241 	val = int(lrint(log10(m_gain) * 20.0)); | 
| Chris@534 | 242 	if (val < *min) val = *min; | 
| Chris@534 | 243 	if (val > *max) val = *max; | 
| Chris@534 | 244 | 
| Chris@534 | 245     } else if (name == "Colour Scale") { | 
| Chris@159 | 246 | 
| Chris@159 | 247 	*min = 0; | 
| Chris@509 | 248 	*max = 3; | 
| Chris@216 | 249         *deflt = (int)LinearScale; | 
| Chris@159 | 250 | 
| Chris@216 | 251 	val = (int)m_colourScale; | 
| Chris@159 | 252 | 
| Chris@197 | 253     } else if (name == "Colour") { | 
| Chris@197 | 254 | 
| Chris@197 | 255 	*min = 0; | 
| Chris@197 | 256 	*max = ColourMapper::getColourMapCount() - 1; | 
| Chris@216 | 257         *deflt = 0; | 
| Chris@197 | 258 | 
| Chris@216 | 259 	val = m_colourMap; | 
| Chris@197 | 260 | 
| Chris@197 | 261     } else if (name == "Normalize Columns") { | 
| Chris@197 | 262 | 
| Chris@216 | 263         *deflt = 0; | 
| Chris@216 | 264 	val = (m_normalizeColumns ? 1 : 0); | 
| Chris@197 | 265 | 
| Chris@197 | 266     } else if (name == "Normalize Visible Area") { | 
| Chris@197 | 267 | 
| Chris@216 | 268         *deflt = 0; | 
| Chris@216 | 269 	val = (m_normalizeVisibleArea ? 1 : 0); | 
| Chris@197 | 270 | 
| Chris@357 | 271     } else if (name == "Invert Vertical Scale") { | 
| Chris@357 | 272 | 
| Chris@357 | 273         *deflt = 0; | 
| Chris@357 | 274 	val = (m_invertVertical ? 1 : 0); | 
| Chris@357 | 275 | 
| Chris@531 | 276     } else if (name == "Bin Scale") { | 
| Chris@531 | 277 | 
| Chris@531 | 278 	*min = 0; | 
| Chris@531 | 279 	*max = 1; | 
| Chris@531 | 280         *deflt = int(LinearBinScale); | 
| Chris@531 | 281 	val = (int)m_binScale; | 
| Chris@531 | 282 | 
| Chris@465 | 283     } else if (name == "Opaque") { | 
| Chris@465 | 284 | 
| Chris@465 | 285         *deflt = 0; | 
| Chris@465 | 286 	val = (m_opaque ? 1 : 0); | 
| Chris@465 | 287 | 
| Chris@535 | 288     } else if (name == "Smooth") { | 
| Chris@535 | 289 | 
| Chris@535 | 290         *deflt = 0; | 
| Chris@535 | 291 	val = (m_smooth ? 1 : 0); | 
| Chris@535 | 292 | 
| Chris@159 | 293     } else { | 
| Chris@216 | 294 	val = Layer::getPropertyRangeAndValue(name, min, max, deflt); | 
| Chris@159 | 295     } | 
| Chris@159 | 296 | 
| Chris@216 | 297     return val; | 
| Chris@159 | 298 } | 
| Chris@159 | 299 | 
| Chris@159 | 300 QString | 
| Chris@159 | 301 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name, | 
| Chris@159 | 302 				    int value) const | 
| Chris@159 | 303 { | 
| Chris@197 | 304     if (name == "Colour") { | 
| Chris@197 | 305         return ColourMapper::getColourMapName(value); | 
| Chris@197 | 306     } | 
| Chris@159 | 307     if (name == "Colour Scale") { | 
| Chris@159 | 308 	switch (value) { | 
| Chris@159 | 309 	default: | 
| Chris@198 | 310 	case 0: return tr("Linear"); | 
| Chris@198 | 311 	case 1: return tr("Log"); | 
| Chris@198 | 312 	case 2: return tr("+/-1"); | 
| Chris@509 | 313 	case 3: return tr("Absolute"); | 
| Chris@159 | 314 	} | 
| Chris@159 | 315     } | 
| Chris@531 | 316     if (name == "Bin Scale") { | 
| Chris@531 | 317 	switch (value) { | 
| Chris@531 | 318 	default: | 
| Chris@531 | 319 	case 0: return tr("Linear"); | 
| Chris@531 | 320 	case 1: return tr("Log"); | 
| Chris@531 | 321 	} | 
| Chris@531 | 322     } | 
| Chris@159 | 323     return tr("<unknown>"); | 
| Chris@159 | 324 } | 
| Chris@159 | 325 | 
| Chris@534 | 326 RangeMapper * | 
| Chris@534 | 327 Colour3DPlotLayer::getNewPropertyRangeMapper(const PropertyName &name) const | 
| Chris@534 | 328 { | 
| Chris@534 | 329     if (name == "Gain") { | 
| Chris@534 | 330         return new LinearRangeMapper(-50, 50, -25, 25, tr("dB")); | 
| Chris@534 | 331     } | 
| Chris@534 | 332     return 0; | 
| Chris@534 | 333 } | 
| Chris@534 | 334 | 
| Chris@159 | 335 void | 
| Chris@159 | 336 Colour3DPlotLayer::setProperty(const PropertyName &name, int value) | 
| Chris@159 | 337 { | 
| Chris@534 | 338     if (name == "Gain") { | 
| Chris@902 | 339 	setGain(float(pow(10, value/20.0))); | 
| Chris@534 | 340     } else if (name == "Colour Scale") { | 
| Chris@159 | 341 	switch (value) { | 
| Chris@159 | 342 	default: | 
| Chris@159 | 343 	case 0: setColourScale(LinearScale); break; | 
| Chris@197 | 344 	case 1: setColourScale(LogScale); break; | 
| Chris@197 | 345 	case 2: setColourScale(PlusMinusOneScale); break; | 
| Chris@509 | 346 	case 3: setColourScale(AbsoluteScale); break; | 
| Chris@159 | 347 	} | 
| Chris@197 | 348     } else if (name == "Colour") { | 
| Chris@197 | 349         setColourMap(value); | 
| Chris@197 | 350     } else if (name == "Normalize Columns") { | 
| Chris@197 | 351 	setNormalizeColumns(value ? true : false); | 
| Chris@197 | 352     } else if (name == "Normalize Visible Area") { | 
| Chris@197 | 353 	setNormalizeVisibleArea(value ? true : false); | 
| Chris@357 | 354     } else if (name == "Invert Vertical Scale") { | 
| Chris@357 | 355 	setInvertVertical(value ? true : false); | 
| Chris@465 | 356     } else if (name == "Opaque") { | 
| Chris@465 | 357 	setOpaque(value ? true : false); | 
| Chris@535 | 358     } else if (name == "Smooth") { | 
| Chris@535 | 359 	setSmooth(value ? true : false); | 
| Chris@531 | 360     } else if (name == "Bin Scale") { | 
| Chris@531 | 361 	switch (value) { | 
| Chris@531 | 362 	default: | 
| Chris@531 | 363 	case 0: setBinScale(LinearBinScale); break; | 
| Chris@531 | 364 	case 1: setBinScale(LogBinScale); break; | 
| Chris@531 | 365 	} | 
| Chris@159 | 366     } | 
| Chris@159 | 367 } | 
| Chris@159 | 368 | 
| Chris@159 | 369 void | 
| Chris@159 | 370 Colour3DPlotLayer::setColourScale(ColourScale scale) | 
| Chris@159 | 371 { | 
| Chris@159 | 372     if (m_colourScale == scale) return; | 
| Chris@159 | 373     m_colourScale = scale; | 
| Chris@461 | 374     m_colourScaleSet = true; | 
| Chris@159 | 375     cacheInvalid(); | 
| Chris@159 | 376     emit layerParametersChanged(); | 
| Chris@159 | 377 } | 
| Chris@159 | 378 | 
| Chris@197 | 379 void | 
| Chris@197 | 380 Colour3DPlotLayer::setColourMap(int map) | 
| Chris@197 | 381 { | 
| Chris@197 | 382     if (m_colourMap == map) return; | 
| Chris@197 | 383     m_colourMap = map; | 
| Chris@197 | 384     cacheInvalid(); | 
| Chris@197 | 385     emit layerParametersChanged(); | 
| Chris@197 | 386 } | 
| Chris@197 | 387 | 
| Chris@197 | 388 void | 
| Chris@534 | 389 Colour3DPlotLayer::setGain(float gain) | 
| Chris@534 | 390 { | 
| Chris@534 | 391     if (m_gain == gain) return; | 
| Chris@534 | 392     m_gain = gain; | 
| Chris@534 | 393     cacheInvalid(); | 
| Chris@534 | 394     emit layerParametersChanged(); | 
| Chris@534 | 395 } | 
| Chris@534 | 396 | 
| Chris@534 | 397 float | 
| Chris@534 | 398 Colour3DPlotLayer::getGain() const | 
| Chris@534 | 399 { | 
| Chris@534 | 400     return m_gain; | 
| Chris@534 | 401 } | 
| Chris@534 | 402 | 
| Chris@534 | 403 void | 
| Chris@531 | 404 Colour3DPlotLayer::setBinScale(BinScale binScale) | 
| Chris@531 | 405 { | 
| Chris@531 | 406     if (m_binScale == binScale) return; | 
| Chris@531 | 407     m_binScale = binScale; | 
| Chris@531 | 408     cacheInvalid(); | 
| Chris@531 | 409     emit layerParametersChanged(); | 
| Chris@531 | 410 } | 
| Chris@531 | 411 | 
| Chris@531 | 412 Colour3DPlotLayer::BinScale | 
| Chris@531 | 413 Colour3DPlotLayer::getBinScale() const | 
| Chris@531 | 414 { | 
| Chris@531 | 415     return m_binScale; | 
| Chris@531 | 416 } | 
| Chris@531 | 417 | 
| Chris@531 | 418 void | 
| Chris@197 | 419 Colour3DPlotLayer::setNormalizeColumns(bool n) | 
| Chris@197 | 420 { | 
| Chris@197 | 421     if (m_normalizeColumns == n) return; | 
| Chris@197 | 422     m_normalizeColumns = n; | 
| Chris@197 | 423     cacheInvalid(); | 
| Chris@197 | 424     emit layerParametersChanged(); | 
| Chris@197 | 425 } | 
| Chris@197 | 426 | 
| Chris@197 | 427 bool | 
| Chris@197 | 428 Colour3DPlotLayer::getNormalizeColumns() const | 
| Chris@197 | 429 { | 
| Chris@197 | 430     return m_normalizeColumns; | 
| Chris@197 | 431 } | 
| Chris@197 | 432 | 
| Chris@197 | 433 void | 
| Chris@719 | 434 Colour3DPlotLayer::setNormalizeHybrid(bool n) | 
| Chris@719 | 435 { | 
| Chris@719 | 436     if (m_normalizeHybrid == n) return; | 
| Chris@719 | 437     m_normalizeHybrid = n; | 
| Chris@719 | 438     cacheInvalid(); | 
| Chris@719 | 439     emit layerParametersChanged(); | 
| Chris@719 | 440 } | 
| Chris@719 | 441 | 
| Chris@719 | 442 bool | 
| Chris@719 | 443 Colour3DPlotLayer::getNormalizeHybrid() const | 
| Chris@719 | 444 { | 
| Chris@719 | 445     return m_normalizeHybrid; | 
| Chris@719 | 446 } | 
| Chris@719 | 447 | 
| Chris@719 | 448 void | 
| Chris@197 | 449 Colour3DPlotLayer::setNormalizeVisibleArea(bool n) | 
| Chris@197 | 450 { | 
| Chris@197 | 451     if (m_normalizeVisibleArea == n) return; | 
| Chris@197 | 452     m_normalizeVisibleArea = n; | 
| Chris@197 | 453     cacheInvalid(); | 
| Chris@197 | 454     emit layerParametersChanged(); | 
| Chris@197 | 455 } | 
| Chris@197 | 456 | 
| Chris@197 | 457 bool | 
| Chris@197 | 458 Colour3DPlotLayer::getNormalizeVisibleArea() const | 
| Chris@197 | 459 { | 
| Chris@197 | 460     return m_normalizeVisibleArea; | 
| Chris@197 | 461 } | 
| Chris@197 | 462 | 
| Chris@357 | 463 void | 
| Chris@357 | 464 Colour3DPlotLayer::setInvertVertical(bool n) | 
| Chris@357 | 465 { | 
| Chris@357 | 466     if (m_invertVertical == n) return; | 
| Chris@357 | 467     m_invertVertical = n; | 
| Chris@357 | 468     cacheInvalid(); | 
| Chris@357 | 469     emit layerParametersChanged(); | 
| Chris@357 | 470 } | 
| Chris@357 | 471 | 
| Chris@465 | 472 void | 
| Chris@465 | 473 Colour3DPlotLayer::setOpaque(bool n) | 
| Chris@465 | 474 { | 
| Chris@465 | 475     if (m_opaque == n) return; | 
| Chris@465 | 476     m_opaque = n; | 
| Chris@465 | 477     emit layerParametersChanged(); | 
| Chris@465 | 478 } | 
| Chris@465 | 479 | 
| Chris@535 | 480 void | 
| Chris@535 | 481 Colour3DPlotLayer::setSmooth(bool n) | 
| Chris@535 | 482 { | 
| Chris@535 | 483     if (m_smooth == n) return; | 
| Chris@535 | 484     m_smooth = n; | 
| Chris@535 | 485     emit layerParametersChanged(); | 
| Chris@535 | 486 } | 
| Chris@535 | 487 | 
| Chris@357 | 488 bool | 
| Chris@357 | 489 Colour3DPlotLayer::getInvertVertical() const | 
| Chris@357 | 490 { | 
| Chris@357 | 491     return m_invertVertical; | 
| Chris@357 | 492 } | 
| Chris@357 | 493 | 
| Chris@25 | 494 bool | 
| Chris@465 | 495 Colour3DPlotLayer::getOpaque() const | 
| Chris@465 | 496 { | 
| Chris@465 | 497     return m_opaque; | 
| Chris@465 | 498 } | 
| Chris@465 | 499 | 
| Chris@535 | 500 bool | 
| Chris@535 | 501 Colour3DPlotLayer::getSmooth() const | 
| Chris@535 | 502 { | 
| Chris@535 | 503     return m_smooth; | 
| Chris@535 | 504 } | 
| Chris@535 | 505 | 
| Chris@475 | 506 void | 
| Chris@475 | 507 Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant) | 
| Chris@475 | 508 { | 
| Chris@475 | 509     if (dormant) { | 
| Chris@475 | 510 | 
| Chris@475 | 511 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 512         cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")" | 
| Chris@585 | 513                   << endl; | 
| Chris@475 | 514 #endif | 
| Chris@475 | 515 | 
| Chris@475 | 516         if (isLayerDormant(v)) { | 
| Chris@475 | 517             return; | 
| Chris@475 | 518         } | 
| Chris@475 | 519 | 
| Chris@475 | 520         Layer::setLayerDormant(v, true); | 
| Chris@475 | 521 | 
| Chris@475 | 522         cacheInvalid(); | 
| Chris@475 | 523 | 
| Chris@475 | 524     } else { | 
| Chris@475 | 525 | 
| Chris@475 | 526         Layer::setLayerDormant(v, false); | 
| Chris@475 | 527     } | 
| Chris@475 | 528 } | 
| Chris@475 | 529 | 
| Chris@465 | 530 bool | 
| Chris@44 | 531 Colour3DPlotLayer::isLayerScrollable(const View *v) const | 
| Chris@25 | 532 { | 
| Chris@812 | 533     if (m_normalizeVisibleArea) { | 
| Chris@812 | 534         return false; | 
| Chris@812 | 535     } | 
| Chris@812 | 536     if (shouldPaintDenseIn(v)) { | 
| Chris@812 | 537         return true; | 
| Chris@812 | 538     } | 
| Chris@25 | 539     QPoint discard; | 
| Chris@44 | 540     return !v->shouldIlluminateLocalFeatures(this, discard); | 
| Chris@25 | 541 } | 
| Chris@25 | 542 | 
| Chris@444 | 543 bool | 
| Chris@444 | 544 Colour3DPlotLayer::getValueExtents(float &min, float &max, | 
| Chris@444 | 545                                    bool &logarithmic, QString &unit) const | 
| Chris@444 | 546 { | 
| Chris@444 | 547     if (!m_model) return false; | 
| Chris@444 | 548 | 
| Chris@444 | 549     min = 0; | 
| Chris@902 | 550     max = float(m_model->getHeight()); | 
| Chris@444 | 551 | 
| Chris@444 | 552     logarithmic = false; | 
| Chris@444 | 553     unit = ""; | 
| Chris@444 | 554 | 
| Chris@444 | 555     return true; | 
| Chris@444 | 556 } | 
| Chris@444 | 557 | 
| Chris@444 | 558 bool | 
| Chris@444 | 559 Colour3DPlotLayer::getDisplayExtents(float &min, float &max) const | 
| Chris@444 | 560 { | 
| Chris@444 | 561     if (!m_model) return false; | 
| Chris@444 | 562 | 
| Chris@902 | 563     float hmax = float(m_model->getHeight()); | 
| Chris@902 | 564 | 
| Chris@902 | 565     min = float(m_miny); | 
| Chris@902 | 566     max = float(m_maxy); | 
| Chris@444 | 567     if (max <= min) { | 
| Chris@444 | 568         min = 0; | 
| Chris@902 | 569         max = hmax; | 
| Chris@444 | 570     } | 
| Chris@444 | 571     if (min < 0) min = 0; | 
| Chris@902 | 572     if (max > hmax) max = hmax; | 
| Chris@444 | 573 | 
| Chris@444 | 574     return true; | 
| Chris@444 | 575 } | 
| Chris@444 | 576 | 
| Chris@444 | 577 bool | 
| Chris@444 | 578 Colour3DPlotLayer::setDisplayExtents(float min, float max) | 
| Chris@444 | 579 { | 
| Chris@444 | 580     if (!m_model) return false; | 
| Chris@444 | 581 | 
| Chris@902 | 582     m_miny = int(lrintf(min)); | 
| Chris@902 | 583     m_maxy = int(lrintf(max)); | 
| Chris@444 | 584 | 
| Chris@444 | 585     emit layerParametersChanged(); | 
| Chris@444 | 586     return true; | 
| Chris@444 | 587 } | 
| Chris@444 | 588 | 
| Chris@725 | 589 bool | 
| Chris@805 | 590 Colour3DPlotLayer::getYScaleValue(const View *, int, | 
| Chris@805 | 591                                   float &, QString &) const | 
| Chris@725 | 592 { | 
| Chris@725 | 593     return false;//!!! | 
| Chris@725 | 594 } | 
| Chris@725 | 595 | 
| Chris@444 | 596 int | 
| Chris@444 | 597 Colour3DPlotLayer::getVerticalZoomSteps(int &defaultStep) const | 
| Chris@444 | 598 { | 
| Chris@444 | 599     if (!m_model) return 0; | 
| Chris@444 | 600 | 
| Chris@444 | 601     defaultStep = 0; | 
| Chris@444 | 602     int h = m_model->getHeight(); | 
| Chris@444 | 603     return h; | 
| Chris@444 | 604 } | 
| Chris@444 | 605 | 
| Chris@444 | 606 int | 
| Chris@444 | 607 Colour3DPlotLayer::getCurrentVerticalZoomStep() const | 
| Chris@444 | 608 { | 
| Chris@444 | 609     if (!m_model) return 0; | 
| Chris@444 | 610 | 
| Chris@444 | 611     float min, max; | 
| Chris@444 | 612     getDisplayExtents(min, max); | 
| Chris@902 | 613     return m_model->getHeight() - int(lrintf(max - min)); | 
| Chris@444 | 614 } | 
| Chris@444 | 615 | 
| Chris@444 | 616 void | 
| Chris@444 | 617 Colour3DPlotLayer::setVerticalZoomStep(int step) | 
| Chris@444 | 618 { | 
| Chris@444 | 619     if (!m_model) return; | 
| Chris@444 | 620 | 
| Chris@587 | 621 //    SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): before: miny = " << m_miny << ", maxy = " << m_maxy << endl; | 
| Chris@444 | 622 | 
| Chris@444 | 623     int dist = m_model->getHeight() - step; | 
| Chris@444 | 624     if (dist < 1) dist = 1; | 
| Chris@902 | 625     float centre = float(m_miny) + (float(m_maxy) - float(m_miny)) / 2.f; | 
| Chris@902 | 626     m_miny = int(lrintf(centre - float(dist)/2)); | 
| Chris@444 | 627     if (m_miny < 0) m_miny = 0; | 
| Chris@444 | 628     m_maxy = m_miny + dist; | 
| Chris@444 | 629     if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight(); | 
| Chris@444 | 630 | 
| Chris@587 | 631 //    SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"):  after: miny = " << m_miny << ", maxy = " << m_maxy << endl; | 
| Chris@444 | 632 | 
| Chris@444 | 633     emit layerParametersChanged(); | 
| Chris@444 | 634 } | 
| Chris@444 | 635 | 
| Chris@444 | 636 RangeMapper * | 
| Chris@444 | 637 Colour3DPlotLayer::getNewVerticalZoomRangeMapper() const | 
| Chris@444 | 638 { | 
| Chris@444 | 639     if (!m_model) return 0; | 
| Chris@444 | 640 | 
| Chris@444 | 641     return new LinearRangeMapper(0, m_model->getHeight(), | 
| Chris@444 | 642                                  0, m_model->getHeight(), ""); | 
| Chris@444 | 643 } | 
| Chris@444 | 644 | 
| Chris@532 | 645 float | 
| Chris@532 | 646 Colour3DPlotLayer::getYForBin(View *v, float bin) const | 
| Chris@532 | 647 { | 
| Chris@532 | 648     float y = bin; | 
| Chris@532 | 649     if (!m_model) return y; | 
| Chris@902 | 650     float mn = 0, mx = float(m_model->getHeight()); | 
| Chris@532 | 651     getDisplayExtents(mn, mx); | 
| Chris@902 | 652     float h = float(v->height()); | 
| Chris@532 | 653     if (m_binScale == LinearBinScale) { | 
| Chris@532 | 654         y = h - (((bin - mn) * h) / (mx - mn)); | 
| Chris@532 | 655     } else { | 
| Chris@532 | 656         float logmin = mn + 1, logmax = mx + 1; | 
| Chris@532 | 657         LogRange::mapRange(logmin, logmax); | 
| Chris@532 | 658         y = h - (((LogRange::map(bin + 1) - logmin) * h) / (logmax - logmin)); | 
| Chris@532 | 659     } | 
| Chris@532 | 660     return y; | 
| Chris@532 | 661 } | 
| Chris@532 | 662 | 
| Chris@532 | 663 float | 
| Chris@532 | 664 Colour3DPlotLayer::getBinForY(View *v, float y) const | 
| Chris@532 | 665 { | 
| Chris@532 | 666     float bin = y; | 
| Chris@532 | 667     if (!m_model) return bin; | 
| Chris@902 | 668     float mn = 0, mx = float(m_model->getHeight()); | 
| Chris@532 | 669     getDisplayExtents(mn, mx); | 
| Chris@902 | 670     float h = float(v->height()); | 
| Chris@532 | 671     if (m_binScale == LinearBinScale) { | 
| Chris@532 | 672         bin = mn + ((h - y) * (mx - mn)) / h; | 
| Chris@532 | 673     } else { | 
| Chris@532 | 674         float logmin = mn + 1, logmax = mx + 1; | 
| Chris@532 | 675         LogRange::mapRange(logmin, logmax); | 
| Chris@532 | 676         bin = LogRange::unmap(logmin + ((h - y) * (logmax - logmin)) / h) - 1; | 
| Chris@532 | 677     } | 
| Chris@532 | 678     return bin; | 
| Chris@532 | 679 } | 
| Chris@532 | 680 | 
| Chris@25 | 681 QString | 
| Chris@44 | 682 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const | 
| Chris@25 | 683 { | 
| Chris@25 | 684     if (!m_model) return ""; | 
| Chris@25 | 685 | 
| Chris@25 | 686     int x = pos.x(); | 
| Chris@25 | 687     int y = pos.y(); | 
| Chris@25 | 688 | 
| Chris@902 | 689     sv_frame_t modelStart = m_model->getStartFrame(); | 
| Chris@805 | 690     int modelResolution = m_model->getResolution(); | 
| Chris@25 | 691 | 
| Chris@902 | 692     double srRatio = | 
| Chris@902 | 693         v->getViewManager()->getMainModelSampleRate() / | 
| Chris@902 | 694         m_model->getSampleRate(); | 
| Chris@159 | 695 | 
| Chris@902 | 696     int sx0 = int((double(v->getFrameForX(x)) / srRatio - double(modelStart)) / | 
| Chris@812 | 697                   modelResolution); | 
| Chris@25 | 698 | 
| Chris@160 | 699     int f0 = sx0 * modelResolution; | 
| Chris@160 | 700     int f1 =  f0 + modelResolution; | 
| Chris@160 | 701 | 
| Chris@447 | 702     int sh = m_model->getHeight(); | 
| Chris@447 | 703 | 
| Chris@447 | 704     int symin = m_miny; | 
| Chris@447 | 705     int symax = m_maxy; | 
| Chris@447 | 706     if (symax <= symin) { | 
| Chris@447 | 707         symin = 0; | 
| Chris@447 | 708         symax = sh; | 
| Chris@447 | 709     } | 
| Chris@447 | 710     if (symin < 0) symin = 0; | 
| Chris@447 | 711     if (symax > sh) symax = sh; | 
| Chris@447 | 712 | 
| Chris@534 | 713  //    float binHeight = float(v->height()) / (symax - symin); | 
| Chris@534 | 714 //    int sy = int((v->height() - y) / binHeight) + symin; | 
| Chris@534 | 715 | 
| Chris@902 | 716     int sy = int(getBinForY(v, float(y))); | 
| Chris@25 | 717 | 
| Chris@812 | 718     if (sy < 0 || sy >= m_model->getHeight()) { | 
| Chris@812 | 719         return ""; | 
| Chris@812 | 720     } | 
| Chris@812 | 721 | 
| Chris@357 | 722     if (m_invertVertical) sy = m_model->getHeight() - sy - 1; | 
| Chris@357 | 723 | 
| Chris@160 | 724     float value = m_model->getValueAt(sx0, sy); | 
| Chris@159 | 725 | 
| Chris@682 | 726 //    cerr << "bin value (" << sx0 << "," << sy << ") is " << value << endl; | 
| Chris@25 | 727 | 
| Chris@25 | 728     QString binName = m_model->getBinName(sy); | 
| Chris@25 | 729     if (binName == "") binName = QString("[%1]").arg(sy + 1); | 
| Chris@25 | 730     else binName = QString("%1 [%2]").arg(binName).arg(sy + 1); | 
| Chris@25 | 731 | 
| Chris@25 | 732     QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4") | 
| Chris@160 | 733 	.arg(RealTime::frame2RealTime(f0, m_model->getSampleRate()) | 
| Chris@25 | 734 	     .toText(true).c_str()) | 
| Chris@160 | 735 	.arg(RealTime::frame2RealTime(f1, m_model->getSampleRate()) | 
| Chris@25 | 736 	     .toText(true).c_str()) | 
| Chris@25 | 737 	.arg(binName) | 
| Chris@25 | 738 	.arg(value); | 
| Chris@25 | 739 | 
| Chris@25 | 740     return text; | 
| Chris@25 | 741 } | 
| Chris@25 | 742 | 
| Chris@25 | 743 int | 
| Chris@248 | 744 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const | 
| Chris@159 | 745 { | 
| Chris@159 | 746     int cw = 20; | 
| Chris@159 | 747     return cw; | 
| Chris@159 | 748 } | 
| Chris@159 | 749 | 
| Chris@159 | 750 int | 
| Chris@607 | 751 Colour3DPlotLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const | 
| Chris@25 | 752 { | 
| Chris@25 | 753     if (!m_model) return 0; | 
| Chris@25 | 754 | 
| Chris@160 | 755     QString sampleText = QString("[%1]").arg(m_model->getHeight()); | 
| Chris@25 | 756     int tw = paint.fontMetrics().width(sampleText); | 
| Chris@98 | 757     bool another = false; | 
| Chris@25 | 758 | 
| Chris@805 | 759     for (int i = 0; i < m_model->getHeight(); ++i) { | 
| Chris@25 | 760 	if (m_model->getBinName(i).length() > sampleText.length()) { | 
| Chris@25 | 761 	    sampleText = m_model->getBinName(i); | 
| Chris@98 | 762             another = true; | 
| Chris@25 | 763 	} | 
| Chris@25 | 764     } | 
| Chris@98 | 765     if (another) { | 
| Chris@25 | 766 	tw = std::max(tw, paint.fontMetrics().width(sampleText)); | 
| Chris@25 | 767     } | 
| Chris@25 | 768 | 
| Chris@159 | 769     return tw + 13 + getColourScaleWidth(paint); | 
| Chris@25 | 770 } | 
| Chris@25 | 771 | 
| Chris@25 | 772 void | 
| Chris@607 | 773 Colour3DPlotLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const | 
| Chris@25 | 774 { | 
| Chris@25 | 775     if (!m_model) return; | 
| Chris@25 | 776 | 
| Chris@25 | 777     int h = rect.height(), w = rect.width(); | 
| Chris@25 | 778 | 
| Chris@159 | 779     int cw = getColourScaleWidth(paint); | 
| Chris@159 | 780 | 
| Chris@159 | 781     int ch = h - 20; | 
| Chris@159 | 782     if (ch > 20 && m_cache) { | 
| Chris@159 | 783 | 
| Chris@447 | 784         float min = m_model->getMinimumLevel(); | 
| Chris@447 | 785         float max = m_model->getMaximumLevel(); | 
| Chris@447 | 786 | 
| Chris@447 | 787         float mmin = min; | 
| Chris@447 | 788         float mmax = max; | 
| Chris@447 | 789 | 
| Chris@447 | 790         if (m_colourScale == LogScale) { | 
| Chris@447 | 791             LogRange::mapRange(mmin, mmax); | 
| Chris@447 | 792         } else if (m_colourScale == PlusMinusOneScale) { | 
| Chris@447 | 793             mmin = -1.f; | 
| Chris@447 | 794             mmax = 1.f; | 
| Chris@509 | 795         } else if (m_colourScale == AbsoluteScale) { | 
| Chris@509 | 796             if (mmin < 0) { | 
| Chris@509 | 797                 if (fabsf(mmin) > fabsf(mmax)) mmax = fabsf(mmin); | 
| Chris@509 | 798                 else mmax = fabsf(mmax); | 
| Chris@509 | 799                 mmin = 0; | 
| Chris@509 | 800             } else { | 
| Chris@509 | 801                 mmin = fabsf(mmin); | 
| Chris@509 | 802                 mmax = fabsf(mmax); | 
| Chris@509 | 803             } | 
| Chris@447 | 804         } | 
| Chris@447 | 805 | 
| Chris@902 | 806         if (max == min) max = min + 1.f; | 
| Chris@902 | 807         if (mmax == mmin) mmax = mmin + 1.f; | 
| Chris@447 | 808 | 
| Chris@287 | 809         paint.setPen(v->getForeground()); | 
| Chris@447 | 810         paint.drawRect(4, 10, cw - 8, ch+1); | 
| Chris@159 | 811 | 
| Chris@446 | 812         for (int y = 0; y < ch; ++y) { | 
| Chris@902 | 813             float value = ((max - min) * (float(ch-y) - 1.f)) / float(ch) + min; | 
| Chris@447 | 814             if (m_colourScale == LogScale) { | 
| Chris@447 | 815                 value = LogRange::map(value); | 
| Chris@447 | 816             } | 
| Chris@447 | 817             int pixel = int(((value - mmin) * 256) / (mmax - mmin)); | 
| Chris@465 | 818             if (pixel >= 0 && pixel < 256) { | 
| Chris@465 | 819                 QRgb c = m_cache->color(pixel); | 
| Chris@465 | 820                 paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c))); | 
| Chris@465 | 821                 paint.drawLine(5, 11 + y, cw - 5, 11 + y); | 
| Chris@465 | 822             } else { | 
| Chris@682 | 823                 cerr << "WARNING: Colour3DPlotLayer::paintVerticalScale: value " << value << ", mmin " << mmin << ", mmax " << mmax << " leads to invalid pixel " << pixel << endl; | 
| Chris@465 | 824             } | 
| Chris@159 | 825         } | 
| Chris@446 | 826 | 
| Chris@446 | 827         QString minstr = QString("%1").arg(min); | 
| Chris@446 | 828         QString maxstr = QString("%1").arg(max); | 
| Chris@446 | 829 | 
| Chris@446 | 830         paint.save(); | 
| Chris@446 | 831 | 
| Chris@446 | 832         QFont font = paint.font(); | 
| Chris@446 | 833         font.setPixelSize(10); | 
| Chris@446 | 834         paint.setFont(font); | 
| Chris@446 | 835 | 
| Chris@446 | 836         int msw = paint.fontMetrics().width(maxstr); | 
| Chris@446 | 837 | 
| Chris@446 | 838         QMatrix m; | 
| Chris@446 | 839         m.translate(cw - 6, ch + 10); | 
| Chris@446 | 840         m.rotate(-90); | 
| Chris@446 | 841 | 
| Chris@446 | 842         paint.setWorldMatrix(m); | 
| Chris@446 | 843 | 
| Chris@446 | 844         v->drawVisibleText(paint, 2, 0, minstr, View::OutlinedText); | 
| Chris@446 | 845 | 
| Chris@446 | 846         m.translate(ch - msw - 2, 0); | 
| Chris@446 | 847         paint.setWorldMatrix(m); | 
| Chris@446 | 848 | 
| Chris@446 | 849         v->drawVisibleText(paint, 0, 0, maxstr, View::OutlinedText); | 
| Chris@446 | 850 | 
| Chris@446 | 851         paint.restore(); | 
| Chris@159 | 852     } | 
| Chris@159 | 853 | 
| Chris@287 | 854     paint.setPen(v->getForeground()); | 
| Chris@159 | 855 | 
| Chris@445 | 856     int sh = m_model->getHeight(); | 
| Chris@445 | 857 | 
| Chris@445 | 858     int symin = m_miny; | 
| Chris@445 | 859     int symax = m_maxy; | 
| Chris@445 | 860     if (symax <= symin) { | 
| Chris@445 | 861         symin = 0; | 
| Chris@445 | 862         symax = sh; | 
| Chris@445 | 863     } | 
| Chris@445 | 864     if (symin < 0) symin = 0; | 
| Chris@445 | 865     if (symax > sh) symax = sh; | 
| Chris@445 | 866 | 
| Chris@532 | 867     paint.save(); | 
| Chris@456 | 868 | 
| Chris@533 | 869     int py = h; | 
| Chris@25 | 870 | 
| Chris@805 | 871     for (int i = symin; i <= symax; ++i) { | 
| Chris@98 | 872 | 
| Chris@532 | 873         int y0; | 
| Chris@534 | 874 | 
| Chris@902 | 875         y0 = int(lrint(getYForBin(v, float(i)))); | 
| Chris@532 | 876         int h = py - y0; | 
| Chris@532 | 877 | 
| Chris@532 | 878         if (i > symin) { | 
| Chris@532 | 879             if (paint.fontMetrics().height() >= h) { | 
| Chris@533 | 880                 if (h >= 8) { | 
| Chris@532 | 881                     QFont tf = paint.font(); | 
| Chris@533 | 882                     tf.setPixelSize(h-2); | 
| Chris@532 | 883                     paint.setFont(tf); | 
| Chris@532 | 884                 } else { | 
| Chris@532 | 885                     continue; | 
| Chris@532 | 886                 } | 
| Chris@532 | 887             } | 
| Chris@532 | 888         } | 
| Chris@25 | 889 | 
| Chris@532 | 890         py = y0; | 
| Chris@532 | 891 | 
| Chris@534 | 892         if (i < symax) { | 
| Chris@534 | 893             paint.drawLine(cw, y0, w, y0); | 
| Chris@534 | 894         } | 
| Chris@25 | 895 | 
| Chris@532 | 896         if (i > symin) { | 
| Chris@534 | 897 | 
| Chris@805 | 898             int idx = i - 1; | 
| Chris@534 | 899             if (m_invertVertical) idx = m_model->getHeight() - idx - 1; | 
| Chris@534 | 900 | 
| Chris@534 | 901             QString text = m_model->getBinName(idx); | 
| Chris@534 | 902             if (text == "") text = QString("[%1]").arg(idx + 1); | 
| Chris@534 | 903 | 
| Chris@534 | 904             int ty = y0 + (h/2) - (paint.fontMetrics().height()/2) + | 
| Chris@534 | 905                 paint.fontMetrics().ascent() + 1; | 
| Chris@534 | 906 | 
| Chris@534 | 907             paint.drawText(cw + 5, ty, text); | 
| Chris@457 | 908         } | 
| Chris@25 | 909     } | 
| Chris@456 | 910 | 
| Chris@456 | 911     paint.restore(); | 
| Chris@25 | 912 } | 
| Chris@25 | 913 | 
| Chris@467 | 914 DenseThreeDimensionalModel::Column | 
| Chris@805 | 915 Colour3DPlotLayer::getColumn(int col) const | 
| Chris@197 | 916 { | 
| Chris@812 | 917     Profiler profiler("Colour3DPlotLayer::getColumn"); | 
| Chris@812 | 918 | 
| Chris@467 | 919     DenseThreeDimensionalModel::Column values = m_model->getColumn(col); | 
| Chris@468 | 920     while (values.size() < m_model->getHeight()) values.push_back(0.f); | 
| Chris@719 | 921     if (!m_normalizeColumns && !m_normalizeHybrid) return values; | 
| Chris@461 | 922 | 
| Chris@224 | 923     float colMax = 0.f, colMin = 0.f; | 
| Chris@461 | 924     float min = 0.f, max = 0.f; | 
| Chris@197 | 925 | 
| Chris@461 | 926     min = m_model->getMinimumLevel(); | 
| Chris@461 | 927     max = m_model->getMaximumLevel(); | 
| Chris@461 | 928 | 
| Chris@805 | 929     for (int y = 0; y < values.size(); ++y) { | 
| Chris@467 | 930         if (y == 0 || values.at(y) > colMax) colMax = values.at(y); | 
| Chris@467 | 931         if (y == 0 || values.at(y) < colMin) colMin = values.at(y); | 
| Chris@197 | 932     } | 
| Chris@461 | 933     if (colMin == colMax) colMax = colMin + 1; | 
| Chris@197 | 934 | 
| Chris@805 | 935     for (int y = 0; y < values.size(); ++y) { | 
| Chris@461 | 936 | 
| Chris@467 | 937         float value = values.at(y); | 
| Chris@461 | 938         float norm = (value - colMin) / (colMax - colMin); | 
| Chris@467 | 939         float newvalue = min + (max - min) * norm; | 
| Chris@197 | 940 | 
| Chris@467 | 941         if (value != newvalue) values[y] = newvalue; | 
| Chris@468 | 942     } | 
| Chris@468 | 943 | 
| Chris@719 | 944     if (m_normalizeHybrid && (colMax > 0.0)) { | 
| Chris@902 | 945         float logmax = log10f(colMax); | 
| Chris@805 | 946         for (int y = 0; y < values.size(); ++y) { | 
| Chris@719 | 947             values[y] *= logmax; | 
| Chris@719 | 948         } | 
| Chris@719 | 949     } | 
| Chris@719 | 950 | 
| Chris@468 | 951     return values; | 
| Chris@197 | 952 } | 
| Chris@197 | 953 | 
| Chris@197 | 954 void | 
| Chris@805 | 955 Colour3DPlotLayer::fillCache(int firstBin, int lastBin) const | 
| Chris@197 | 956 { | 
| Chris@812 | 957     Profiler profiler("Colour3DPlotLayer::fillCache", true); | 
| Chris@476 | 958 | 
| Chris@902 | 959     sv_frame_t modelStart = m_model->getStartFrame(); | 
| Chris@902 | 960     sv_frame_t modelEnd = m_model->getEndFrame(); | 
| Chris@805 | 961     int modelResolution = m_model->getResolution(); | 
| Chris@197 | 962 | 
| Chris@902 | 963     int modelStartBin = int(modelStart / modelResolution); | 
| Chris@902 | 964     int modelEndBin = int(modelEnd / modelResolution); | 
| Chris@461 | 965 | 
| Chris@812 | 966 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 967     cerr << "Colour3DPlotLayer::fillCache: range " << firstBin << " -> " << lastBin << " of model range " << modelStartBin << " -> " << modelEndBin << " (model resolution " << modelResolution << ")" << endl; | 
| Chris@812 | 968 #endif | 
| Chris@812 | 969 | 
| Chris@805 | 970     int cacheWidth = modelEndBin - modelStartBin + 1; | 
| Chris@471 | 971     if (lastBin > modelEndBin) cacheWidth = lastBin - modelStartBin + 1; | 
| Chris@805 | 972     int cacheHeight = m_model->getHeight(); | 
| Chris@461 | 973 | 
| Chris@812 | 974     if (m_cache && m_cache->height() != cacheHeight) { | 
| Chris@742 | 975         // height has changed: delete everything rather than resizing | 
| Chris@812 | 976 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 977         cerr << "Colour3DPlotLayer::fillCache: Cache height has changed, recreating" << endl; | 
| Chris@812 | 978 #endif | 
| Chris@461 | 979         delete m_cache; | 
| Chris@469 | 980         delete m_peaksCache; | 
| Chris@461 | 981         m_cache = 0; | 
| Chris@469 | 982         m_peaksCache = 0; | 
| Chris@461 | 983     } | 
| Chris@461 | 984 | 
| Chris@812 | 985     if (m_cache && m_cache->width() != cacheWidth) { | 
| Chris@742 | 986         // width has changed and we have an existing cache: resize it | 
| Chris@812 | 987 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 988         cerr << "Colour3DPlotLayer::fillCache: Cache width has changed, resizing existing cache" << endl; | 
| Chris@812 | 989 #endif | 
| Chris@469 | 990         QImage *newCache = | 
| Chris@469 | 991             new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight)); | 
| Chris@461 | 992         delete m_cache; | 
| Chris@461 | 993         m_cache = newCache; | 
| Chris@469 | 994         if (m_peaksCache) { | 
| Chris@469 | 995             QImage *newPeaksCache = | 
| Chris@469 | 996                 new QImage(m_peaksCache->copy | 
| Chris@742 | 997                            (0, 0, cacheWidth / m_peakResolution + 1, cacheHeight)); | 
| Chris@469 | 998             delete m_peaksCache; | 
| Chris@469 | 999             m_peaksCache = newPeaksCache; | 
| Chris@469 | 1000         } | 
| Chris@197 | 1001     } | 
| Chris@197 | 1002 | 
| Chris@461 | 1003     if (!m_cache) { | 
| Chris@812 | 1004 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1005         cerr << "Colour3DPlotLayer::fillCache: Have no cache, making one" << endl; | 
| Chris@812 | 1006 #endif | 
| Chris@469 | 1007         m_cache = new QImage | 
| Chris@469 | 1008             (cacheWidth, cacheHeight, QImage::Format_Indexed8); | 
| Chris@812 | 1009         m_cache->setColorCount(256); | 
| Chris@514 | 1010         m_cache->fill(0); | 
| Chris@474 | 1011         if (!m_normalizeVisibleArea) { | 
| Chris@469 | 1012             m_peaksCache = new QImage | 
| Chris@469 | 1013                 (cacheWidth / m_peakResolution + 1, cacheHeight, | 
| Chris@469 | 1014                  QImage::Format_Indexed8); | 
| Chris@812 | 1015             m_peaksCache->setColorCount(256); | 
| Chris@514 | 1016             m_peaksCache->fill(0); | 
| Chris@469 | 1017         } else if (m_peaksCache) { | 
| Chris@469 | 1018             delete m_peaksCache; | 
| Chris@469 | 1019             m_peaksCache = 0; | 
| Chris@469 | 1020         } | 
| Chris@461 | 1021         m_cacheValidStart = 0; | 
| Chris@461 | 1022         m_cacheValidEnd = 0; | 
| Chris@197 | 1023     } | 
| Chris@197 | 1024 | 
| Chris@812 | 1025 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1026     cerr << "cache size = " << m_cache->width() << "x" << m_cache->height() | 
| Chris@812 | 1027          << " peaks cache size = " << m_peaksCache->width() << "x" << m_peaksCache->height() << endl; | 
| Chris@812 | 1028 #endif | 
| Chris@742 | 1029 | 
| Chris@461 | 1030     if (m_cacheValidStart <= firstBin && m_cacheValidEnd >= lastBin) { | 
| Chris@519 | 1031 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@682 | 1032         cerr << "Cache is valid in this region already" << endl; | 
| Chris@519 | 1033 #endif | 
| Chris@461 | 1034         return; | 
| Chris@461 | 1035     } | 
| Chris@461 | 1036 | 
| Chris@805 | 1037     int fillStart = firstBin; | 
| Chris@805 | 1038     int fillEnd = lastBin; | 
| Chris@197 | 1039 | 
| Chris@461 | 1040     if (fillStart < modelStartBin) fillStart = modelStartBin; | 
| Chris@461 | 1041     if (fillStart > modelEndBin) fillStart = modelEndBin; | 
| Chris@461 | 1042     if (fillEnd < modelStartBin) fillEnd = modelStartBin; | 
| Chris@461 | 1043     if (fillEnd > modelEndBin) fillEnd = modelEndBin; | 
| Chris@197 | 1044 | 
| Chris@461 | 1045     bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns); | 
| Chris@197 | 1046 | 
| Chris@461 | 1047     if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) { | 
| Chris@461 | 1048 | 
| Chris@461 | 1049         if (m_cacheValidEnd < fillStart) { | 
| Chris@461 | 1050             fillStart = m_cacheValidEnd + 1; | 
| Chris@461 | 1051         } | 
| Chris@461 | 1052         if (m_cacheValidStart > fillEnd) { | 
| Chris@461 | 1053             fillEnd = m_cacheValidStart - 1; | 
| Chris@461 | 1054         } | 
| Chris@461 | 1055 | 
| Chris@461 | 1056         m_cacheValidStart = std::min(fillStart, m_cacheValidStart); | 
| Chris@461 | 1057         m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd); | 
| Chris@461 | 1058 | 
| Chris@461 | 1059     } else { | 
| Chris@461 | 1060 | 
| Chris@812 | 1061         // when normalising the visible area, the only valid area, | 
| Chris@812 | 1062         // ever, is the currently visible one | 
| Chris@461 | 1063 | 
| Chris@461 | 1064         m_cacheValidStart = fillStart; | 
| Chris@461 | 1065         m_cacheValidEnd = fillEnd; | 
| Chris@461 | 1066     } | 
| Chris@461 | 1067 | 
| Chris@519 | 1068 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1069     cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << " (fillStart = " << fillStart << ", fillEnd = " << fillEnd << ")" << endl; | 
| Chris@519 | 1070 #endif | 
| Chris@461 | 1071 | 
| Chris@197 | 1072     DenseThreeDimensionalModel::Column values; | 
| Chris@197 | 1073 | 
| Chris@197 | 1074     float min = m_model->getMinimumLevel(); | 
| Chris@197 | 1075     float max = m_model->getMaximumLevel(); | 
| Chris@197 | 1076 | 
| Chris@197 | 1077     if (m_colourScale == LogScale) { | 
| Chris@197 | 1078         LogRange::mapRange(min, max); | 
| Chris@197 | 1079     } else if (m_colourScale == PlusMinusOneScale) { | 
| Chris@197 | 1080         min = -1.f; | 
| Chris@197 | 1081         max = 1.f; | 
| Chris@509 | 1082     } else if (m_colourScale == AbsoluteScale) { | 
| Chris@509 | 1083         if (min < 0) { | 
| Chris@509 | 1084             if (fabsf(min) > fabsf(max)) max = fabsf(min); | 
| Chris@509 | 1085             else max = fabsf(max); | 
| Chris@509 | 1086             min = 0; | 
| Chris@509 | 1087         } else { | 
| Chris@509 | 1088             min = fabsf(min); | 
| Chris@509 | 1089             max = fabsf(max); | 
| Chris@509 | 1090         } | 
| Chris@197 | 1091     } | 
| Chris@197 | 1092 | 
| Chris@902 | 1093     if (max == min) max = min + 1.f; | 
| Chris@197 | 1094 | 
| Chris@197 | 1095     ColourMapper mapper(m_colourMap, 0.f, 255.f); | 
| Chris@197 | 1096 | 
| Chris@197 | 1097     for (int index = 0; index < 256; ++index) { | 
| Chris@197 | 1098         QColor colour = mapper.map(index); | 
| Chris@469 | 1099         m_cache->setColor | 
| Chris@469 | 1100             (index, qRgb(colour.red(), colour.green(), colour.blue())); | 
| Chris@469 | 1101         if (m_peaksCache) { | 
| Chris@469 | 1102             m_peaksCache->setColor | 
| Chris@469 | 1103                 (index, qRgb(colour.red(), colour.green(), colour.blue())); | 
| Chris@469 | 1104         } | 
| Chris@197 | 1105     } | 
| Chris@197 | 1106 | 
| Chris@224 | 1107     float visibleMax = 0.f, visibleMin = 0.f; | 
| Chris@197 | 1108 | 
| Chris@461 | 1109     if (normalizeVisible) { | 
| Chris@197 | 1110 | 
| Chris@805 | 1111         for (int c = fillStart; c <= fillEnd; ++c) { | 
| Chris@197 | 1112 | 
| Chris@467 | 1113             values = getColumn(c); | 
| Chris@197 | 1114 | 
| Chris@224 | 1115             float colMax = 0.f, colMin = 0.f; | 
| Chris@197 | 1116 | 
| Chris@805 | 1117             for (int y = 0; y < cacheHeight; ++y) { | 
| Chris@197 | 1118                 if (y >= values.size()) break; | 
| Chris@197 | 1119                 if (y == 0 || values[y] > colMax) colMax = values[y]; | 
| Chris@224 | 1120                 if (y == 0 || values[y] < colMin) colMin = values[y]; | 
| Chris@197 | 1121             } | 
| Chris@197 | 1122 | 
| Chris@461 | 1123             if (c == fillStart || colMax > visibleMax) visibleMax = colMax; | 
| Chris@461 | 1124             if (c == fillStart || colMin < visibleMin) visibleMin = colMin; | 
| Chris@461 | 1125         } | 
| Chris@461 | 1126 | 
| Chris@461 | 1127         if (m_colourScale == LogScale) { | 
| Chris@461 | 1128             visibleMin = LogRange::map(visibleMin); | 
| Chris@461 | 1129             visibleMax = LogRange::map(visibleMax); | 
| Chris@461 | 1130             if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax); | 
| Chris@509 | 1131         } else if (m_colourScale == AbsoluteScale) { | 
| Chris@509 | 1132             if (visibleMin < 0) { | 
| Chris@509 | 1133                 if (fabsf(visibleMin) > fabsf(visibleMax)) visibleMax = fabsf(visibleMin); | 
| Chris@509 | 1134                 else visibleMax = fabsf(visibleMax); | 
| Chris@509 | 1135                 visibleMin = 0; | 
| Chris@509 | 1136             } else { | 
| Chris@509 | 1137                 visibleMin = fabsf(visibleMin); | 
| Chris@509 | 1138                 visibleMax = fabsf(visibleMax); | 
| Chris@509 | 1139             } | 
| Chris@197 | 1140         } | 
| Chris@197 | 1141     } | 
| Chris@197 | 1142 | 
| Chris@224 | 1143     if (visibleMin == visibleMax) visibleMax = visibleMin + 1; | 
| Chris@224 | 1144 | 
| Chris@469 | 1145     int *peaks = 0; | 
| Chris@469 | 1146     if (m_peaksCache) { | 
| Chris@469 | 1147         peaks = new int[cacheHeight]; | 
| Chris@469 | 1148         for (int y = 0; y < cacheHeight; ++y) { | 
| Chris@469 | 1149             peaks[y] = 0; | 
| Chris@469 | 1150         } | 
| Chris@469 | 1151     } | 
| Chris@469 | 1152 | 
| Chris@812 | 1153     Profiler profiler2("Colour3DPlotLayer::fillCache: filling", true); | 
| Chris@812 | 1154 | 
| Chris@805 | 1155     for (int c = fillStart; c <= fillEnd; ++c) { | 
| Chris@197 | 1156 | 
| Chris@467 | 1157         values = getColumn(c); | 
| Chris@197 | 1158 | 
| Chris@742 | 1159         if (c >= m_cache->width()) { | 
| Chris@742 | 1160             cerr << "ERROR: column " << c << " >= cache width " | 
| Chris@742 | 1161                  << m_cache->width() << endl; | 
| Chris@742 | 1162             continue; | 
| Chris@742 | 1163         } | 
| Chris@742 | 1164 | 
| Chris@805 | 1165         for (int y = 0; y < cacheHeight; ++y) { | 
| Chris@197 | 1166 | 
| Chris@197 | 1167             float value = min; | 
| Chris@197 | 1168             if (y < values.size()) { | 
| Chris@469 | 1169                 value = values.at(y); | 
| Chris@197 | 1170             } | 
| Chris@224 | 1171 | 
| Chris@534 | 1172             value = value * m_gain; | 
| Chris@534 | 1173 | 
| Chris@224 | 1174             if (m_colourScale == LogScale) { | 
| Chris@224 | 1175                 value = LogRange::map(value); | 
| Chris@509 | 1176             } else if (m_colourScale == AbsoluteScale) { | 
| Chris@509 | 1177                 value = fabsf(value); | 
| Chris@197 | 1178             } | 
| Chris@461 | 1179 | 
| Chris@461 | 1180             if (normalizeVisible) { | 
| Chris@461 | 1181                 float norm = (value - visibleMin) / (visibleMax - visibleMin); | 
| Chris@461 | 1182                 value = min + (max - min) * norm; | 
| Chris@461 | 1183             } | 
| Chris@197 | 1184 | 
| Chris@197 | 1185             int pixel = int(((value - min) * 256) / (max - min)); | 
| Chris@197 | 1186             if (pixel < 0) pixel = 0; | 
| Chris@197 | 1187             if (pixel > 255) pixel = 255; | 
| Chris@469 | 1188             if (peaks && (pixel > peaks[y])) peaks[y] = pixel; | 
| Chris@197 | 1189 | 
| Chris@357 | 1190             if (m_invertVertical) { | 
| Chris@461 | 1191                 m_cache->setPixel(c, cacheHeight - y - 1, pixel); | 
| Chris@357 | 1192             } else { | 
| Chris@742 | 1193                 if (y >= m_cache->height()) { | 
| Chris@742 | 1194                     cerr << "ERROR: row " << y << " >= cache height " << m_cache->height() << endl; | 
| Chris@742 | 1195                 } else { | 
| Chris@742 | 1196                     m_cache->setPixel(c, y, pixel); | 
| Chris@742 | 1197                 } | 
| Chris@357 | 1198             } | 
| Chris@197 | 1199         } | 
| Chris@469 | 1200 | 
| Chris@469 | 1201         if (peaks) { | 
| Chris@805 | 1202             int notch = (c % m_peakResolution); | 
| Chris@469 | 1203             if (notch == m_peakResolution-1 || c == fillEnd) { | 
| Chris@805 | 1204                 int pc = c / m_peakResolution; | 
| Chris@742 | 1205                 if (pc >= m_peaksCache->width()) { | 
| Chris@742 | 1206                     cerr << "ERROR: peak column " << pc | 
| Chris@742 | 1207                          << " (from col " << c << ") >= peaks cache width " | 
| Chris@742 | 1208                          << m_peaksCache->width() << endl; | 
| Chris@742 | 1209                     continue; | 
| Chris@742 | 1210                 } | 
| Chris@805 | 1211                 for (int y = 0; y < cacheHeight; ++y) { | 
| Chris@469 | 1212                     if (m_invertVertical) { | 
| Chris@469 | 1213                         m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]); | 
| Chris@469 | 1214                     } else { | 
| Chris@742 | 1215                         if (y >= m_peaksCache->height()) { | 
| Chris@742 | 1216                             cerr << "ERROR: row " << y | 
| Chris@742 | 1217                                  << " >= peaks cache height " | 
| Chris@742 | 1218                                  << m_peaksCache->height() << endl; | 
| Chris@742 | 1219                         } else { | 
| Chris@742 | 1220                             m_peaksCache->setPixel(pc, y, peaks[y]); | 
| Chris@742 | 1221                         } | 
| Chris@469 | 1222                     } | 
| Chris@469 | 1223                 } | 
| Chris@469 | 1224                 for (int y = 0; y < cacheHeight; ++y) { | 
| Chris@469 | 1225                     peaks[y] = 0; | 
| Chris@469 | 1226                 } | 
| Chris@469 | 1227             } | 
| Chris@469 | 1228         } | 
| Chris@197 | 1229     } | 
| Chris@469 | 1230 | 
| Chris@469 | 1231     delete[] peaks; | 
| Chris@197 | 1232 } | 
| Chris@197 | 1233 | 
| Chris@812 | 1234 bool | 
| Chris@812 | 1235 Colour3DPlotLayer::shouldPaintDenseIn(const View *v) const | 
| Chris@812 | 1236 { | 
| Chris@812 | 1237     if (!m_model || !v || !(v->getViewManager())) { | 
| Chris@812 | 1238         return false; | 
| Chris@812 | 1239     } | 
| Chris@902 | 1240     double srRatio = | 
| Chris@902 | 1241         v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate(); | 
| Chris@812 | 1242     if (m_opaque || | 
| Chris@812 | 1243         m_smooth || | 
| Chris@812 | 1244         m_model->getHeight() >= v->height() || | 
| Chris@812 | 1245         ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) { | 
| Chris@812 | 1246         return true; | 
| Chris@812 | 1247     } | 
| Chris@812 | 1248     return false; | 
| Chris@812 | 1249 } | 
| Chris@812 | 1250 | 
| Chris@197 | 1251 void | 
| Chris@44 | 1252 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const | 
| Chris@0 | 1253 { | 
| Chris@514 | 1254 /* | 
| Chris@443 | 1255     if (m_model) { | 
| Chris@587 | 1256         SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl; | 
| Chris@443 | 1257     } | 
| Chris@514 | 1258 */ | 
| Chris@466 | 1259     Profiler profiler("Colour3DPlotLayer::paint"); | 
| Chris@125 | 1260 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1261     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; | 
| Chris@125 | 1262 #endif | 
| Chris@0 | 1263 | 
| Chris@0 | 1264     int completion = 0; | 
| Chris@0 | 1265     if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) { | 
| Chris@0 | 1266 	if (completion > 0) { | 
| Chris@44 | 1267 	    paint.fillRect(0, 10, v->width() * completion / 100, | 
| Chris@0 | 1268 			   10, QColor(120, 120, 120)); | 
| Chris@0 | 1269 	} | 
| Chris@0 | 1270 	return; | 
| Chris@0 | 1271     } | 
| Chris@0 | 1272 | 
| Chris@197 | 1273     if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect(); | 
| Chris@197 | 1274 | 
| Chris@902 | 1275     sv_frame_t modelStart = m_model->getStartFrame(); | 
| Chris@902 | 1276     sv_frame_t modelEnd = m_model->getEndFrame(); | 
| Chris@805 | 1277     int modelResolution = m_model->getResolution(); | 
| Chris@0 | 1278 | 
| Chris@197 | 1279     // The cache is from the model's start frame to the model's end | 
| Chris@197 | 1280     // frame at the model's window increment frames per pixel.  We | 
| Chris@197 | 1281     // want to draw from our start frame + x0 * zoomLevel to our start | 
| Chris@197 | 1282     // frame + x1 * zoomLevel at zoomLevel frames per pixel. | 
| Chris@12 | 1283 | 
| Chris@197 | 1284     //  We have quite different paint mechanisms for rendering "large" | 
| Chris@197 | 1285     //  bins (more than one bin per pixel in both directions) and | 
| Chris@197 | 1286     //  "small".  This is "large"; see paintDense below for "small". | 
| Chris@12 | 1287 | 
| Chris@197 | 1288     int x0 = rect.left(); | 
| Chris@197 | 1289     int x1 = rect.right() + 1; | 
| Chris@12 | 1290 | 
| Chris@197 | 1291     int h = v->height(); | 
| Chris@0 | 1292 | 
| Chris@902 | 1293     double srRatio = | 
| Chris@902 | 1294         v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate(); | 
| Chris@0 | 1295 | 
| Chris@902 | 1296     int sx0 = int((double(v->getFrameForX(x0)) / srRatio - double(modelStart)) | 
| Chris@812 | 1297                   / modelResolution); | 
| Chris@902 | 1298     int sx1 = int((double(v->getFrameForX(x1)) / srRatio - double(modelStart)) | 
| Chris@812 | 1299                   / modelResolution); | 
| Chris@197 | 1300     int sh = m_model->getHeight(); | 
| Chris@159 | 1301 | 
| Chris@444 | 1302     int symin = m_miny; | 
| Chris@444 | 1303     int symax = m_maxy; | 
| Chris@444 | 1304     if (symax <= symin) { | 
| Chris@444 | 1305         symin = 0; | 
| Chris@444 | 1306         symax = sh; | 
| Chris@444 | 1307     } | 
| Chris@444 | 1308     if (symin < 0) symin = 0; | 
| Chris@444 | 1309     if (symax > sh) symax = sh; | 
| Chris@444 | 1310 | 
| Chris@197 | 1311     if (sx0 > 0) --sx0; | 
| Chris@197 | 1312     fillCache(sx0 < 0 ? 0 : sx0, | 
| Chris@197 | 1313               sx1 < 0 ? 0 : sx1); | 
| Chris@0 | 1314 | 
| Chris@351 | 1315 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1316     cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << endl; | 
| Chris@351 | 1317 #endif | 
| Chris@351 | 1318 | 
| Chris@812 | 1319     if (shouldPaintDenseIn(v)) { | 
| Chris@347 | 1320 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1321         cerr << "calling paintDense" << endl; | 
| Chris@347 | 1322 #endif | 
| Chris@98 | 1323         paintDense(v, paint, rect); | 
| Chris@98 | 1324         return; | 
| Chris@98 | 1325     } | 
| Chris@98 | 1326 | 
| Chris@125 | 1327 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1328     cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << endl; | 
| Chris@682 | 1329     cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << endl; | 
| Chris@125 | 1330 #endif | 
| Chris@0 | 1331 | 
| Chris@25 | 1332     QPoint illuminatePos; | 
| Chris@44 | 1333     bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos); | 
| Chris@864 | 1334 | 
| Chris@864 | 1335     const int buflen = 40; | 
| Chris@864 | 1336     char labelbuf[buflen]; | 
| Chris@25 | 1337 | 
| Chris@197 | 1338     for (int sx = sx0; sx <= sx1; ++sx) { | 
| Chris@0 | 1339 | 
| Chris@902 | 1340 	sv_frame_t fx = sx * modelResolution; | 
| Chris@0 | 1341 | 
| Chris@812 | 1342 	if (fx + modelResolution <= modelStart || fx > modelEnd) continue; | 
| Chris@0 | 1343 | 
| Chris@902 | 1344         int rx0 = v->getXForFrame(int(double(fx + modelStart) * srRatio)); | 
| Chris@902 | 1345 	int rx1 = v->getXForFrame(int(double(fx + modelStart + modelResolution + 1) * srRatio)); | 
| Chris@54 | 1346 | 
| Chris@159 | 1347 	int rw = rx1 - rx0; | 
| Chris@159 | 1348 	if (rw < 1) rw = 1; | 
| Chris@54 | 1349 | 
| Chris@159 | 1350 	bool showLabel = (rw > 10 && | 
| Chris@159 | 1351 			  paint.fontMetrics().width("0.000000") < rw - 3 && | 
| Chris@54 | 1352 			  paint.fontMetrics().height() < (h / sh)); | 
| Chris@98 | 1353 | 
| Chris@444 | 1354 	for (int sy = symin; sy < symax; ++sy) { | 
| Chris@0 | 1355 | 
| Chris@534 | 1356             int ry0 = getYForBin(v, sy); | 
| Chris@534 | 1357             int ry1 = getYForBin(v, sy + 1); | 
| Chris@534 | 1358             QRect r(rx0, ry1, rw, ry0 - ry1); | 
| Chris@534 | 1359 | 
| Chris@0 | 1360 	    QRgb pixel = qRgb(255, 255, 255); | 
| Chris@461 | 1361 	    if (sx >= 0 && sx < m_cache->width() && | 
| Chris@0 | 1362 		sy >= 0 && sy < m_cache->height()) { | 
| Chris@461 | 1363 		pixel = m_cache->pixel(sx, sy); | 
| Chris@0 | 1364 	    } | 
| Chris@0 | 1365 | 
| Chris@159 | 1366             if (rw == 1) { | 
| Chris@159 | 1367                 paint.setPen(pixel); | 
| Chris@159 | 1368                 paint.setBrush(Qt::NoBrush); | 
| Chris@159 | 1369                 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1); | 
| Chris@159 | 1370                 continue; | 
| Chris@159 | 1371             } | 
| Chris@159 | 1372 | 
| Chris@0 | 1373 	    QColor pen(255, 255, 255, 80); | 
| Chris@0 | 1374 	    QColor brush(pixel); | 
| Chris@159 | 1375 | 
| Chris@159 | 1376             if (rw > 3 && r.height() > 3) { | 
| Chris@159 | 1377                 brush.setAlpha(160); | 
| Chris@159 | 1378             } | 
| Chris@159 | 1379 | 
| Chris@0 | 1380 	    paint.setPen(Qt::NoPen); | 
| Chris@0 | 1381 	    paint.setBrush(brush); | 
| Chris@0 | 1382 | 
| Chris@25 | 1383 	    if (illuminate) { | 
| Chris@25 | 1384 		if (r.contains(illuminatePos)) { | 
| Chris@287 | 1385 		    paint.setPen(v->getForeground()); | 
| Chris@25 | 1386 		} | 
| Chris@25 | 1387 	    } | 
| Chris@76 | 1388 | 
| Chris@125 | 1389 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@682 | 1390 //            cerr << "rect " << r.x() << "," << r.y() << " " | 
| Chris@682 | 1391 //                      << r.width() << "x" << r.height() << endl; | 
| Chris@125 | 1392 #endif | 
| Chris@25 | 1393 | 
| Chris@25 | 1394 	    paint.drawRect(r); | 
| Chris@0 | 1395 | 
| Chris@54 | 1396 	    if (showLabel) { | 
| Chris@461 | 1397 		if (sx >= 0 && sx < m_cache->width() && | 
| Chris@54 | 1398 		    sy >= 0 && sy < m_cache->height()) { | 
| Chris@461 | 1399 		    float value = m_model->getValueAt(sx, sy); | 
| Chris@864 | 1400 		    snprintf(labelbuf, buflen, "%06f", value); | 
| Chris@54 | 1401 		    QString text(labelbuf); | 
| Chris@287 | 1402 		    paint.setPen(v->getBackground()); | 
| Chris@54 | 1403 		    paint.drawText(rx0 + 2, | 
| Chris@54 | 1404 				   ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(), | 
| Chris@54 | 1405 				   text); | 
| Chris@0 | 1406 		} | 
| Chris@0 | 1407 	    } | 
| Chris@0 | 1408 	} | 
| Chris@0 | 1409     } | 
| Chris@98 | 1410 } | 
| Chris@0 | 1411 | 
| Chris@98 | 1412 void | 
| Chris@98 | 1413 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const | 
| Chris@98 | 1414 { | 
| Chris@812 | 1415     Profiler profiler("Colour3DPlotLayer::paintDense", true); | 
| Chris@463 | 1416     if (!m_cache) return; | 
| Chris@463 | 1417 | 
| Chris@466 | 1418     float modelStart = m_model->getStartFrame(); | 
| Chris@466 | 1419     float modelResolution = m_model->getResolution(); | 
| Chris@0 | 1420 | 
| Chris@469 | 1421     int mmsr = v->getViewManager()->getMainModelSampleRate(); | 
| Chris@469 | 1422     int msr = m_model->getSampleRate(); | 
| Chris@469 | 1423     float srRatio = float(mmsr) / float(msr); | 
| Chris@159 | 1424 | 
| Chris@98 | 1425     int x0 = rect.left(); | 
| Chris@98 | 1426     int x1 = rect.right() + 1; | 
| Chris@0 | 1427 | 
| Chris@470 | 1428     const int w = x1 - x0; // const so it can be used as array size below | 
| Chris@471 | 1429     int h = v->height(); // we always paint full height | 
| Chris@160 | 1430     int sh = m_model->getHeight(); | 
| Chris@98 | 1431 | 
| Chris@444 | 1432     int symin = m_miny; | 
| Chris@444 | 1433     int symax = m_maxy; | 
| Chris@444 | 1434     if (symax <= symin) { | 
| Chris@444 | 1435         symin = 0; | 
| Chris@444 | 1436         symax = sh; | 
| Chris@444 | 1437     } | 
| Chris@444 | 1438     if (symin < 0) symin = 0; | 
| Chris@444 | 1439     if (symax > sh) symax = sh; | 
| Chris@444 | 1440 | 
| Chris@466 | 1441     QImage img(w, h, QImage::Format_Indexed8); | 
| Chris@466 | 1442     img.setColorTable(m_cache->colorTable()); | 
| Chris@98 | 1443 | 
| Chris@466 | 1444     uchar *peaks = new uchar[w]; | 
| Chris@466 | 1445     memset(peaks, 0, w); | 
| Chris@98 | 1446 | 
| Chris@469 | 1447     int zoomLevel = v->getZoomLevel(); | 
| Chris@469 | 1448 | 
| Chris@469 | 1449     QImage *source = m_cache; | 
| Chris@812 | 1450 | 
| Chris@812 | 1451 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1452     cerr << "modelResolution " << modelResolution << ", srRatio " | 
| Chris@812 | 1453          << srRatio << ", m_peakResolution " << m_peakResolution | 
| Chris@812 | 1454          << ", zoomLevel " << zoomLevel << ", result " | 
| Chris@812 | 1455          << ((modelResolution * srRatio * m_peakResolution) / zoomLevel) | 
| Chris@812 | 1456          << endl; | 
| Chris@812 | 1457 #endif | 
| Chris@474 | 1458 | 
| Chris@474 | 1459     if (m_peaksCache) { | 
| Chris@474 | 1460         if (((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) { | 
| Chris@812 | 1461 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1462             cerr << "using peaks cache" << endl; | 
| Chris@812 | 1463 #endif | 
| Chris@474 | 1464             source = m_peaksCache; | 
| Chris@474 | 1465             modelResolution *= m_peakResolution; | 
| Chris@474 | 1466         } else { | 
| Chris@812 | 1467 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1468             cerr << "not using peaks cache" << endl; | 
| Chris@812 | 1469 #endif | 
| Chris@474 | 1470         } | 
| Chris@469 | 1471     } else { | 
| Chris@812 | 1472 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1473         cerr << "have no peaks cache" << endl; | 
| Chris@812 | 1474 #endif | 
| Chris@469 | 1475     } | 
| Chris@469 | 1476 | 
| Chris@469 | 1477     int sw = source->width(); | 
| Chris@470 | 1478 | 
| Chris@812 | 1479     int xf = -1; | 
| Chris@812 | 1480     int nxf = v->getFrameForX(x0); | 
| Chris@470 | 1481 | 
| Chris@535 | 1482     float epsilon = 0.000001; | 
| Chris@535 | 1483 | 
| Chris@545 | 1484 #ifdef __GNUC__ | 
| Chris@535 | 1485     float sxa[w * 2]; | 
| Chris@545 | 1486 #else | 
| Chris@545 | 1487     float *sxa = (float *)alloca(w * 2 * sizeof(float)); | 
| Chris@545 | 1488 #endif | 
| Chris@470 | 1489     for (int x = 0; x < w; ++x) { | 
| Chris@470 | 1490 | 
| Chris@470 | 1491         xf = nxf; | 
| Chris@470 | 1492         nxf = xf + zoomLevel; | 
| Chris@470 | 1493 | 
| Chris@470 | 1494         float sx0 = (float(xf) / srRatio - modelStart) / modelResolution; | 
| Chris@470 | 1495         float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution; | 
| Chris@470 | 1496 | 
| Chris@535 | 1497         sxa[x*2] = sx0; | 
| Chris@535 | 1498         sxa[x*2 + 1] = sx1; | 
| Chris@470 | 1499     } | 
| Chris@466 | 1500 | 
| Chris@532 | 1501     float logmin = symin+1, logmax = symax+1; | 
| Chris@532 | 1502     LogRange::mapRange(logmin, logmax); | 
| Chris@532 | 1503 | 
| Chris@812 | 1504 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@812 | 1505     cerr << "m_smooth = " << m_smooth << ", w = " << w << ", h = " << h << endl; | 
| Chris@812 | 1506 #endif | 
| Chris@812 | 1507 | 
| Chris@535 | 1508     if (m_smooth) { | 
| Chris@535 | 1509 | 
| Chris@535 | 1510         for (int y = 0; y < h; ++y) { | 
| Chris@466 | 1511 | 
| Chris@535 | 1512             float sy = getBinForY(v, y) - 0.5; | 
| Chris@535 | 1513             int syi = int(sy + epsilon); | 
| Chris@535 | 1514             if (syi < 0 || syi >= source->height()) continue; | 
| Chris@531 | 1515 | 
| Chris@535 | 1516             uchar *targetLine = img.scanLine(y); | 
| Chris@535 | 1517             uchar *sourceLine = source->scanLine(syi); | 
| Chris@535 | 1518             uchar *nextSource; | 
| Chris@535 | 1519             if (syi + 1 < source->height()) { | 
| Chris@535 | 1520                 nextSource = source->scanLine(syi + 1); | 
| Chris@535 | 1521             } else { | 
| Chris@535 | 1522                 nextSource = sourceLine; | 
| Chris@535 | 1523             } | 
| Chris@466 | 1524 | 
| Chris@466 | 1525             for (int x = 0; x < w; ++x) { | 
| Chris@98 | 1526 | 
| Chris@535 | 1527                 targetLine[x] = 0; | 
| Chris@474 | 1528 | 
| Chris@535 | 1529                 float sx0 = sxa[x*2]; | 
| Chris@537 | 1530                 if (sx0 < 0) continue; | 
| Chris@535 | 1531                 int sx0i = int(sx0 + epsilon); | 
| Chris@474 | 1532                 if (sx0i >= sw) break; | 
| Chris@98 | 1533 | 
| Chris@843 | 1534                 float a = float(sourceLine[sx0i]); | 
| Chris@843 | 1535                 float b = a; | 
| Chris@843 | 1536                 float value; | 
| Chris@535 | 1537 | 
| Chris@535 | 1538                 float sx1 = sxa[x*2+1]; | 
| Chris@535 | 1539                 if (sx1 > sx0 + 1.f) { | 
| Chris@535 | 1540                     int sx1i = int(sx1); | 
| Chris@535 | 1541                     bool have = false; | 
| Chris@535 | 1542                     for (int sx = sx0i; sx <= sx1i; ++sx) { | 
| Chris@535 | 1543                         if (sx < 0 || sx >= sw) continue; | 
| Chris@535 | 1544                         if (!have) { | 
| Chris@535 | 1545                             a = float(sourceLine[sx]); | 
| Chris@535 | 1546                             b = float(nextSource[sx]); | 
| Chris@535 | 1547                             have = true; | 
| Chris@535 | 1548                         } else { | 
| Chris@535 | 1549                             a = std::max(a, float(sourceLine[sx])); | 
| Chris@535 | 1550                             b = std::max(b, float(nextSource[sx])); | 
| Chris@535 | 1551                         } | 
| Chris@535 | 1552                     } | 
| Chris@535 | 1553                     float yprop = sy - syi; | 
| Chris@535 | 1554                     value = (a * (1.f - yprop) + b * yprop); | 
| Chris@535 | 1555                 } else { | 
| Chris@535 | 1556                     a = float(sourceLine[sx0i]); | 
| Chris@535 | 1557                     b = float(nextSource[sx0i]); | 
| Chris@535 | 1558                     float yprop = sy - syi; | 
| Chris@535 | 1559                     value = (a * (1.f - yprop) + b * yprop); | 
| Chris@535 | 1560                     int oi = sx0i + 1; | 
| Chris@535 | 1561                     float xprop = sx0 - sx0i; | 
| Chris@535 | 1562                     xprop -= 0.5; | 
| Chris@535 | 1563                     if (xprop < 0) { | 
| Chris@535 | 1564                         oi = sx0i - 1; | 
| Chris@535 | 1565                         xprop = -xprop; | 
| Chris@535 | 1566                     } | 
| Chris@535 | 1567                     if (oi < 0 || oi >= sw) oi = sx0i; | 
| Chris@535 | 1568                     a = float(sourceLine[oi]); | 
| Chris@535 | 1569                     b = float(nextSource[oi]); | 
| Chris@535 | 1570                     value = (value * (1.f - xprop) + | 
| Chris@535 | 1571                              (a * (1.f - yprop) + b * yprop) * xprop); | 
| Chris@98 | 1572                 } | 
| Chris@535 | 1573 | 
| Chris@535 | 1574                 int vi = lrintf(value); | 
| Chris@535 | 1575                 if (vi > 255) vi = 255; | 
| Chris@535 | 1576                 if (vi < 0) vi = 0; | 
| Chris@535 | 1577                 targetLine[x] = uchar(vi); | 
| Chris@98 | 1578             } | 
| Chris@466 | 1579         } | 
| Chris@535 | 1580     } else { | 
| Chris@535 | 1581 | 
| Chris@812 | 1582         float sy0 = getBinForY(v, 0); | 
| Chris@812 | 1583 | 
| Chris@812 | 1584         int psy0i = -1, psy1i = -1; | 
| Chris@812 | 1585 | 
| Chris@535 | 1586         for (int y = 0; y < h; ++y) { | 
| Chris@535 | 1587 | 
| Chris@812 | 1588             float sy1 = sy0; | 
| Chris@535 | 1589             sy0 = getBinForY(v, y + 1); | 
| Chris@535 | 1590 | 
| Chris@535 | 1591             int sy0i = int(sy0 + epsilon); | 
| Chris@535 | 1592             int sy1i = int(sy1); | 
| Chris@535 | 1593 | 
| Chris@535 | 1594             uchar *targetLine = img.scanLine(y); | 
| Chris@535 | 1595 | 
| Chris@812 | 1596             if (sy0i == psy0i && sy1i == psy1i) { | 
| Chris@812 | 1597                 // same source scan line as just computed | 
| Chris@535 | 1598                 goto copy; | 
| Chris@535 | 1599             } | 
| Chris@535 | 1600 | 
| Chris@812 | 1601             psy0i = sy0i; | 
| Chris@812 | 1602             psy1i = sy1i; | 
| Chris@812 | 1603 | 
| Chris@535 | 1604             for (int x = 0; x < w; ++x) { | 
| Chris@535 | 1605                 peaks[x] = 0; | 
| Chris@535 | 1606             } | 
| Chris@466 | 1607 | 
| Chris@535 | 1608             for (int sy = sy0i; sy <= sy1i; ++sy) { | 
| Chris@535 | 1609 | 
| Chris@535 | 1610                 if (sy < 0 || sy >= source->height()) continue; | 
| Chris@535 | 1611 | 
| Chris@535 | 1612                 uchar *sourceLine = source->scanLine(sy); | 
| Chris@535 | 1613 | 
| Chris@535 | 1614                 for (int x = 0; x < w; ++x) { | 
| Chris@535 | 1615 | 
| Chris@537 | 1616                     float sx1 = sxa[x*2 + 1]; | 
| Chris@537 | 1617                     if (sx1 < 0) continue; | 
| Chris@537 | 1618                     int sx1i = int(sx1); | 
| Chris@535 | 1619 | 
| Chris@537 | 1620                     float sx0 = sxa[x*2]; | 
| Chris@537 | 1621                     if (sx0 < 0) continue; | 
| Chris@537 | 1622                     int sx0i = int(sx0 + epsilon); | 
| Chris@535 | 1623                     if (sx0i >= sw) break; | 
| Chris@535 | 1624 | 
| Chris@535 | 1625                     uchar peak = 0; | 
| Chris@535 | 1626                     for (int sx = sx0i; sx <= sx1i; ++sx) { | 
| Chris@535 | 1627                         if (sx < 0 || sx >= sw) continue; | 
| Chris@535 | 1628                         if (sourceLine[sx] > peak) peak = sourceLine[sx]; | 
| Chris@535 | 1629                     } | 
| Chris@535 | 1630                     peaks[x] = peak; | 
| Chris@535 | 1631                 } | 
| Chris@535 | 1632             } | 
| Chris@535 | 1633 | 
| Chris@535 | 1634         copy: | 
| Chris@535 | 1635             for (int x = 0; x < w; ++x) { | 
| Chris@535 | 1636                 targetLine[x] = peaks[x]; | 
| Chris@535 | 1637             } | 
| Chris@98 | 1638         } | 
| Chris@0 | 1639     } | 
| Chris@0 | 1640 | 
| Chris@469 | 1641     delete[] peaks; | 
| Chris@469 | 1642 | 
| Chris@98 | 1643     paint.drawImage(x0, 0, img); | 
| Chris@0 | 1644 } | 
| Chris@0 | 1645 | 
| Chris@28 | 1646 bool | 
| Chris@44 | 1647 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame, | 
| Chris@805 | 1648 				      int &resolution, | 
| Chris@28 | 1649 				      SnapType snap) const | 
| Chris@24 | 1650 { | 
| Chris@24 | 1651     if (!m_model) { | 
| Chris@44 | 1652 	return Layer::snapToFeatureFrame(v, frame, resolution, snap); | 
| Chris@24 | 1653     } | 
| Chris@24 | 1654 | 
| Chris@130 | 1655     resolution = m_model->getResolution(); | 
| Chris@28 | 1656     int left = (frame / resolution) * resolution; | 
| Chris@28 | 1657     int right = left + resolution; | 
| Chris@28 | 1658 | 
| Chris@28 | 1659     switch (snap) { | 
| Chris@28 | 1660     case SnapLeft:  frame = left;  break; | 
| Chris@28 | 1661     case SnapRight: frame = right; break; | 
| Chris@28 | 1662     case SnapNearest: | 
| Chris@28 | 1663     case SnapNeighbouring: | 
| Chris@28 | 1664 	if (frame - left > right - frame) frame = right; | 
| Chris@28 | 1665 	else frame = left; | 
| Chris@28 | 1666 	break; | 
| Chris@28 | 1667     } | 
| Chris@24 | 1668 | 
| Chris@28 | 1669     return true; | 
| Chris@24 | 1670 } | 
| Chris@24 | 1671 | 
| Chris@316 | 1672 void | 
| Chris@316 | 1673 Colour3DPlotLayer::toXml(QTextStream &stream, | 
| Chris@316 | 1674                          QString indent, QString extraAttributes) const | 
| Chris@197 | 1675 { | 
| Chris@316 | 1676     QString s = QString("scale=\"%1\" " | 
| Chris@316 | 1677                         "colourScheme=\"%2\" " | 
| Chris@316 | 1678                         "normalizeColumns=\"%3\" " | 
| Chris@445 | 1679                         "normalizeVisibleArea=\"%4\" " | 
| Chris@445 | 1680                         "minY=\"%5\" " | 
| Chris@465 | 1681                         "maxY=\"%6\" " | 
| Chris@465 | 1682                         "invertVertical=\"%7\" " | 
| Chris@535 | 1683                         "opaque=\"%8\" %9") | 
| Chris@197 | 1684 	.arg((int)m_colourScale) | 
| Chris@197 | 1685         .arg(m_colourMap) | 
| Chris@197 | 1686         .arg(m_normalizeColumns ? "true" : "false") | 
| Chris@445 | 1687         .arg(m_normalizeVisibleArea ? "true" : "false") | 
| Chris@445 | 1688         .arg(m_miny) | 
| Chris@465 | 1689         .arg(m_maxy) | 
| Chris@465 | 1690         .arg(m_invertVertical ? "true" : "false") | 
| Chris@534 | 1691         .arg(m_opaque ? "true" : "false") | 
| Chris@536 | 1692         .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ") | 
| Chris@535 | 1693              .arg((int)m_binScale) | 
| Chris@536 | 1694              .arg(m_smooth ? "true" : "false") | 
| Chris@536 | 1695              .arg(m_gain)); | 
| Chris@535 | 1696 | 
| Chris@316 | 1697     Layer::toXml(stream, indent, extraAttributes + " " + s); | 
| Chris@197 | 1698 } | 
| Chris@197 | 1699 | 
| Chris@197 | 1700 void | 
| Chris@197 | 1701 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes) | 
| Chris@197 | 1702 { | 
| Chris@445 | 1703     bool ok = false, alsoOk = false; | 
| Chris@197 | 1704 | 
| Chris@197 | 1705     ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok); | 
| Chris@197 | 1706     if (ok) setColourScale(scale); | 
| Chris@197 | 1707 | 
| Chris@197 | 1708     int colourMap = attributes.value("colourScheme").toInt(&ok); | 
| Chris@197 | 1709     if (ok) setColourMap(colourMap); | 
| Chris@197 | 1710 | 
| Chris@534 | 1711     BinScale binscale = (BinScale)attributes.value("binScale").toInt(&ok); | 
| Chris@534 | 1712     if (ok) setBinScale(binscale); | 
| Chris@534 | 1713 | 
| Chris@197 | 1714     bool normalizeColumns = | 
| Chris@197 | 1715         (attributes.value("normalizeColumns").trimmed() == "true"); | 
| Chris@197 | 1716     setNormalizeColumns(normalizeColumns); | 
| Chris@197 | 1717 | 
| Chris@197 | 1718     bool normalizeVisibleArea = | 
| Chris@197 | 1719         (attributes.value("normalizeVisibleArea").trimmed() == "true"); | 
| Chris@197 | 1720     setNormalizeVisibleArea(normalizeVisibleArea); | 
| Chris@445 | 1721 | 
| Chris@465 | 1722     bool invertVertical = | 
| Chris@465 | 1723         (attributes.value("invertVertical").trimmed() == "true"); | 
| Chris@465 | 1724     setInvertVertical(invertVertical); | 
| Chris@465 | 1725 | 
| Chris@465 | 1726     bool opaque = | 
| Chris@465 | 1727         (attributes.value("opaque").trimmed() == "true"); | 
| Chris@535 | 1728     setOpaque(opaque); | 
| Chris@535 | 1729 | 
| Chris@535 | 1730     bool smooth = | 
| Chris@535 | 1731         (attributes.value("smooth").trimmed() == "true"); | 
| Chris@535 | 1732     setSmooth(smooth); | 
| Chris@465 | 1733 | 
| Chris@536 | 1734     float gain = attributes.value("gain").toFloat(&ok); | 
| Chris@536 | 1735     if (ok) setGain(gain); | 
| Chris@536 | 1736 | 
| Chris@445 | 1737     float min = attributes.value("minY").toFloat(&ok); | 
| Chris@445 | 1738     float max = attributes.value("maxY").toFloat(&alsoOk); | 
| Chris@445 | 1739     if (ok && alsoOk) setDisplayExtents(min, max); | 
| Chris@197 | 1740 } | 
| Chris@197 | 1741 |