| 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@353 | 33 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1 | 
| Chris@125 | 34 | 
| Chris@0 | 35 | 
| Chris@44 | 36 Colour3DPlotLayer::Colour3DPlotLayer() : | 
| Chris@0 | 37     m_model(0), | 
| Chris@159 | 38     m_cache(0), | 
| Chris@469 | 39     m_peaksCache(0), | 
| Chris@469 | 40     m_peakResolution(128), | 
| Chris@461 | 41     m_cacheValidStart(0), | 
| Chris@461 | 42     m_cacheValidEnd(0), | 
| Chris@197 | 43     m_colourScale(LinearScale), | 
| Chris@461 | 44     m_colourScaleSet(false), | 
| Chris@197 | 45     m_colourMap(0), | 
| Chris@197 | 46     m_normalizeColumns(false), | 
| Chris@357 | 47     m_normalizeVisibleArea(false), | 
| Chris@444 | 48     m_invertVertical(false), | 
| Chris@465 | 49     m_opaque(false), | 
| Chris@444 | 50     m_miny(0), | 
| Chris@444 | 51     m_maxy(0) | 
| Chris@0 | 52 { | 
| Chris@44 | 53 | 
| Chris@0 | 54 } | 
| Chris@0 | 55 | 
| Chris@0 | 56 Colour3DPlotLayer::~Colour3DPlotLayer() | 
| Chris@0 | 57 { | 
| Chris@461 | 58     delete m_cache; | 
| Chris@469 | 59     delete m_peaksCache; | 
| Chris@0 | 60 } | 
| Chris@0 | 61 | 
| Chris@0 | 62 void | 
| Chris@0 | 63 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model) | 
| Chris@0 | 64 { | 
| Chris@193 | 65     if (m_model == model) return; | 
| Chris@193 | 66     const DenseThreeDimensionalModel *oldModel = m_model; | 
| Chris@0 | 67     m_model = model; | 
| Chris@0 | 68     if (!m_model || !m_model->isOK()) return; | 
| Chris@0 | 69 | 
| Chris@320 | 70     connectSignals(m_model); | 
| Chris@0 | 71 | 
| Chris@461 | 72     connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged())); | 
| Chris@0 | 73     connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | 
| Chris@461 | 74 	    this, SLOT(modelChanged(size_t, size_t))); | 
| Chris@0 | 75 | 
| Chris@0 | 76     emit modelReplaced(); | 
| Chris@193 | 77     emit sliceableModelReplaced(oldModel, model); | 
| Chris@0 | 78 } | 
| Chris@0 | 79 | 
| Chris@0 | 80 void | 
| Chris@0 | 81 Colour3DPlotLayer::cacheInvalid() | 
| Chris@0 | 82 { | 
| Chris@469 | 83     delete m_cache; | 
| Chris@469 | 84     delete m_peaksCache; | 
| Chris@0 | 85     m_cache = 0; | 
| Chris@469 | 86     m_peaksCache = 0; | 
| Chris@461 | 87     m_cacheValidStart = 0; | 
| Chris@461 | 88     m_cacheValidEnd = 0; | 
| Chris@0 | 89 } | 
| Chris@0 | 90 | 
| Chris@0 | 91 void | 
| Chris@461 | 92 Colour3DPlotLayer::cacheInvalid(size_t startFrame, size_t endFrame) | 
| Chris@0 | 93 { | 
| Chris@461 | 94     if (!m_cache) return; | 
| Chris@461 | 95 | 
| Chris@461 | 96     size_t modelResolution = m_model->getResolution(); | 
| Chris@461 | 97     size_t start = startFrame / modelResolution; | 
| Chris@461 | 98     size_t end = endFrame / modelResolution + 1; | 
| Chris@461 | 99     if (m_cacheValidStart < end) m_cacheValidStart = end; | 
| Chris@461 | 100     if (m_cacheValidEnd > start) m_cacheValidEnd = start; | 
| Chris@461 | 101     if (m_cacheValidStart > m_cacheValidEnd) m_cacheValidEnd = m_cacheValidStart; | 
| Chris@461 | 102 } | 
| Chris@461 | 103 | 
| Chris@461 | 104 void | 
| Chris@461 | 105 Colour3DPlotLayer::modelChanged() | 
| Chris@461 | 106 { | 
| Chris@461 | 107     if (!m_colourScaleSet && m_colourScale == LinearScale) { | 
| Chris@461 | 108         if (m_model) { | 
| Chris@461 | 109             if (m_model->shouldUseLogValueScale()) { | 
| Chris@461 | 110                 setColourScale(LogScale); | 
| Chris@461 | 111             } else { | 
| Chris@461 | 112                 m_colourScaleSet = true; | 
| Chris@461 | 113             } | 
| Chris@461 | 114         } | 
| Chris@461 | 115     } | 
| Chris@0 | 116     cacheInvalid(); | 
| Chris@0 | 117 } | 
| Chris@0 | 118 | 
| Chris@461 | 119 void | 
| Chris@461 | 120 Colour3DPlotLayer::modelChanged(size_t startFrame, size_t endFrame) | 
| Chris@461 | 121 { | 
| Chris@461 | 122     if (!m_colourScaleSet && m_colourScale == LinearScale) { | 
| Chris@461 | 123         if (m_model && m_model->getWidth() > 50) { | 
| Chris@461 | 124             if (m_model->shouldUseLogValueScale()) { | 
| Chris@461 | 125                 setColourScale(LogScale); | 
| Chris@461 | 126             } else { | 
| Chris@461 | 127                 m_colourScaleSet = true; | 
| Chris@461 | 128             } | 
| Chris@461 | 129         } | 
| Chris@461 | 130     } | 
| Chris@461 | 131     cacheInvalid(startFrame, endFrame); | 
| Chris@461 | 132 } | 
| Chris@461 | 133 | 
| Chris@159 | 134 Layer::PropertyList | 
| Chris@159 | 135 Colour3DPlotLayer::getProperties() const | 
| Chris@159 | 136 { | 
| Chris@159 | 137     PropertyList list; | 
| Chris@197 | 138     list.push_back("Colour"); | 
| Chris@159 | 139     list.push_back("Colour Scale"); | 
| Chris@197 | 140     list.push_back("Normalize Columns"); | 
| Chris@197 | 141     list.push_back("Normalize Visible Area"); | 
| Chris@357 | 142     list.push_back("Invert Vertical Scale"); | 
| Chris@465 | 143     list.push_back("Opaque"); | 
| Chris@159 | 144     return list; | 
| Chris@159 | 145 } | 
| Chris@159 | 146 | 
| Chris@159 | 147 QString | 
| Chris@159 | 148 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const | 
| Chris@159 | 149 { | 
| Chris@197 | 150     if (name == "Colour") return tr("Colour"); | 
| Chris@197 | 151     if (name == "Colour Scale") return tr("Scale"); | 
| Chris@197 | 152     if (name == "Normalize Columns") return tr("Normalize Columns"); | 
| Chris@197 | 153     if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); | 
| Chris@357 | 154     if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); | 
| Chris@465 | 155     if (name == "Opaque") return tr("Always Opaque"); | 
| Chris@159 | 156     return ""; | 
| Chris@159 | 157 } | 
| Chris@159 | 158 | 
| Chris@346 | 159 QString | 
| Chris@346 | 160 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const | 
| Chris@346 | 161 { | 
| Chris@346 | 162     if (name == "Normalize Columns") return "normalise-columns"; | 
| Chris@346 | 163     if (name == "Normalize Visible Area") return "normalise"; | 
| Chris@357 | 164     if (name == "Invert Vertical Scale") return "invert-vertical"; | 
| Chris@465 | 165     if (name == "Opaque") return "opaque"; | 
| Chris@346 | 166     return ""; | 
| Chris@346 | 167 } | 
| Chris@346 | 168 | 
| Chris@159 | 169 Layer::PropertyType | 
| Chris@159 | 170 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const | 
| Chris@159 | 171 { | 
| Chris@197 | 172     if (name == "Normalize Columns") return ToggleProperty; | 
| Chris@197 | 173     if (name == "Normalize Visible Area") return ToggleProperty; | 
| Chris@357 | 174     if (name == "Invert Vertical Scale") return ToggleProperty; | 
| Chris@465 | 175     if (name == "Opaque") return ToggleProperty; | 
| Chris@159 | 176     return ValueProperty; | 
| Chris@159 | 177 } | 
| Chris@159 | 178 | 
| Chris@159 | 179 QString | 
| Chris@159 | 180 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const | 
| Chris@159 | 181 { | 
| Chris@197 | 182     if (name == "Normalize Columns" || | 
| Chris@197 | 183         name == "Normalize Visible Area" || | 
| Chris@357 | 184         name == "Invert Vertical Scale" || | 
| Chris@197 | 185 	name == "Colour Scale") return tr("Scale"); | 
| Chris@465 | 186     if (name == "Opaque" || | 
| Chris@465 | 187         name == "Colour") return tr("Colour"); | 
| Chris@159 | 188     return QString(); | 
| Chris@159 | 189 } | 
| Chris@159 | 190 | 
| Chris@159 | 191 int | 
| Chris@159 | 192 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name, | 
| Chris@216 | 193                                             int *min, int *max, int *deflt) const | 
| Chris@159 | 194 { | 
| Chris@216 | 195     int val = 0; | 
| Chris@159 | 196 | 
| Chris@216 | 197     int garbage0, garbage1, garbage2; | 
| Chris@159 | 198     if (!min) min = &garbage0; | 
| Chris@159 | 199     if (!max) max = &garbage1; | 
| Chris@216 | 200     if (!deflt) deflt = &garbage2; | 
| Chris@159 | 201 | 
| Chris@159 | 202     if (name == "Colour Scale") { | 
| Chris@159 | 203 | 
| Chris@159 | 204 	*min = 0; | 
| Chris@197 | 205 	*max = 2; | 
| Chris@216 | 206         *deflt = (int)LinearScale; | 
| Chris@159 | 207 | 
| Chris@216 | 208 	val = (int)m_colourScale; | 
| Chris@159 | 209 | 
| Chris@197 | 210     } else if (name == "Colour") { | 
| Chris@197 | 211 | 
| Chris@197 | 212 	*min = 0; | 
| Chris@197 | 213 	*max = ColourMapper::getColourMapCount() - 1; | 
| Chris@216 | 214         *deflt = 0; | 
| Chris@197 | 215 | 
| Chris@216 | 216 	val = m_colourMap; | 
| Chris@197 | 217 | 
| Chris@197 | 218     } else if (name == "Normalize Columns") { | 
| Chris@197 | 219 | 
| Chris@216 | 220         *deflt = 0; | 
| Chris@216 | 221 	val = (m_normalizeColumns ? 1 : 0); | 
| Chris@197 | 222 | 
| Chris@197 | 223     } else if (name == "Normalize Visible Area") { | 
| Chris@197 | 224 | 
| Chris@216 | 225         *deflt = 0; | 
| Chris@216 | 226 	val = (m_normalizeVisibleArea ? 1 : 0); | 
| Chris@197 | 227 | 
| Chris@357 | 228     } else if (name == "Invert Vertical Scale") { | 
| Chris@357 | 229 | 
| Chris@357 | 230         *deflt = 0; | 
| Chris@357 | 231 	val = (m_invertVertical ? 1 : 0); | 
| Chris@357 | 232 | 
| Chris@465 | 233     } else if (name == "Opaque") { | 
| Chris@465 | 234 | 
| Chris@465 | 235         *deflt = 0; | 
| Chris@465 | 236 	val = (m_opaque ? 1 : 0); | 
| Chris@465 | 237 | 
| Chris@159 | 238     } else { | 
| Chris@216 | 239 	val = Layer::getPropertyRangeAndValue(name, min, max, deflt); | 
| Chris@159 | 240     } | 
| Chris@159 | 241 | 
| Chris@216 | 242     return val; | 
| Chris@159 | 243 } | 
| Chris@159 | 244 | 
| Chris@159 | 245 QString | 
| Chris@159 | 246 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name, | 
| Chris@159 | 247 				    int value) const | 
| Chris@159 | 248 { | 
| Chris@197 | 249     if (name == "Colour") { | 
| Chris@197 | 250         return ColourMapper::getColourMapName(value); | 
| Chris@197 | 251     } | 
| Chris@159 | 252     if (name == "Colour Scale") { | 
| Chris@159 | 253 	switch (value) { | 
| Chris@159 | 254 	default: | 
| Chris@198 | 255 	case 0: return tr("Linear"); | 
| Chris@198 | 256 	case 1: return tr("Log"); | 
| Chris@198 | 257 	case 2: return tr("+/-1"); | 
| Chris@159 | 258 	} | 
| Chris@159 | 259     } | 
| Chris@159 | 260     return tr("<unknown>"); | 
| Chris@159 | 261 } | 
| Chris@159 | 262 | 
| Chris@159 | 263 void | 
| Chris@159 | 264 Colour3DPlotLayer::setProperty(const PropertyName &name, int value) | 
| Chris@159 | 265 { | 
| Chris@159 | 266     if (name == "Colour Scale") { | 
| Chris@159 | 267 	switch (value) { | 
| Chris@159 | 268 	default: | 
| Chris@159 | 269 	case 0: setColourScale(LinearScale); break; | 
| Chris@197 | 270 	case 1: setColourScale(LogScale); break; | 
| Chris@197 | 271 	case 2: setColourScale(PlusMinusOneScale); break; | 
| Chris@159 | 272 	} | 
| Chris@197 | 273     } else if (name == "Colour") { | 
| Chris@197 | 274         setColourMap(value); | 
| Chris@197 | 275     } else if (name == "Normalize Columns") { | 
| Chris@197 | 276 	setNormalizeColumns(value ? true : false); | 
| Chris@197 | 277     } else if (name == "Normalize Visible Area") { | 
| Chris@197 | 278 	setNormalizeVisibleArea(value ? true : false); | 
| Chris@357 | 279     } else if (name == "Invert Vertical Scale") { | 
| Chris@357 | 280 	setInvertVertical(value ? true : false); | 
| Chris@465 | 281     } else if (name == "Opaque") { | 
| Chris@465 | 282 	setOpaque(value ? true : false); | 
| Chris@159 | 283     } | 
| Chris@159 | 284 } | 
| Chris@159 | 285 | 
| Chris@159 | 286 void | 
| Chris@159 | 287 Colour3DPlotLayer::setColourScale(ColourScale scale) | 
| Chris@159 | 288 { | 
| Chris@159 | 289     if (m_colourScale == scale) return; | 
| Chris@159 | 290     m_colourScale = scale; | 
| Chris@461 | 291     m_colourScaleSet = true; | 
| Chris@159 | 292     cacheInvalid(); | 
| Chris@159 | 293     emit layerParametersChanged(); | 
| Chris@159 | 294 } | 
| Chris@159 | 295 | 
| Chris@197 | 296 void | 
| Chris@197 | 297 Colour3DPlotLayer::setColourMap(int map) | 
| Chris@197 | 298 { | 
| Chris@197 | 299     if (m_colourMap == map) return; | 
| Chris@197 | 300     m_colourMap = map; | 
| Chris@197 | 301     cacheInvalid(); | 
| Chris@197 | 302     emit layerParametersChanged(); | 
| Chris@197 | 303 } | 
| Chris@197 | 304 | 
| Chris@197 | 305 void | 
| Chris@197 | 306 Colour3DPlotLayer::setNormalizeColumns(bool n) | 
| Chris@197 | 307 { | 
| Chris@197 | 308     if (m_normalizeColumns == n) return; | 
| Chris@197 | 309     m_normalizeColumns = n; | 
| Chris@197 | 310     cacheInvalid(); | 
| Chris@197 | 311     emit layerParametersChanged(); | 
| Chris@197 | 312 } | 
| Chris@197 | 313 | 
| Chris@197 | 314 bool | 
| Chris@197 | 315 Colour3DPlotLayer::getNormalizeColumns() const | 
| Chris@197 | 316 { | 
| Chris@197 | 317     return m_normalizeColumns; | 
| Chris@197 | 318 } | 
| Chris@197 | 319 | 
| Chris@197 | 320 void | 
| Chris@197 | 321 Colour3DPlotLayer::setNormalizeVisibleArea(bool n) | 
| Chris@197 | 322 { | 
| Chris@197 | 323     if (m_normalizeVisibleArea == n) return; | 
| Chris@197 | 324     m_normalizeVisibleArea = n; | 
| Chris@197 | 325     cacheInvalid(); | 
| Chris@197 | 326     emit layerParametersChanged(); | 
| Chris@197 | 327 } | 
| Chris@197 | 328 | 
| Chris@197 | 329 bool | 
| Chris@197 | 330 Colour3DPlotLayer::getNormalizeVisibleArea() const | 
| Chris@197 | 331 { | 
| Chris@197 | 332     return m_normalizeVisibleArea; | 
| Chris@197 | 333 } | 
| Chris@197 | 334 | 
| Chris@357 | 335 void | 
| Chris@357 | 336 Colour3DPlotLayer::setInvertVertical(bool n) | 
| Chris@357 | 337 { | 
| Chris@357 | 338     if (m_invertVertical == n) return; | 
| Chris@357 | 339     m_invertVertical = n; | 
| Chris@357 | 340     cacheInvalid(); | 
| Chris@357 | 341     emit layerParametersChanged(); | 
| Chris@357 | 342 } | 
| Chris@357 | 343 | 
| Chris@465 | 344 void | 
| Chris@465 | 345 Colour3DPlotLayer::setOpaque(bool n) | 
| Chris@465 | 346 { | 
| Chris@465 | 347     if (m_opaque == n) return; | 
| Chris@465 | 348     m_opaque = n; | 
| Chris@465 | 349     emit layerParametersChanged(); | 
| Chris@465 | 350 } | 
| Chris@465 | 351 | 
| Chris@357 | 352 bool | 
| Chris@357 | 353 Colour3DPlotLayer::getInvertVertical() const | 
| Chris@357 | 354 { | 
| Chris@357 | 355     return m_invertVertical; | 
| Chris@357 | 356 } | 
| Chris@357 | 357 | 
| Chris@25 | 358 bool | 
| Chris@465 | 359 Colour3DPlotLayer::getOpaque() const | 
| Chris@465 | 360 { | 
| Chris@465 | 361     return m_opaque; | 
| Chris@465 | 362 } | 
| Chris@465 | 363 | 
| Chris@465 | 364 bool | 
| Chris@44 | 365 Colour3DPlotLayer::isLayerScrollable(const View *v) const | 
| Chris@25 | 366 { | 
| Chris@197 | 367     if (m_normalizeVisibleArea) return false; | 
| Chris@25 | 368     QPoint discard; | 
| Chris@44 | 369     return !v->shouldIlluminateLocalFeatures(this, discard); | 
| Chris@25 | 370 } | 
| Chris@25 | 371 | 
| Chris@444 | 372 bool | 
| Chris@444 | 373 Colour3DPlotLayer::getValueExtents(float &min, float &max, | 
| Chris@444 | 374                                    bool &logarithmic, QString &unit) const | 
| Chris@444 | 375 { | 
| Chris@444 | 376     if (!m_model) return false; | 
| Chris@444 | 377 | 
| Chris@444 | 378     min = 0; | 
| Chris@444 | 379     max = m_model->getHeight(); | 
| Chris@444 | 380 | 
| Chris@444 | 381     logarithmic = false; | 
| Chris@444 | 382     unit = ""; | 
| Chris@444 | 383 | 
| Chris@444 | 384     return true; | 
| Chris@444 | 385 } | 
| Chris@444 | 386 | 
| Chris@444 | 387 bool | 
| Chris@444 | 388 Colour3DPlotLayer::getDisplayExtents(float &min, float &max) const | 
| Chris@444 | 389 { | 
| Chris@444 | 390     if (!m_model) return false; | 
| Chris@444 | 391 | 
| Chris@444 | 392     min = m_miny; | 
| Chris@444 | 393     max = m_maxy; | 
| Chris@444 | 394     if (max <= min) { | 
| Chris@444 | 395         min = 0; | 
| Chris@444 | 396         max = m_model->getHeight(); | 
| Chris@444 | 397     } | 
| Chris@444 | 398     if (min < 0) min = 0; | 
| Chris@444 | 399     if (max > m_model->getHeight()) max = m_model->getHeight(); | 
| Chris@444 | 400 | 
| Chris@444 | 401     return true; | 
| Chris@444 | 402 } | 
| Chris@444 | 403 | 
| Chris@444 | 404 bool | 
| Chris@444 | 405 Colour3DPlotLayer::setDisplayExtents(float min, float max) | 
| Chris@444 | 406 { | 
| Chris@444 | 407     if (!m_model) return false; | 
| Chris@444 | 408 | 
| Chris@444 | 409     m_miny = lrintf(min); | 
| Chris@444 | 410     m_maxy = lrintf(max); | 
| Chris@444 | 411 | 
| Chris@444 | 412     emit layerParametersChanged(); | 
| Chris@444 | 413     return true; | 
| Chris@444 | 414 } | 
| Chris@444 | 415 | 
| Chris@444 | 416 int | 
| Chris@444 | 417 Colour3DPlotLayer::getVerticalZoomSteps(int &defaultStep) const | 
| Chris@444 | 418 { | 
| Chris@444 | 419     if (!m_model) return 0; | 
| Chris@444 | 420 | 
| Chris@444 | 421     defaultStep = 0; | 
| Chris@444 | 422     int h = m_model->getHeight(); | 
| Chris@444 | 423     return h; | 
| Chris@444 | 424 } | 
| Chris@444 | 425 | 
| Chris@444 | 426 int | 
| Chris@444 | 427 Colour3DPlotLayer::getCurrentVerticalZoomStep() const | 
| Chris@444 | 428 { | 
| Chris@444 | 429     if (!m_model) return 0; | 
| Chris@444 | 430 | 
| Chris@444 | 431     float min, max; | 
| Chris@444 | 432     getDisplayExtents(min, max); | 
| Chris@444 | 433     return m_model->getHeight() - lrintf(max - min); | 
| Chris@444 | 434 } | 
| Chris@444 | 435 | 
| Chris@444 | 436 void | 
| Chris@444 | 437 Colour3DPlotLayer::setVerticalZoomStep(int step) | 
| Chris@444 | 438 { | 
| Chris@444 | 439     if (!m_model) return; | 
| Chris@444 | 440 | 
| Chris@445 | 441 //    std::cerr << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): before: miny = " << m_miny << ", maxy = " << m_maxy << std::endl; | 
| Chris@444 | 442 | 
| Chris@444 | 443     int dist = m_model->getHeight() - step; | 
| Chris@444 | 444     if (dist < 1) dist = 1; | 
| Chris@444 | 445     float centre = m_miny + (float(m_maxy) - float(m_miny)) / 2.f; | 
| Chris@444 | 446     m_miny = lrintf(centre - float(dist)/2); | 
| Chris@444 | 447     if (m_miny < 0) m_miny = 0; | 
| Chris@444 | 448     m_maxy = m_miny + dist; | 
| Chris@444 | 449     if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight(); | 
| Chris@444 | 450 | 
| Chris@445 | 451 //    std::cerr << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"):  after: miny = " << m_miny << ", maxy = " << m_maxy << std::endl; | 
| Chris@444 | 452 | 
| Chris@444 | 453     emit layerParametersChanged(); | 
| Chris@444 | 454 } | 
| Chris@444 | 455 | 
| Chris@444 | 456 RangeMapper * | 
| Chris@444 | 457 Colour3DPlotLayer::getNewVerticalZoomRangeMapper() const | 
| Chris@444 | 458 { | 
| Chris@444 | 459     if (!m_model) return 0; | 
| Chris@444 | 460 | 
| Chris@444 | 461     return new LinearRangeMapper(0, m_model->getHeight(), | 
| Chris@444 | 462                                  0, m_model->getHeight(), ""); | 
| Chris@444 | 463 } | 
| Chris@444 | 464 | 
| Chris@25 | 465 QString | 
| Chris@44 | 466 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const | 
| Chris@25 | 467 { | 
| Chris@25 | 468     if (!m_model) return ""; | 
| Chris@25 | 469 | 
| Chris@25 | 470     int x = pos.x(); | 
| Chris@25 | 471     int y = pos.y(); | 
| Chris@25 | 472 | 
| Chris@25 | 473     size_t modelStart = m_model->getStartFrame(); | 
| Chris@130 | 474     size_t modelResolution = m_model->getResolution(); | 
| Chris@25 | 475 | 
| Chris@159 | 476     float srRatio = | 
| Chris@159 | 477         float(v->getViewManager()->getMainModelSampleRate()) / | 
| Chris@159 | 478         float(m_model->getSampleRate()); | 
| Chris@159 | 479 | 
| Chris@160 | 480     int sx0 = int((v->getFrameForX(x) / srRatio - long(modelStart)) / | 
| Chris@160 | 481                   long(modelResolution)); | 
| Chris@25 | 482 | 
| Chris@160 | 483     int f0 = sx0 * modelResolution; | 
| Chris@160 | 484     int f1 =  f0 + modelResolution; | 
| Chris@160 | 485 | 
| Chris@447 | 486     int sh = m_model->getHeight(); | 
| Chris@447 | 487 | 
| Chris@447 | 488     int symin = m_miny; | 
| Chris@447 | 489     int symax = m_maxy; | 
| Chris@447 | 490     if (symax <= symin) { | 
| Chris@447 | 491         symin = 0; | 
| Chris@447 | 492         symax = sh; | 
| Chris@447 | 493     } | 
| Chris@447 | 494     if (symin < 0) symin = 0; | 
| Chris@447 | 495     if (symax > sh) symax = sh; | 
| Chris@447 | 496 | 
| Chris@447 | 497     float binHeight = float(v->height()) / (symax - symin); | 
| Chris@447 | 498     int sy = int((v->height() - y) / binHeight) + symin; | 
| Chris@25 | 499 | 
| Chris@357 | 500     if (m_invertVertical) sy = m_model->getHeight() - sy - 1; | 
| Chris@357 | 501 | 
| Chris@160 | 502     float value = m_model->getValueAt(sx0, sy); | 
| Chris@159 | 503 | 
| Chris@159 | 504 //    std::cerr << "bin value (" << sx0 << "," << sy << ") is " << value << std::endl; | 
| Chris@25 | 505 | 
| Chris@25 | 506     QString binName = m_model->getBinName(sy); | 
| Chris@25 | 507     if (binName == "") binName = QString("[%1]").arg(sy + 1); | 
| Chris@25 | 508     else binName = QString("%1 [%2]").arg(binName).arg(sy + 1); | 
| Chris@25 | 509 | 
| Chris@25 | 510     QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4") | 
| Chris@160 | 511 	.arg(RealTime::frame2RealTime(f0, m_model->getSampleRate()) | 
| Chris@25 | 512 	     .toText(true).c_str()) | 
| Chris@160 | 513 	.arg(RealTime::frame2RealTime(f1, m_model->getSampleRate()) | 
| Chris@25 | 514 	     .toText(true).c_str()) | 
| Chris@25 | 515 	.arg(binName) | 
| Chris@25 | 516 	.arg(value); | 
| Chris@25 | 517 | 
| Chris@25 | 518     return text; | 
| Chris@25 | 519 } | 
| Chris@25 | 520 | 
| Chris@25 | 521 int | 
| Chris@248 | 522 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const | 
| Chris@159 | 523 { | 
| Chris@159 | 524     int cw = 20; | 
| Chris@159 | 525     return cw; | 
| Chris@159 | 526 } | 
| Chris@159 | 527 | 
| Chris@159 | 528 int | 
| Chris@248 | 529 Colour3DPlotLayer::getVerticalScaleWidth(View *, QPainter &paint) const | 
| Chris@25 | 530 { | 
| Chris@25 | 531     if (!m_model) return 0; | 
| Chris@25 | 532 | 
| Chris@160 | 533     QString sampleText = QString("[%1]").arg(m_model->getHeight()); | 
| Chris@25 | 534     int tw = paint.fontMetrics().width(sampleText); | 
| Chris@98 | 535     bool another = false; | 
| Chris@25 | 536 | 
| Chris@160 | 537     for (size_t i = 0; i < m_model->getHeight(); ++i) { | 
| Chris@25 | 538 	if (m_model->getBinName(i).length() > sampleText.length()) { | 
| Chris@25 | 539 	    sampleText = m_model->getBinName(i); | 
| Chris@98 | 540             another = true; | 
| Chris@25 | 541 	} | 
| Chris@25 | 542     } | 
| Chris@98 | 543     if (another) { | 
| Chris@25 | 544 	tw = std::max(tw, paint.fontMetrics().width(sampleText)); | 
| Chris@25 | 545     } | 
| Chris@25 | 546 | 
| Chris@159 | 547     return tw + 13 + getColourScaleWidth(paint); | 
| Chris@25 | 548 } | 
| Chris@25 | 549 | 
| Chris@25 | 550 void | 
| Chris@44 | 551 Colour3DPlotLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const | 
| Chris@25 | 552 { | 
| Chris@25 | 553     if (!m_model) return; | 
| Chris@25 | 554 | 
| Chris@25 | 555     int h = rect.height(), w = rect.width(); | 
| Chris@25 | 556 | 
| Chris@159 | 557     int cw = getColourScaleWidth(paint); | 
| Chris@159 | 558 | 
| Chris@159 | 559     int ch = h - 20; | 
| Chris@159 | 560     if (ch > 20 && m_cache) { | 
| Chris@159 | 561 | 
| Chris@447 | 562         float min = m_model->getMinimumLevel(); | 
| Chris@447 | 563         float max = m_model->getMaximumLevel(); | 
| Chris@447 | 564 | 
| Chris@447 | 565         float mmin = min; | 
| Chris@447 | 566         float mmax = max; | 
| Chris@447 | 567 | 
| Chris@447 | 568         if (m_colourScale == LogScale) { | 
| Chris@447 | 569             LogRange::mapRange(mmin, mmax); | 
| Chris@447 | 570         } else if (m_colourScale == PlusMinusOneScale) { | 
| Chris@447 | 571             mmin = -1.f; | 
| Chris@447 | 572             mmax = 1.f; | 
| Chris@447 | 573         } | 
| Chris@447 | 574 | 
| Chris@447 | 575         if (max == min) max = min + 1.0; | 
| Chris@465 | 576         if (mmax == mmin) mmax = mmin + 1.0; | 
| Chris@447 | 577 | 
| Chris@287 | 578         paint.setPen(v->getForeground()); | 
| Chris@447 | 579         paint.drawRect(4, 10, cw - 8, ch+1); | 
| Chris@159 | 580 | 
| Chris@446 | 581         for (int y = 0; y < ch; ++y) { | 
| Chris@447 | 582             float value = ((max - min) * (ch - y - 1)) / ch + min; | 
| Chris@447 | 583             if (m_colourScale == LogScale) { | 
| Chris@447 | 584                 value = LogRange::map(value); | 
| Chris@447 | 585             } | 
| Chris@447 | 586             int pixel = int(((value - mmin) * 256) / (mmax - mmin)); | 
| Chris@465 | 587             if (pixel >= 0 && pixel < 256) { | 
| Chris@465 | 588                 QRgb c = m_cache->color(pixel); | 
| Chris@465 | 589                 paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c))); | 
| Chris@465 | 590                 paint.drawLine(5, 11 + y, cw - 5, 11 + y); | 
| Chris@465 | 591             } else { | 
| Chris@465 | 592                 std::cerr << "WARNING: Colour3DPlotLayer::paintVerticalScale: value " << value << ", mmin " << mmin << ", mmax " << mmax << " leads to invalid pixel " << pixel << std::endl; | 
| Chris@465 | 593             } | 
| Chris@159 | 594         } | 
| Chris@446 | 595 | 
| Chris@446 | 596         QString minstr = QString("%1").arg(min); | 
| Chris@446 | 597         QString maxstr = QString("%1").arg(max); | 
| Chris@446 | 598 | 
| Chris@446 | 599         paint.save(); | 
| Chris@446 | 600 | 
| Chris@446 | 601         QFont font = paint.font(); | 
| Chris@446 | 602         font.setPixelSize(10); | 
| Chris@446 | 603         paint.setFont(font); | 
| Chris@446 | 604 | 
| Chris@446 | 605         int msw = paint.fontMetrics().width(maxstr); | 
| Chris@446 | 606 | 
| Chris@446 | 607         QMatrix m; | 
| Chris@446 | 608         m.translate(cw - 6, ch + 10); | 
| Chris@446 | 609         m.rotate(-90); | 
| Chris@446 | 610 | 
| Chris@446 | 611         paint.setWorldMatrix(m); | 
| Chris@446 | 612 | 
| Chris@446 | 613         v->drawVisibleText(paint, 2, 0, minstr, View::OutlinedText); | 
| Chris@446 | 614 | 
| Chris@446 | 615         m.translate(ch - msw - 2, 0); | 
| Chris@446 | 616         paint.setWorldMatrix(m); | 
| Chris@446 | 617 | 
| Chris@446 | 618         v->drawVisibleText(paint, 0, 0, maxstr, View::OutlinedText); | 
| Chris@446 | 619 | 
| Chris@446 | 620         paint.restore(); | 
| Chris@159 | 621     } | 
| Chris@159 | 622 | 
| Chris@287 | 623     paint.setPen(v->getForeground()); | 
| Chris@159 | 624 | 
| Chris@445 | 625     int sh = m_model->getHeight(); | 
| Chris@445 | 626 | 
| Chris@445 | 627     int symin = m_miny; | 
| Chris@445 | 628     int symax = m_maxy; | 
| Chris@445 | 629     if (symax <= symin) { | 
| Chris@445 | 630         symin = 0; | 
| Chris@445 | 631         symax = sh; | 
| Chris@445 | 632     } | 
| Chris@445 | 633     if (symin < 0) symin = 0; | 
| Chris@445 | 634     if (symax > sh) symax = sh; | 
| Chris@445 | 635 | 
| Chris@456 | 636     float binHeight = float(v->height()) / (symax - symin); | 
| Chris@456 | 637 | 
| Chris@456 | 638     paint.save(); | 
| Chris@456 | 639 | 
| Chris@456 | 640     QFont tf = paint.font(); | 
| Chris@456 | 641     if (paint.fontMetrics().height() >= binHeight) { | 
| Chris@457 | 642         tf.setPixelSize(binHeight > 7 ? binHeight - 2 : 5); | 
| Chris@456 | 643         paint.setFont(tf); | 
| Chris@456 | 644     } | 
| Chris@456 | 645 | 
| Chris@98 | 646     int count = v->height() / paint.fontMetrics().height(); | 
| Chris@445 | 647     int step = (symax - symin) / count; | 
| Chris@98 | 648     if (step == 0) step = 1; | 
| Chris@25 | 649 | 
| Chris@445 | 650     for (size_t i = symin; i < symax; ++i) { | 
| Chris@25 | 651 | 
| Chris@357 | 652         size_t idx = i; | 
| Chris@357 | 653         if (m_invertVertical) idx = m_model->getHeight() - idx - 1; | 
| Chris@357 | 654 | 
| Chris@357 | 655         if ((idx % step) != 0) continue; | 
| Chris@98 | 656 | 
| Chris@445 | 657 	int y0 = int(v->height() - ((i - symin) * binHeight) - 1); | 
| Chris@25 | 658 | 
| Chris@357 | 659 	QString text = m_model->getBinName(idx); | 
| Chris@357 | 660 	if (text == "") text = QString("[%1]").arg(idx + 1); | 
| Chris@25 | 661 | 
| Chris@159 | 662 	paint.drawLine(cw, y0, w, y0); | 
| Chris@25 | 663 | 
| Chris@457 | 664         if (step > 1) { | 
| Chris@457 | 665             paint.drawLine(w - 1, y0 - (step * binHeight) + 1, | 
| Chris@457 | 666                            w - 1, y0 - binHeight - 1); | 
| Chris@457 | 667             paint.drawLine(w - 2, y0 - (step * binHeight) + 1, | 
| Chris@457 | 668                            w - 2, y0 - binHeight - 2); | 
| Chris@457 | 669         } | 
| Chris@457 | 670 | 
| Chris@248 | 671 	int cy = int(y0 - (step * binHeight)/2); | 
| Chris@25 | 672 	int ty = cy + paint.fontMetrics().ascent()/2; | 
| Chris@25 | 673 | 
| Chris@159 | 674 	paint.drawText(cw + 5, ty, text); | 
| Chris@25 | 675     } | 
| Chris@456 | 676 | 
| Chris@456 | 677     paint.restore(); | 
| Chris@25 | 678 } | 
| Chris@25 | 679 | 
| Chris@467 | 680 DenseThreeDimensionalModel::Column | 
| Chris@467 | 681 Colour3DPlotLayer::getColumn(size_t col) const | 
| Chris@197 | 682 { | 
| Chris@467 | 683     DenseThreeDimensionalModel::Column values = m_model->getColumn(col); | 
| Chris@468 | 684     while (values.size() < m_model->getHeight()) values.push_back(0.f); | 
| Chris@467 | 685     if (!m_normalizeColumns) return values; | 
| Chris@461 | 686 | 
| Chris@224 | 687     float colMax = 0.f, colMin = 0.f; | 
| Chris@461 | 688     float min = 0.f, max = 0.f; | 
| Chris@197 | 689 | 
| Chris@461 | 690     min = m_model->getMinimumLevel(); | 
| Chris@461 | 691     max = m_model->getMaximumLevel(); | 
| Chris@461 | 692 | 
| Chris@461 | 693     for (size_t y = 0; y < values.size(); ++y) { | 
| Chris@467 | 694         if (y == 0 || values.at(y) > colMax) colMax = values.at(y); | 
| Chris@467 | 695         if (y == 0 || values.at(y) < colMin) colMin = values.at(y); | 
| Chris@197 | 696     } | 
| Chris@461 | 697     if (colMin == colMax) colMax = colMin + 1; | 
| Chris@197 | 698 | 
| Chris@197 | 699     for (size_t y = 0; y < values.size(); ++y) { | 
| Chris@461 | 700 | 
| Chris@467 | 701         float value = values.at(y); | 
| Chris@461 | 702         float norm = (value - colMin) / (colMax - colMin); | 
| Chris@467 | 703         float newvalue = min + (max - min) * norm; | 
| Chris@197 | 704 | 
| Chris@467 | 705         if (value != newvalue) values[y] = newvalue; | 
| Chris@468 | 706     } | 
| Chris@468 | 707 | 
| Chris@468 | 708     return values; | 
| Chris@197 | 709 } | 
| Chris@197 | 710 | 
| Chris@197 | 711 void | 
| Chris@197 | 712 Colour3DPlotLayer::fillCache(size_t firstBin, size_t lastBin) const | 
| Chris@197 | 713 { | 
| Chris@466 | 714     Profiler profiler("Colour3DPlotLayer::fillCache"); | 
| Chris@197 | 715     size_t modelStart = m_model->getStartFrame(); | 
| Chris@197 | 716     size_t modelEnd = m_model->getEndFrame(); | 
| Chris@197 | 717     size_t modelResolution = m_model->getResolution(); | 
| Chris@197 | 718 | 
| Chris@224 | 719 //    std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl; | 
| Chris@197 | 720 | 
| Chris@461 | 721     size_t modelStartBin = modelStart / modelResolution; | 
| Chris@461 | 722     size_t modelEndBin = modelEnd / modelResolution; | 
| Chris@461 | 723 | 
| Chris@461 | 724     size_t cacheWidth = modelEndBin - modelStartBin + 1; | 
| Chris@461 | 725     size_t cacheHeight = m_model->getHeight(); | 
| Chris@461 | 726 | 
| Chris@461 | 727     if (m_cache && (m_cache->height() != int(cacheHeight))) { | 
| Chris@461 | 728         delete m_cache; | 
| Chris@469 | 729         delete m_peaksCache; | 
| Chris@461 | 730         m_cache = 0; | 
| Chris@469 | 731         m_peaksCache = 0; | 
| Chris@461 | 732     } | 
| Chris@461 | 733 | 
| Chris@461 | 734     if (m_cache && (m_cache->width() != int(cacheWidth))) { | 
| Chris@469 | 735         QImage *newCache = | 
| Chris@469 | 736             new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight)); | 
| Chris@461 | 737         delete m_cache; | 
| Chris@461 | 738         m_cache = newCache; | 
| Chris@469 | 739         if (m_peaksCache) { | 
| Chris@469 | 740             QImage *newPeaksCache = | 
| Chris@469 | 741                 new QImage(m_peaksCache->copy | 
| Chris@469 | 742                            (0, 0, cacheWidth / m_peakResolution, cacheHeight)); | 
| Chris@469 | 743             delete m_peaksCache; | 
| Chris@469 | 744             m_peaksCache = newPeaksCache; | 
| Chris@469 | 745         } | 
| Chris@197 | 746     } | 
| Chris@197 | 747 | 
| Chris@461 | 748     if (!m_cache) { | 
| Chris@469 | 749         m_cache = new QImage | 
| Chris@469 | 750             (cacheWidth, cacheHeight, QImage::Format_Indexed8); | 
| Chris@461 | 751         m_cache->setNumColors(256); | 
| Chris@469 | 752         if (modelResolution < m_peakResolution / 2 && !m_normalizeVisibleArea) { | 
| Chris@469 | 753             m_peaksCache = new QImage | 
| Chris@469 | 754                 (cacheWidth / m_peakResolution + 1, cacheHeight, | 
| Chris@469 | 755                  QImage::Format_Indexed8); | 
| Chris@469 | 756             m_peaksCache->setNumColors(256); | 
| Chris@469 | 757         } else if (m_peaksCache) { | 
| Chris@469 | 758             delete m_peaksCache; | 
| Chris@469 | 759             m_peaksCache = 0; | 
| Chris@469 | 760         } | 
| Chris@461 | 761         m_cacheValidStart = 0; | 
| Chris@461 | 762         m_cacheValidEnd = 0; | 
| Chris@197 | 763     } | 
| Chris@197 | 764 | 
| Chris@461 | 765     if (m_cacheValidStart <= firstBin && m_cacheValidEnd >= lastBin) { | 
| Chris@461 | 766         return; | 
| Chris@461 | 767     } | 
| Chris@461 | 768 | 
| Chris@461 | 769     size_t fillStart = firstBin; | 
| Chris@461 | 770     size_t fillEnd = lastBin; | 
| Chris@197 | 771 | 
| Chris@461 | 772     if (fillStart < modelStartBin) fillStart = modelStartBin; | 
| Chris@461 | 773     if (fillStart > modelEndBin) fillStart = modelEndBin; | 
| Chris@461 | 774     if (fillEnd < modelStartBin) fillEnd = modelStartBin; | 
| Chris@461 | 775     if (fillEnd > modelEndBin) fillEnd = modelEndBin; | 
| Chris@197 | 776 | 
| Chris@461 | 777     bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns); | 
| Chris@197 | 778 | 
| Chris@461 | 779     if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) { | 
| Chris@461 | 780 | 
| Chris@461 | 781         if (m_cacheValidEnd < fillStart) { | 
| Chris@461 | 782             fillStart = m_cacheValidEnd + 1; | 
| Chris@461 | 783         } | 
| Chris@461 | 784         if (m_cacheValidStart > fillEnd) { | 
| Chris@461 | 785             fillEnd = m_cacheValidStart - 1; | 
| Chris@461 | 786         } | 
| Chris@461 | 787 | 
| Chris@461 | 788         m_cacheValidStart = std::min(fillStart, m_cacheValidStart); | 
| Chris@461 | 789         m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd); | 
| Chris@461 | 790 | 
| Chris@461 | 791     } else { | 
| Chris@461 | 792 | 
| Chris@461 | 793         // the only valid area, ever, is the currently visible one | 
| Chris@461 | 794 | 
| Chris@461 | 795         m_cacheValidStart = fillStart; | 
| Chris@461 | 796         m_cacheValidEnd = fillEnd; | 
| Chris@461 | 797     } | 
| Chris@461 | 798 | 
| Chris@461 | 799 //    std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << std::endl; | 
| Chris@461 | 800 | 
| Chris@197 | 801     DenseThreeDimensionalModel::Column values; | 
| Chris@197 | 802 | 
| Chris@197 | 803     float min = m_model->getMinimumLevel(); | 
| Chris@197 | 804     float max = m_model->getMaximumLevel(); | 
| Chris@197 | 805 | 
| Chris@197 | 806     if (m_colourScale == LogScale) { | 
| Chris@197 | 807         LogRange::mapRange(min, max); | 
| Chris@197 | 808     } else if (m_colourScale == PlusMinusOneScale) { | 
| Chris@197 | 809         min = -1.f; | 
| Chris@197 | 810         max = 1.f; | 
| Chris@197 | 811     } | 
| Chris@197 | 812 | 
| Chris@197 | 813     if (max == min) max = min + 1.0; | 
| Chris@197 | 814 | 
| Chris@197 | 815     ColourMapper mapper(m_colourMap, 0.f, 255.f); | 
| Chris@197 | 816 | 
| Chris@197 | 817     for (int index = 0; index < 256; ++index) { | 
| Chris@197 | 818         QColor colour = mapper.map(index); | 
| Chris@469 | 819         m_cache->setColor | 
| Chris@469 | 820             (index, qRgb(colour.red(), colour.green(), colour.blue())); | 
| Chris@469 | 821         if (m_peaksCache) { | 
| Chris@469 | 822             m_peaksCache->setColor | 
| Chris@469 | 823                 (index, qRgb(colour.red(), colour.green(), colour.blue())); | 
| Chris@469 | 824         } | 
| Chris@197 | 825     } | 
| Chris@197 | 826 | 
| Chris@461 | 827 //    m_cache->fill(0); | 
| Chris@197 | 828 | 
| Chris@224 | 829     float visibleMax = 0.f, visibleMin = 0.f; | 
| Chris@197 | 830 | 
| Chris@461 | 831     if (normalizeVisible) { | 
| Chris@197 | 832 | 
| Chris@461 | 833         for (size_t c = fillStart; c <= fillEnd; ++c) { | 
| Chris@197 | 834 | 
| Chris@467 | 835             values = getColumn(c); | 
| Chris@197 | 836 | 
| Chris@224 | 837             float colMax = 0.f, colMin = 0.f; | 
| Chris@197 | 838 | 
| Chris@461 | 839             for (size_t y = 0; y < cacheHeight; ++y) { | 
| Chris@197 | 840                 if (y >= values.size()) break; | 
| Chris@197 | 841                 if (y == 0 || values[y] > colMax) colMax = values[y]; | 
| Chris@224 | 842                 if (y == 0 || values[y] < colMin) colMin = values[y]; | 
| Chris@197 | 843             } | 
| Chris@197 | 844 | 
| Chris@461 | 845             if (c == fillStart || colMax > visibleMax) visibleMax = colMax; | 
| Chris@461 | 846             if (c == fillStart || colMin < visibleMin) visibleMin = colMin; | 
| Chris@461 | 847         } | 
| Chris@461 | 848 | 
| Chris@461 | 849         if (m_colourScale == LogScale) { | 
| Chris@461 | 850             visibleMin = LogRange::map(visibleMin); | 
| Chris@461 | 851             visibleMax = LogRange::map(visibleMax); | 
| Chris@461 | 852             if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax); | 
| Chris@197 | 853         } | 
| Chris@197 | 854     } | 
| Chris@197 | 855 | 
| Chris@224 | 856     if (visibleMin == visibleMax) visibleMax = visibleMin + 1; | 
| Chris@224 | 857 | 
| Chris@469 | 858     int *peaks = 0; | 
| Chris@469 | 859     if (m_peaksCache) { | 
| Chris@469 | 860         peaks = new int[cacheHeight]; | 
| Chris@469 | 861         for (int y = 0; y < cacheHeight; ++y) { | 
| Chris@469 | 862             peaks[y] = 0; | 
| Chris@469 | 863         } | 
| Chris@469 | 864     } | 
| Chris@469 | 865 | 
| Chris@461 | 866     for (size_t c = fillStart; c <= fillEnd; ++c) { | 
| Chris@197 | 867 | 
| Chris@467 | 868         values = getColumn(c); | 
| Chris@197 | 869 | 
| Chris@461 | 870         for (size_t y = 0; y < cacheHeight; ++y) { | 
| Chris@197 | 871 | 
| Chris@197 | 872             float value = min; | 
| Chris@197 | 873             if (y < values.size()) { | 
| Chris@469 | 874                 value = values.at(y); | 
| Chris@197 | 875             } | 
| Chris@224 | 876 | 
| Chris@224 | 877             if (m_colourScale == LogScale) { | 
| Chris@224 | 878                 value = LogRange::map(value); | 
| Chris@197 | 879             } | 
| Chris@461 | 880 | 
| Chris@461 | 881             if (normalizeVisible) { | 
| Chris@461 | 882                 float norm = (value - visibleMin) / (visibleMax - visibleMin); | 
| Chris@461 | 883                 value = min + (max - min) * norm; | 
| Chris@461 | 884             } | 
| Chris@197 | 885 | 
| Chris@197 | 886             int pixel = int(((value - min) * 256) / (max - min)); | 
| Chris@197 | 887             if (pixel < 0) pixel = 0; | 
| Chris@197 | 888             if (pixel > 255) pixel = 255; | 
| Chris@469 | 889             if (peaks && (pixel > peaks[y])) peaks[y] = pixel; | 
| Chris@197 | 890 | 
| Chris@357 | 891             if (m_invertVertical) { | 
| Chris@461 | 892                 m_cache->setPixel(c, cacheHeight - y - 1, pixel); | 
| Chris@357 | 893             } else { | 
| Chris@461 | 894                 m_cache->setPixel(c, y, pixel); | 
| Chris@357 | 895             } | 
| Chris@197 | 896         } | 
| Chris@469 | 897 | 
| Chris@469 | 898         if (peaks) { | 
| Chris@469 | 899             size_t notch = (c % m_peakResolution); | 
| Chris@469 | 900             if (notch == m_peakResolution-1 || c == fillEnd) { | 
| Chris@469 | 901                 size_t pc = c / m_peakResolution; | 
| Chris@469 | 902                 for (size_t y = 0; y < cacheHeight; ++y) { | 
| Chris@469 | 903                     if (m_invertVertical) { | 
| Chris@469 | 904                         m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]); | 
| Chris@469 | 905                     } else { | 
| Chris@469 | 906                         m_peaksCache->setPixel(pc, y, peaks[y]); | 
| Chris@469 | 907                     } | 
| Chris@469 | 908                 } | 
| Chris@469 | 909                 for (int y = 0; y < cacheHeight; ++y) { | 
| Chris@469 | 910                     peaks[y] = 0; | 
| Chris@469 | 911                 } | 
| Chris@469 | 912             } | 
| Chris@469 | 913         } | 
| Chris@197 | 914     } | 
| Chris@469 | 915 | 
| Chris@469 | 916     delete[] peaks; | 
| Chris@197 | 917 } | 
| Chris@197 | 918 | 
| Chris@197 | 919 void | 
| Chris@44 | 920 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const | 
| Chris@0 | 921 { | 
| Chris@443 | 922 /*!!! | 
| Chris@443 | 923     if (m_model) { | 
| Chris@443 | 924         std::cerr << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << std::endl; | 
| Chris@443 | 925     } | 
| Chris@443 | 926 */ | 
| Chris@466 | 927     Profiler profiler("Colour3DPlotLayer::paint"); | 
| Chris@125 | 928 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@125 | 929     std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl; | 
| Chris@125 | 930 #endif | 
| Chris@0 | 931 | 
| Chris@0 | 932     int completion = 0; | 
| Chris@0 | 933     if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) { | 
| Chris@0 | 934 	if (completion > 0) { | 
| Chris@44 | 935 	    paint.fillRect(0, 10, v->width() * completion / 100, | 
| Chris@0 | 936 			   10, QColor(120, 120, 120)); | 
| Chris@0 | 937 	} | 
| Chris@0 | 938 	return; | 
| Chris@0 | 939     } | 
| Chris@0 | 940 | 
| Chris@197 | 941     if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect(); | 
| Chris@197 | 942 | 
| Chris@0 | 943     size_t modelStart = m_model->getStartFrame(); | 
| Chris@0 | 944     size_t modelEnd = m_model->getEndFrame(); | 
| Chris@130 | 945     size_t modelResolution = m_model->getResolution(); | 
| Chris@0 | 946 | 
| Chris@197 | 947     // The cache is from the model's start frame to the model's end | 
| Chris@197 | 948     // frame at the model's window increment frames per pixel.  We | 
| Chris@197 | 949     // want to draw from our start frame + x0 * zoomLevel to our start | 
| Chris@197 | 950     // frame + x1 * zoomLevel at zoomLevel frames per pixel. | 
| Chris@12 | 951 | 
| Chris@197 | 952     //  We have quite different paint mechanisms for rendering "large" | 
| Chris@197 | 953     //  bins (more than one bin per pixel in both directions) and | 
| Chris@197 | 954     //  "small".  This is "large"; see paintDense below for "small". | 
| Chris@12 | 955 | 
| Chris@197 | 956     int x0 = rect.left(); | 
| Chris@197 | 957     int x1 = rect.right() + 1; | 
| Chris@12 | 958 | 
| Chris@197 | 959     int h = v->height(); | 
| Chris@0 | 960 | 
| Chris@197 | 961     float srRatio = | 
| Chris@197 | 962         float(v->getViewManager()->getMainModelSampleRate()) / | 
| Chris@197 | 963         float(m_model->getSampleRate()); | 
| Chris@0 | 964 | 
| Chris@197 | 965     int sx0 = int((v->getFrameForX(x0) / srRatio - long(modelStart)) | 
| Chris@197 | 966                   / long(modelResolution)); | 
| Chris@197 | 967     int sx1 = int((v->getFrameForX(x1) / srRatio - long(modelStart)) | 
| Chris@197 | 968                   / long(modelResolution)); | 
| Chris@197 | 969     int sh = m_model->getHeight(); | 
| Chris@159 | 970 | 
| Chris@444 | 971     int symin = m_miny; | 
| Chris@444 | 972     int symax = m_maxy; | 
| Chris@444 | 973     if (symax <= symin) { | 
| Chris@444 | 974         symin = 0; | 
| Chris@444 | 975         symax = sh; | 
| Chris@444 | 976     } | 
| Chris@444 | 977     if (symin < 0) symin = 0; | 
| Chris@444 | 978     if (symax > sh) symax = sh; | 
| Chris@444 | 979 | 
| Chris@197 | 980     if (sx0 > 0) --sx0; | 
| Chris@197 | 981     fillCache(sx0 < 0 ? 0 : sx0, | 
| Chris@197 | 982               sx1 < 0 ? 0 : sx1); | 
| Chris@0 | 983 | 
| Chris@351 | 984 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@466 | 985     std::cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << std::endl; | 
| Chris@351 | 986 #endif | 
| Chris@351 | 987 | 
| Chris@465 | 988     if (m_opaque || | 
| Chris@465 | 989         int(m_model->getHeight()) >= v->height() || | 
| Chris@466 | 990         ((modelResolution * srRatio) / v->getZoomLevel()) < 2) { | 
| Chris@347 | 991 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@351 | 992         std::cerr << "calling paintDense" << std::endl; | 
| Chris@347 | 993 #endif | 
| Chris@98 | 994         paintDense(v, paint, rect); | 
| Chris@98 | 995         return; | 
| Chris@98 | 996     } | 
| Chris@98 | 997 | 
| Chris@125 | 998 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@347 | 999     std::cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << std::endl; | 
| Chris@130 | 1000     std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << std::endl; | 
| Chris@125 | 1001 #endif | 
| Chris@0 | 1002 | 
| Chris@25 | 1003     QPoint illuminatePos; | 
| Chris@44 | 1004     bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos); | 
| Chris@54 | 1005     char labelbuf[10]; | 
| Chris@25 | 1006 | 
| Chris@197 | 1007     for (int sx = sx0; sx <= sx1; ++sx) { | 
| Chris@0 | 1008 | 
| Chris@130 | 1009 	int fx = sx * int(modelResolution); | 
| Chris@0 | 1010 | 
| Chris@351 | 1011 	if (fx + int(modelResolution) <= int(modelStart) || | 
| Chris@0 | 1012 	    fx > int(modelEnd)) continue; | 
| Chris@0 | 1013 | 
| Chris@248 | 1014         int rx0 = v->getXForFrame(int((fx + int(modelStart)) * srRatio)); | 
| Chris@248 | 1015 	int rx1 = v->getXForFrame(int((fx + int(modelStart) + int(modelResolution) + 1) * srRatio)); | 
| Chris@54 | 1016 | 
| Chris@159 | 1017 	int rw = rx1 - rx0; | 
| Chris@159 | 1018 	if (rw < 1) rw = 1; | 
| Chris@54 | 1019 | 
| Chris@159 | 1020 	bool showLabel = (rw > 10 && | 
| Chris@159 | 1021 			  paint.fontMetrics().width("0.000000") < rw - 3 && | 
| Chris@54 | 1022 			  paint.fontMetrics().height() < (h / sh)); | 
| Chris@98 | 1023 | 
| Chris@444 | 1024 	for (int sy = symin; sy < symax; ++sy) { | 
| Chris@0 | 1025 | 
| Chris@444 | 1026 	    int ry0 = h - ((sy - symin) * h) / (symax - symin) - 1; | 
| Chris@0 | 1027 	    QRgb pixel = qRgb(255, 255, 255); | 
| Chris@461 | 1028 	    if (sx >= 0 && sx < m_cache->width() && | 
| Chris@0 | 1029 		sy >= 0 && sy < m_cache->height()) { | 
| Chris@461 | 1030 		pixel = m_cache->pixel(sx, sy); | 
| Chris@0 | 1031 	    } | 
| Chris@0 | 1032 | 
| Chris@444 | 1033 	    QRect r(rx0, ry0 - h / (symax - symin) - 1, | 
| Chris@444 | 1034                     rw, h / (symax - symin) + 1); | 
| Chris@159 | 1035 | 
| Chris@159 | 1036             if (rw == 1) { | 
| Chris@159 | 1037                 paint.setPen(pixel); | 
| Chris@159 | 1038                 paint.setBrush(Qt::NoBrush); | 
| Chris@159 | 1039                 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1); | 
| Chris@159 | 1040                 continue; | 
| Chris@159 | 1041             } | 
| Chris@159 | 1042 | 
| Chris@0 | 1043 	    QColor pen(255, 255, 255, 80); | 
| Chris@0 | 1044 	    QColor brush(pixel); | 
| Chris@159 | 1045 | 
| Chris@159 | 1046             if (rw > 3 && r.height() > 3) { | 
| Chris@159 | 1047                 brush.setAlpha(160); | 
| Chris@159 | 1048             } | 
| Chris@159 | 1049 | 
| Chris@0 | 1050 	    paint.setPen(Qt::NoPen); | 
| Chris@0 | 1051 	    paint.setBrush(brush); | 
| Chris@0 | 1052 | 
| Chris@25 | 1053 	    if (illuminate) { | 
| Chris@25 | 1054 		if (r.contains(illuminatePos)) { | 
| Chris@287 | 1055 		    paint.setPen(v->getForeground()); | 
| Chris@25 | 1056 		} | 
| Chris@25 | 1057 	    } | 
| Chris@76 | 1058 | 
| Chris@125 | 1059 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | 
| Chris@159 | 1060             std::cerr << "rect " << r.x() << "," << r.y() << " " | 
| Chris@159 | 1061                       << r.width() << "x" << r.height() << std::endl; | 
| Chris@125 | 1062 #endif | 
| Chris@25 | 1063 | 
| Chris@25 | 1064 	    paint.drawRect(r); | 
| Chris@0 | 1065 | 
| Chris@54 | 1066 	    if (showLabel) { | 
| Chris@461 | 1067 		if (sx >= 0 && sx < m_cache->width() && | 
| Chris@54 | 1068 		    sy >= 0 && sy < m_cache->height()) { | 
| Chris@461 | 1069 		    float value = m_model->getValueAt(sx, sy); | 
| Chris@54 | 1070 		    sprintf(labelbuf, "%06f", value); | 
| Chris@54 | 1071 		    QString text(labelbuf); | 
| Chris@287 | 1072 		    paint.setPen(v->getBackground()); | 
| Chris@54 | 1073 		    paint.drawText(rx0 + 2, | 
| Chris@54 | 1074 				   ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(), | 
| Chris@54 | 1075 				   text); | 
| Chris@0 | 1076 		} | 
| Chris@0 | 1077 	    } | 
| Chris@0 | 1078 	} | 
| Chris@0 | 1079     } | 
| Chris@98 | 1080 } | 
| Chris@0 | 1081 | 
| Chris@98 | 1082 void | 
| Chris@98 | 1083 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const | 
| Chris@98 | 1084 { | 
| Chris@466 | 1085     Profiler profiler("Colour3DPlotLayer::paintDense"); | 
| Chris@463 | 1086     if (!m_cache) return; | 
| Chris@463 | 1087 | 
| Chris@466 | 1088     float modelStart = m_model->getStartFrame(); | 
| Chris@466 | 1089     float modelResolution = m_model->getResolution(); | 
| Chris@0 | 1090 | 
| Chris@469 | 1091     int mmsr = v->getViewManager()->getMainModelSampleRate(); | 
| Chris@469 | 1092     int msr = m_model->getSampleRate(); | 
| Chris@469 | 1093     float srRatio = float(mmsr) / float(msr); | 
| Chris@159 | 1094 | 
| Chris@98 | 1095     int x0 = rect.left(); | 
| Chris@98 | 1096     int x1 = rect.right() + 1; | 
| Chris@0 | 1097 | 
| Chris@98 | 1098     int w = x1 - x0; | 
| Chris@98 | 1099     int h = v->height(); | 
| Chris@160 | 1100     int sh = m_model->getHeight(); | 
| Chris@98 | 1101 | 
| Chris@444 | 1102     int symin = m_miny; | 
| Chris@444 | 1103     int symax = m_maxy; | 
| Chris@444 | 1104     if (symax <= symin) { | 
| Chris@444 | 1105         symin = 0; | 
| Chris@444 | 1106         symax = sh; | 
| Chris@444 | 1107     } | 
| Chris@444 | 1108     if (symin < 0) symin = 0; | 
| Chris@444 | 1109     if (symax > sh) symax = sh; | 
| Chris@444 | 1110 | 
| Chris@466 | 1111     QImage img(w, h, QImage::Format_Indexed8); | 
| Chris@466 | 1112     img.setColorTable(m_cache->colorTable()); | 
| Chris@98 | 1113 | 
| Chris@466 | 1114     uchar *peaks = new uchar[w]; | 
| Chris@466 | 1115     memset(peaks, 0, w); | 
| Chris@98 | 1116 | 
| Chris@469 | 1117     int zoomLevel = v->getZoomLevel(); | 
| Chris@469 | 1118 | 
| Chris@469 | 1119     QImage *source = m_cache; | 
| Chris@469 | 1120     if (m_peaksCache && | 
| Chris@469 | 1121         ((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) { | 
| Chris@469 | 1122 //        std::cerr << "using peaks cache" << std::endl; | 
| Chris@469 | 1123         source = m_peaksCache; | 
| Chris@469 | 1124         modelResolution *= m_peakResolution; | 
| Chris@469 | 1125     } else { | 
| Chris@469 | 1126 //        std::cerr << "not using peaks cache" << std::endl; | 
| Chris@469 | 1127     } | 
| Chris@469 | 1128 | 
| Chris@466 | 1129     int psy1i = -1; | 
| Chris@469 | 1130     int sw = source->width(); | 
| Chris@466 | 1131 | 
| Chris@466 | 1132     for (int y = 0; y < h; ++y) { | 
| Chris@466 | 1133 | 
| Chris@466 | 1134         float sy0 = symin + (float(h - y - 1) * (symax - symin)) / h; | 
| Chris@466 | 1135         float sy1 = symin + (float(h - y) * (symax - symin)) / h; | 
| Chris@466 | 1136 | 
| Chris@466 | 1137         int sy0i = int(sy0 + 0.001); | 
| Chris@466 | 1138         int sy1i = int(sy1); | 
| Chris@466 | 1139 | 
| Chris@466 | 1140         uchar *targetLine = img.scanLine(y); | 
| Chris@466 | 1141 | 
| Chris@466 | 1142         if (sy0i == sy1i && sy0i == psy1i) { // same scan line as just computed | 
| Chris@466 | 1143             goto copy; | 
| Chris@105 | 1144         } | 
| Chris@105 | 1145 | 
| Chris@466 | 1146         memset(peaks, 0, w); | 
| Chris@466 | 1147 | 
| Chris@466 | 1148         for (int sy = sy0i; sy <= sy1i; ++sy) { | 
| Chris@347 | 1149 | 
| Chris@469 | 1150             if (sy < 0 || sy >= source->height()) continue; | 
| Chris@466 | 1151 | 
| Chris@469 | 1152             uchar *sourceLine = source->scanLine(sy); | 
| Chris@98 | 1153 | 
| Chris@469 | 1154             long xf = -1; | 
| Chris@469 | 1155             long nxf = v->getFrameForX(x0); | 
| Chris@469 | 1156 | 
| Chris@469 | 1157             int nsxi = -1; | 
| Chris@98 | 1158 | 
| Chris@466 | 1159             for (int x = 0; x < w; ++x) { | 
| Chris@98 | 1160 | 
| Chris@466 | 1161                 xf = nxf; | 
| Chris@469 | 1162                 nxf = xf + zoomLevel; | 
| Chris@466 | 1163 | 
| Chris@466 | 1164                 if (xf < 0) { | 
| Chris@466 | 1165                     peaks[x] = 0; | 
| Chris@466 | 1166                     continue; | 
| Chris@466 | 1167                 } | 
| Chris@466 | 1168 | 
| Chris@466 | 1169                 float sx0 = (float(xf) / srRatio - modelStart) / modelResolution; | 
| Chris@466 | 1170                 float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution; | 
| Chris@98 | 1171 | 
| Chris@466 | 1172                 int sx0i = int(sx0 + 0.001); | 
| Chris@466 | 1173                 int sx1i = int(sx1); | 
| Chris@98 | 1174 | 
| Chris@466 | 1175                 uchar peak = 0; | 
| Chris@466 | 1176                 for (int sx = sx0i; sx <= sx1i; ++sx) { | 
| Chris@469 | 1177                     if (sx < 0 || sx >= sw) continue; | 
| Chris@466 | 1178                     if (sourceLine[sx] > peak) peak = sourceLine[sx]; | 
| Chris@98 | 1179                 } | 
| Chris@466 | 1180                 peaks[x] = peak; | 
| Chris@98 | 1181             } | 
| Chris@466 | 1182         } | 
| Chris@466 | 1183 | 
| Chris@466 | 1184     copy: | 
| Chris@466 | 1185         for (int x = 0; x < w; ++x) { | 
| Chris@466 | 1186             targetLine[x] = peaks[x]; | 
| Chris@98 | 1187         } | 
| Chris@0 | 1188     } | 
| Chris@0 | 1189 | 
| Chris@469 | 1190     delete[] peaks; | 
| Chris@469 | 1191 | 
| Chris@98 | 1192     paint.drawImage(x0, 0, img); | 
| Chris@0 | 1193 } | 
| Chris@0 | 1194 | 
| Chris@28 | 1195 bool | 
| Chris@44 | 1196 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame, | 
| Chris@28 | 1197 				      size_t &resolution, | 
| Chris@28 | 1198 				      SnapType snap) const | 
| Chris@24 | 1199 { | 
| Chris@24 | 1200     if (!m_model) { | 
| Chris@44 | 1201 	return Layer::snapToFeatureFrame(v, frame, resolution, snap); | 
| Chris@24 | 1202     } | 
| Chris@24 | 1203 | 
| Chris@130 | 1204     resolution = m_model->getResolution(); | 
| Chris@28 | 1205     int left = (frame / resolution) * resolution; | 
| Chris@28 | 1206     int right = left + resolution; | 
| Chris@28 | 1207 | 
| Chris@28 | 1208     switch (snap) { | 
| Chris@28 | 1209     case SnapLeft:  frame = left;  break; | 
| Chris@28 | 1210     case SnapRight: frame = right; break; | 
| Chris@28 | 1211     case SnapNearest: | 
| Chris@28 | 1212     case SnapNeighbouring: | 
| Chris@28 | 1213 	if (frame - left > right - frame) frame = right; | 
| Chris@28 | 1214 	else frame = left; | 
| Chris@28 | 1215 	break; | 
| Chris@28 | 1216     } | 
| Chris@24 | 1217 | 
| Chris@28 | 1218     return true; | 
| Chris@24 | 1219 } | 
| Chris@24 | 1220 | 
| Chris@316 | 1221 void | 
| Chris@316 | 1222 Colour3DPlotLayer::toXml(QTextStream &stream, | 
| Chris@316 | 1223                          QString indent, QString extraAttributes) const | 
| Chris@197 | 1224 { | 
| Chris@316 | 1225     QString s = QString("scale=\"%1\" " | 
| Chris@316 | 1226                         "colourScheme=\"%2\" " | 
| Chris@316 | 1227                         "normalizeColumns=\"%3\" " | 
| Chris@445 | 1228                         "normalizeVisibleArea=\"%4\" " | 
| Chris@445 | 1229                         "minY=\"%5\" " | 
| Chris@465 | 1230                         "maxY=\"%6\" " | 
| Chris@465 | 1231                         "invertVertical=\"%7\" " | 
| Chris@465 | 1232                         "opaque=\"%8\"") | 
| Chris@197 | 1233 	.arg((int)m_colourScale) | 
| Chris@197 | 1234         .arg(m_colourMap) | 
| Chris@197 | 1235         .arg(m_normalizeColumns ? "true" : "false") | 
| Chris@445 | 1236         .arg(m_normalizeVisibleArea ? "true" : "false") | 
| Chris@445 | 1237         .arg(m_miny) | 
| Chris@465 | 1238         .arg(m_maxy) | 
| Chris@465 | 1239         .arg(m_invertVertical ? "true" : "false") | 
| Chris@465 | 1240         .arg(m_opaque ? "true" : "false"); | 
| Chris@197 | 1241 | 
| Chris@316 | 1242     Layer::toXml(stream, indent, extraAttributes + " " + s); | 
| Chris@197 | 1243 } | 
| Chris@197 | 1244 | 
| Chris@197 | 1245 void | 
| Chris@197 | 1246 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes) | 
| Chris@197 | 1247 { | 
| Chris@445 | 1248     bool ok = false, alsoOk = false; | 
| Chris@197 | 1249 | 
| Chris@197 | 1250     ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok); | 
| Chris@197 | 1251     if (ok) setColourScale(scale); | 
| Chris@197 | 1252 | 
| Chris@197 | 1253     int colourMap = attributes.value("colourScheme").toInt(&ok); | 
| Chris@197 | 1254     if (ok) setColourMap(colourMap); | 
| Chris@197 | 1255 | 
| Chris@197 | 1256     bool normalizeColumns = | 
| Chris@197 | 1257         (attributes.value("normalizeColumns").trimmed() == "true"); | 
| Chris@197 | 1258     setNormalizeColumns(normalizeColumns); | 
| Chris@197 | 1259 | 
| Chris@197 | 1260     bool normalizeVisibleArea = | 
| Chris@197 | 1261         (attributes.value("normalizeVisibleArea").trimmed() == "true"); | 
| Chris@197 | 1262     setNormalizeVisibleArea(normalizeVisibleArea); | 
| Chris@445 | 1263 | 
| Chris@465 | 1264     bool invertVertical = | 
| Chris@465 | 1265         (attributes.value("invertVertical").trimmed() == "true"); | 
| Chris@465 | 1266     setInvertVertical(invertVertical); | 
| Chris@465 | 1267 | 
| Chris@465 | 1268     bool opaque = | 
| Chris@465 | 1269         (attributes.value("opaque").trimmed() == "true"); | 
| Chris@465 | 1270     setNormalizeVisibleArea(opaque); | 
| Chris@465 | 1271 | 
| Chris@445 | 1272     float min = attributes.value("minY").toFloat(&ok); | 
| Chris@445 | 1273     float max = attributes.value("maxY").toFloat(&alsoOk); | 
| Chris@445 | 1274     if (ok && alsoOk) setDisplayExtents(min, max); | 
| Chris@197 | 1275 } | 
| Chris@197 | 1276 |