annotate layer/Colour3DPlotLayer.cpp @ 1242:b10bd0611d16

Fix various "model deleted with no aboutToDelete notification" warnings (and one associated potential memory leak)
author Chris Cannam
date Wed, 22 Feb 2017 12:01:39 +0000
parents 4d0ca1ab4cd0
children 3ec95b7d1bfc
rev   line source
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@0 18 #include "base/Profiler.h"
Chris@197 19 #include "base/LogRange.h"
Chris@444 20 #include "base/RangeMapper.h"
Chris@1077 21
Chris@376 22 #include "ColourMapper.h"
Chris@1077 23 #include "LayerGeometryProvider.h"
Chris@1078 24 #include "PaintAssistant.h"
Chris@1077 25
Chris@1100 26 #include "data/model/Dense3DModelPeakCache.h"
Chris@1100 27
Chris@1077 28 #include "view/ViewManager.h"
Chris@0 29
Chris@0 30 #include <QPainter>
Chris@0 31 #include <QImage>
Chris@0 32 #include <QRect>
Chris@316 33 #include <QTextStream>
Chris@1018 34 #include <QSettings>
Chris@0 35
Chris@0 36 #include <iostream>
Chris@0 37
Chris@0 38 #include <cassert>
Chris@0 39
Chris@903 40 using std::vector;
Chris@903 41
Chris@353 42 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
Chris@125 43
Chris@0 44
Chris@44 45 Colour3DPlotLayer::Colour3DPlotLayer() :
Chris@0 46 m_model(0),
Chris@1105 47 m_colourScale(ColourScaleType::Linear),
Chris@461 48 m_colourScaleSet(false),
Chris@197 49 m_colourMap(0),
Chris@534 50 m_gain(1.0),
Chris@1103 51 m_binScale(BinScale::Linear),
Chris@1104 52 m_normalization(ColumnNormalization::None),
Chris@1104 53 m_normalizeVisibleArea(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@1100 59 m_maxy(0),
Chris@1101 60 m_synchronous(false),
Chris@1100 61 m_peakCache(0),
Chris@1100 62 m_peakCacheDivisor(8)
Chris@0 63 {
Chris@1018 64 QSettings settings;
Chris@1018 65 settings.beginGroup("Preferences");
Chris@1018 66 setColourMap(settings.value("colour-3d-plot-colour", ColourMapper::Green).toInt());
Chris@1018 67 settings.endGroup();
Chris@0 68 }
Chris@0 69
Chris@0 70 Colour3DPlotLayer::~Colour3DPlotLayer()
Chris@0 71 {
Chris@1107 72 invalidateRenderers();
Chris@1242 73 if (m_peakCache) m_peakCache->aboutToDelete();
Chris@1100 74 delete m_peakCache;
Chris@0 75 }
Chris@0 76
Chris@1105 77 ColourScaleType
Chris@1104 78 Colour3DPlotLayer::convertToColourScale(int value)
Chris@1104 79 {
Chris@1104 80 switch (value) {
Chris@1104 81 default:
Chris@1105 82 case 0: return ColourScaleType::Linear;
Chris@1105 83 case 1: return ColourScaleType::Log;
Chris@1105 84 case 2: return ColourScaleType::PlusMinusOne;
Chris@1105 85 case 3: return ColourScaleType::Absolute;
Chris@1104 86 }
Chris@1104 87 }
Chris@1104 88
Chris@1104 89 int
Chris@1105 90 Colour3DPlotLayer::convertFromColourScale(ColourScaleType scale)
Chris@1104 91 {
Chris@1104 92 switch (scale) {
Chris@1105 93 case ColourScaleType::Linear: return 0;
Chris@1105 94 case ColourScaleType::Log: return 1;
Chris@1105 95 case ColourScaleType::PlusMinusOne: return 2;
Chris@1105 96 case ColourScaleType::Absolute: return 3;
Chris@1104 97
Chris@1105 98 case ColourScaleType::Meter:
Chris@1105 99 case ColourScaleType::Phase:
Chris@1104 100 default: return 0;
Chris@1104 101 }
Chris@1104 102 }
Chris@1104 103
Chris@1104 104 std::pair<ColumnNormalization, bool>
Chris@1104 105 Colour3DPlotLayer::convertToColumnNorm(int value)
Chris@1104 106 {
Chris@1104 107 switch (value) {
Chris@1104 108 default:
Chris@1104 109 case 0: return { ColumnNormalization::None, false };
Chris@1104 110 case 1: return { ColumnNormalization::Max1, false };
Chris@1104 111 case 2: return { ColumnNormalization::None, true }; // visible area
Chris@1104 112 case 3: return { ColumnNormalization::Hybrid, false };
Chris@1104 113 }
Chris@1104 114 }
Chris@1104 115
Chris@1104 116 int
Chris@1104 117 Colour3DPlotLayer::convertFromColumnNorm(ColumnNormalization norm, bool visible)
Chris@1104 118 {
Chris@1104 119 if (visible) return 2;
Chris@1104 120 switch (norm) {
Chris@1104 121 case ColumnNormalization::None: return 0;
Chris@1104 122 case ColumnNormalization::Max1: return 1;
Chris@1104 123 case ColumnNormalization::Hybrid: return 3;
Chris@1104 124
Chris@1104 125 case ColumnNormalization::Sum1:
Chris@1104 126 default: return 0;
Chris@1104 127 }
Chris@1104 128 }
Chris@1104 129
Chris@0 130 void
Chris@1101 131 Colour3DPlotLayer::setSynchronousPainting(bool synchronous)
Chris@1101 132 {
Chris@1101 133 m_synchronous = synchronous;
Chris@1101 134 }
Chris@1101 135
Chris@1101 136 void
Chris@0 137 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
Chris@0 138 {
Chris@1242 139 SVDEBUG << "Colour3DPlotLayer::setModel(" << model << ")" << endl;
Chris@1242 140
Chris@193 141 if (m_model == model) return;
Chris@193 142 const DenseThreeDimensionalModel *oldModel = m_model;
Chris@0 143 m_model = model;
Chris@0 144 if (!m_model || !m_model->isOK()) return;
Chris@0 145
Chris@320 146 connectSignals(m_model);
Chris@0 147
Chris@461 148 connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
Chris@908 149 connect(m_model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@908 150 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
Chris@0 151
Chris@474 152 m_peakResolution = 256;
Chris@474 153 if (model->getResolution() > 512) {
Chris@474 154 m_peakResolution = 16;
Chris@474 155 } else if (model->getResolution() > 128) {
Chris@474 156 m_peakResolution = 64;
Chris@474 157 } else if (model->getResolution() > 2) {
Chris@474 158 m_peakResolution = 128;
Chris@474 159 }
Chris@1100 160
Chris@1242 161 if (m_peakCache) m_peakCache->aboutToDelete();
Chris@1100 162 delete m_peakCache;
Chris@1100 163 m_peakCache = 0;
Chris@1100 164
Chris@1107 165 invalidateRenderers();
Chris@1235 166 invalidateMagnitudes();
Chris@474 167
Chris@0 168 emit modelReplaced();
Chris@193 169 emit sliceableModelReplaced(oldModel, model);
Chris@0 170 }
Chris@0 171
Chris@0 172 void
Chris@0 173 Colour3DPlotLayer::cacheInvalid()
Chris@0 174 {
Chris@1107 175 invalidateRenderers();
Chris@1235 176 invalidateMagnitudes();
Chris@1107 177 }
Chris@1102 178
Chris@1107 179 void
Chris@1107 180 Colour3DPlotLayer::cacheInvalid(sv_frame_t /* startFrame */,
Chris@1107 181 sv_frame_t /* endFrame */)
Chris@1107 182 {
Chris@1107 183 //!!! should do this only if the range is visible
Chris@1242 184 if (m_peakCache) m_peakCache->aboutToDelete();
Chris@1107 185 delete m_peakCache;
Chris@1108 186 m_peakCache = 0;
Chris@1108 187
Chris@1107 188 invalidateRenderers();
Chris@1235 189 invalidateMagnitudes();
Chris@1107 190 }
Chris@1107 191
Chris@1107 192 void
Chris@1107 193 Colour3DPlotLayer::invalidateRenderers()
Chris@1107 194 {
Chris@1102 195 for (ViewRendererMap::iterator i = m_renderers.begin();
Chris@1102 196 i != m_renderers.end(); ++i) {
Chris@1102 197 delete i->second;
Chris@1102 198 }
Chris@1102 199 m_renderers.clear();
Chris@0 200 }
Chris@0 201
Chris@1235 202 void
Chris@1235 203 Colour3DPlotLayer::invalidateMagnitudes()
Chris@1235 204 {
Chris@1235 205 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@1235 206 cerr << "Colour3DPlotLayer::invalidateMagnitudes called" << endl;
Chris@1235 207 #endif
Chris@1235 208 m_viewMags.clear();
Chris@1235 209 }
Chris@1235 210
Chris@1100 211 Dense3DModelPeakCache *
Chris@1100 212 Colour3DPlotLayer::getPeakCache() const
Chris@1100 213 {
Chris@1100 214 if (!m_peakCache) {
Chris@1100 215 m_peakCache = new Dense3DModelPeakCache(m_model, m_peakCacheDivisor);
Chris@1100 216 }
Chris@1100 217 return m_peakCache;
Chris@1100 218 }
Chris@1100 219
Chris@461 220 void
Chris@461 221 Colour3DPlotLayer::modelChanged()
Chris@461 222 {
Chris@1105 223 if (!m_colourScaleSet && m_colourScale == ColourScaleType::Linear) {
Chris@461 224 if (m_model) {
Chris@461 225 if (m_model->shouldUseLogValueScale()) {
Chris@1105 226 setColourScale(ColourScaleType::Log);
Chris@461 227 } else {
Chris@461 228 m_colourScaleSet = true;
Chris@461 229 }
Chris@461 230 }
Chris@461 231 }
Chris@0 232 cacheInvalid();
Chris@0 233 }
Chris@0 234
Chris@461 235 void
Chris@908 236 Colour3DPlotLayer::modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame)
Chris@461 237 {
Chris@1105 238 if (!m_colourScaleSet && m_colourScale == ColourScaleType::Linear) {
Chris@461 239 if (m_model && m_model->getWidth() > 50) {
Chris@461 240 if (m_model->shouldUseLogValueScale()) {
Chris@1105 241 setColourScale(ColourScaleType::Log);
Chris@461 242 } else {
Chris@461 243 m_colourScaleSet = true;
Chris@461 244 }
Chris@461 245 }
Chris@461 246 }
Chris@461 247 cacheInvalid(startFrame, endFrame);
Chris@461 248 }
Chris@461 249
Chris@159 250 Layer::PropertyList
Chris@159 251 Colour3DPlotLayer::getProperties() const
Chris@159 252 {
Chris@159 253 PropertyList list;
Chris@197 254 list.push_back("Colour");
Chris@159 255 list.push_back("Colour Scale");
Chris@1104 256 list.push_back("Normalization");
Chris@534 257 list.push_back("Gain");
Chris@531 258 list.push_back("Bin Scale");
Chris@357 259 list.push_back("Invert Vertical Scale");
Chris@465 260 list.push_back("Opaque");
Chris@535 261 list.push_back("Smooth");
Chris@159 262 return list;
Chris@159 263 }
Chris@159 264
Chris@159 265 QString
Chris@159 266 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
Chris@159 267 {
Chris@197 268 if (name == "Colour") return tr("Colour");
Chris@197 269 if (name == "Colour Scale") return tr("Scale");
Chris@1104 270 if (name == "Normalization") return tr("Normalization");
Chris@357 271 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
Chris@534 272 if (name == "Gain") return tr("Gain");
Chris@465 273 if (name == "Opaque") return tr("Always Opaque");
Chris@535 274 if (name == "Smooth") return tr("Smooth");
Chris@531 275 if (name == "Bin Scale") return tr("Bin Scale");
Chris@159 276 return "";
Chris@159 277 }
Chris@159 278
Chris@346 279 QString
Chris@346 280 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
Chris@346 281 {
Chris@357 282 if (name == "Invert Vertical Scale") return "invert-vertical";
Chris@465 283 if (name == "Opaque") return "opaque";
Chris@535 284 if (name == "Smooth") return "smooth";
Chris@346 285 return "";
Chris@346 286 }
Chris@346 287
Chris@159 288 Layer::PropertyType
Chris@159 289 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
Chris@159 290 {
Chris@534 291 if (name == "Gain") return RangeProperty;
Chris@357 292 if (name == "Invert Vertical Scale") return ToggleProperty;
Chris@465 293 if (name == "Opaque") return ToggleProperty;
Chris@535 294 if (name == "Smooth") return ToggleProperty;
Chris@1198 295 if (name == "Colour") return ColourMapProperty;
Chris@159 296 return ValueProperty;
Chris@159 297 }
Chris@159 298
Chris@159 299 QString
Chris@159 300 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
Chris@159 301 {
Chris@1104 302 if (name == "Normalization" ||
Chris@1104 303 name == "Colour Scale" ||
Chris@534 304 name == "Gain") return tr("Scale");
Chris@531 305 if (name == "Bin Scale" ||
Chris@531 306 name == "Invert Vertical Scale") return tr("Bins");
Chris@465 307 if (name == "Opaque" ||
Chris@535 308 name == "Smooth" ||
Chris@465 309 name == "Colour") return tr("Colour");
Chris@159 310 return QString();
Chris@159 311 }
Chris@159 312
Chris@159 313 int
Chris@159 314 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@216 315 int *min, int *max, int *deflt) const
Chris@159 316 {
Chris@216 317 int val = 0;
Chris@159 318
Chris@216 319 int garbage0, garbage1, garbage2;
Chris@159 320 if (!min) min = &garbage0;
Chris@159 321 if (!max) max = &garbage1;
Chris@216 322 if (!deflt) deflt = &garbage2;
Chris@159 323
Chris@534 324 if (name == "Gain") {
Chris@534 325
Chris@534 326 *min = -50;
Chris@534 327 *max = 50;
Chris@534 328
Chris@902 329 *deflt = int(lrint(log10(1.0) * 20.0));
Chris@534 330 if (*deflt < *min) *deflt = *min;
Chris@534 331 if (*deflt > *max) *deflt = *max;
Chris@534 332
Chris@902 333 val = int(lrint(log10(m_gain) * 20.0));
Chris@534 334 if (val < *min) val = *min;
Chris@534 335 if (val > *max) val = *max;
Chris@534 336
Chris@534 337 } else if (name == "Colour Scale") {
Chris@159 338
Chris@1099 339 // linear, log, +/-1, abs
Chris@159 340 *min = 0;
Chris@509 341 *max = 3;
Chris@1099 342 *deflt = 0;
Chris@159 343
Chris@1104 344 val = convertFromColourScale(m_colourScale);
Chris@159 345
Chris@197 346 } else if (name == "Colour") {
Chris@197 347
Chris@197 348 *min = 0;
Chris@197 349 *max = ColourMapper::getColourMapCount() - 1;
Chris@216 350 *deflt = 0;
Chris@197 351
Chris@216 352 val = m_colourMap;
Chris@197 353
Chris@1099 354 } else if (name == "Normalization") {
Chris@197 355
Chris@1099 356 *min = 0;
Chris@1099 357 *max = 3;
Chris@1104 358 *deflt = 0;
Chris@1104 359
Chris@1104 360 val = convertFromColumnNorm(m_normalization, m_normalizeVisibleArea);
Chris@197 361
Chris@357 362 } else if (name == "Invert Vertical Scale") {
Chris@357 363
Chris@357 364 *deflt = 0;
Chris@357 365 val = (m_invertVertical ? 1 : 0);
Chris@357 366
Chris@531 367 } else if (name == "Bin Scale") {
Chris@531 368
Chris@531 369 *min = 0;
Chris@531 370 *max = 1;
Chris@1103 371 *deflt = int(BinScale::Linear);
Chris@531 372 val = (int)m_binScale;
Chris@531 373
Chris@465 374 } else if (name == "Opaque") {
Chris@465 375
Chris@465 376 *deflt = 0;
Chris@465 377 val = (m_opaque ? 1 : 0);
Chris@465 378
Chris@535 379 } else if (name == "Smooth") {
Chris@535 380
Chris@535 381 *deflt = 0;
Chris@535 382 val = (m_smooth ? 1 : 0);
Chris@535 383
Chris@159 384 } else {
Chris@216 385 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@159 386 }
Chris@159 387
Chris@216 388 return val;
Chris@159 389 }
Chris@159 390
Chris@159 391 QString
Chris@159 392 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name,
Chris@159 393 int value) const
Chris@159 394 {
Chris@197 395 if (name == "Colour") {
Chris@197 396 return ColourMapper::getColourMapName(value);
Chris@197 397 }
Chris@159 398 if (name == "Colour Scale") {
Chris@159 399 switch (value) {
Chris@159 400 default:
Chris@198 401 case 0: return tr("Linear");
Chris@198 402 case 1: return tr("Log");
Chris@198 403 case 2: return tr("+/-1");
Chris@509 404 case 3: return tr("Absolute");
Chris@159 405 }
Chris@159 406 }
Chris@1099 407 if (name == "Normalization") {
Chris@1209 408 switch(value) {
Chris@1209 409 default:
Chris@1209 410 case 0: return tr("None");
Chris@1209 411 case 1: return tr("Col");
Chris@1209 412 case 2: return tr("View");
Chris@1209 413 case 3: return tr("Hybrid");
Chris@1209 414 }
Chris@1209 415 // return ""; // icon only
Chris@1099 416 }
Chris@531 417 if (name == "Bin Scale") {
Chris@531 418 switch (value) {
Chris@531 419 default:
Chris@531 420 case 0: return tr("Linear");
Chris@531 421 case 1: return tr("Log");
Chris@531 422 }
Chris@531 423 }
Chris@159 424 return tr("<unknown>");
Chris@159 425 }
Chris@159 426
Chris@1099 427 QString
Chris@1099 428 Colour3DPlotLayer::getPropertyValueIconName(const PropertyName &name,
Chris@1099 429 int value) const
Chris@1099 430 {
Chris@1099 431 if (name == "Normalization") {
Chris@1099 432 switch(value) {
Chris@1099 433 default:
Chris@1099 434 case 0: return "normalise-none";
Chris@1099 435 case 1: return "normalise-columns";
Chris@1099 436 case 2: return "normalise";
Chris@1099 437 case 3: return "normalise-hybrid";
Chris@1099 438 }
Chris@1099 439 }
Chris@1099 440 return "";
Chris@1099 441 }
Chris@1099 442
Chris@534 443 RangeMapper *
Chris@534 444 Colour3DPlotLayer::getNewPropertyRangeMapper(const PropertyName &name) const
Chris@534 445 {
Chris@534 446 if (name == "Gain") {
Chris@534 447 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
Chris@534 448 }
Chris@534 449 return 0;
Chris@534 450 }
Chris@534 451
Chris@159 452 void
Chris@159 453 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
Chris@159 454 {
Chris@534 455 if (name == "Gain") {
Chris@902 456 setGain(float(pow(10, value/20.0)));
Chris@534 457 } else if (name == "Colour Scale") {
Chris@1104 458 setColourScale(convertToColourScale(value));
Chris@197 459 } else if (name == "Colour") {
Chris@197 460 setColourMap(value);
Chris@357 461 } else if (name == "Invert Vertical Scale") {
Chris@357 462 setInvertVertical(value ? true : false);
Chris@465 463 } else if (name == "Opaque") {
Chris@465 464 setOpaque(value ? true : false);
Chris@535 465 } else if (name == "Smooth") {
Chris@535 466 setSmooth(value ? true : false);
Chris@531 467 } else if (name == "Bin Scale") {
Chris@531 468 switch (value) {
Chris@531 469 default:
Chris@1103 470 case 0: setBinScale(BinScale::Linear); break;
Chris@1103 471 case 1: setBinScale(BinScale::Log); break;
Chris@531 472 }
Chris@1099 473 } else if (name == "Normalization") {
Chris@1104 474 auto n = convertToColumnNorm(value);
Chris@1104 475 setNormalization(n.first);
Chris@1104 476 setNormalizeVisibleArea(n.second);
Chris@159 477 }
Chris@159 478 }
Chris@159 479
Chris@159 480 void
Chris@1105 481 Colour3DPlotLayer::setColourScale(ColourScaleType scale)
Chris@159 482 {
Chris@159 483 if (m_colourScale == scale) return;
Chris@159 484 m_colourScale = scale;
Chris@461 485 m_colourScaleSet = true;
Chris@1107 486 invalidateRenderers();
Chris@159 487 emit layerParametersChanged();
Chris@159 488 }
Chris@159 489
Chris@197 490 void
Chris@197 491 Colour3DPlotLayer::setColourMap(int map)
Chris@197 492 {
Chris@197 493 if (m_colourMap == map) return;
Chris@197 494 m_colourMap = map;
Chris@1107 495 invalidateRenderers();
Chris@197 496 emit layerParametersChanged();
Chris@197 497 }
Chris@197 498
Chris@197 499 void
Chris@534 500 Colour3DPlotLayer::setGain(float gain)
Chris@534 501 {
Chris@534 502 if (m_gain == gain) return;
Chris@534 503 m_gain = gain;
Chris@1107 504 invalidateRenderers();
Chris@534 505 emit layerParametersChanged();
Chris@534 506 }
Chris@534 507
Chris@534 508 float
Chris@534 509 Colour3DPlotLayer::getGain() const
Chris@534 510 {
Chris@534 511 return m_gain;
Chris@534 512 }
Chris@534 513
Chris@534 514 void
Chris@1103 515 Colour3DPlotLayer::setBinScale(BinScale binScale)
Chris@531 516 {
Chris@531 517 if (m_binScale == binScale) return;
Chris@531 518 m_binScale = binScale;
Chris@1107 519 invalidateRenderers();
Chris@531 520 emit layerParametersChanged();
Chris@531 521 }
Chris@531 522
Chris@1103 523 BinScale
Chris@531 524 Colour3DPlotLayer::getBinScale() const
Chris@531 525 {
Chris@531 526 return m_binScale;
Chris@531 527 }
Chris@531 528
Chris@531 529 void
Chris@1104 530 Colour3DPlotLayer::setNormalization(ColumnNormalization n)
Chris@197 531 {
Chris@1099 532 if (m_normalization == n) return;
Chris@1099 533
Chris@1099 534 m_normalization = n;
Chris@1107 535 invalidateRenderers();
Chris@1099 536
Chris@197 537 emit layerParametersChanged();
Chris@197 538 }
Chris@197 539
Chris@1104 540 ColumnNormalization
Chris@1099 541 Colour3DPlotLayer::getNormalization() const
Chris@197 542 {
Chris@1099 543 return m_normalization;
Chris@197 544 }
Chris@197 545
Chris@357 546 void
Chris@1104 547 Colour3DPlotLayer::setNormalizeVisibleArea(bool n)
Chris@1104 548 {
Chris@1104 549 if (m_normalizeVisibleArea == n) return;
Chris@1104 550
Chris@1235 551 invalidateRenderers();
Chris@1235 552 invalidateMagnitudes();
Chris@1104 553 m_normalizeVisibleArea = n;
Chris@1104 554
Chris@1104 555 emit layerParametersChanged();
Chris@1104 556 }
Chris@1104 557
Chris@1104 558 bool
Chris@1104 559 Colour3DPlotLayer::getNormalizeVisibleArea() const
Chris@1104 560 {
Chris@1104 561 return m_normalizeVisibleArea;
Chris@1104 562 }
Chris@1104 563
Chris@1104 564 void
Chris@357 565 Colour3DPlotLayer::setInvertVertical(bool n)
Chris@357 566 {
Chris@357 567 if (m_invertVertical == n) return;
Chris@357 568 m_invertVertical = n;
Chris@1107 569 invalidateRenderers();
Chris@357 570 emit layerParametersChanged();
Chris@357 571 }
Chris@357 572
Chris@465 573 void
Chris@465 574 Colour3DPlotLayer::setOpaque(bool n)
Chris@465 575 {
Chris@465 576 if (m_opaque == n) return;
Chris@465 577 m_opaque = n;
Chris@1107 578 invalidateRenderers();
Chris@465 579 emit layerParametersChanged();
Chris@465 580 }
Chris@465 581
Chris@535 582 void
Chris@535 583 Colour3DPlotLayer::setSmooth(bool n)
Chris@535 584 {
Chris@535 585 if (m_smooth == n) return;
Chris@535 586 m_smooth = n;
Chris@1107 587 invalidateRenderers();
Chris@535 588 emit layerParametersChanged();
Chris@535 589 }
Chris@535 590
Chris@357 591 bool
Chris@357 592 Colour3DPlotLayer::getInvertVertical() const
Chris@357 593 {
Chris@357 594 return m_invertVertical;
Chris@357 595 }
Chris@357 596
Chris@25 597 bool
Chris@465 598 Colour3DPlotLayer::getOpaque() const
Chris@465 599 {
Chris@465 600 return m_opaque;
Chris@465 601 }
Chris@465 602
Chris@535 603 bool
Chris@535 604 Colour3DPlotLayer::getSmooth() const
Chris@535 605 {
Chris@535 606 return m_smooth;
Chris@535 607 }
Chris@535 608
Chris@475 609 void
Chris@916 610 Colour3DPlotLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant)
Chris@475 611 {
Chris@475 612 if (dormant) {
Chris@475 613
Chris@475 614 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 615 cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")"
Chris@585 616 << endl;
Chris@475 617 #endif
Chris@475 618
Chris@475 619 if (isLayerDormant(v)) {
Chris@475 620 return;
Chris@475 621 }
Chris@475 622
Chris@475 623 Layer::setLayerDormant(v, true);
Chris@475 624
Chris@475 625 cacheInvalid();
Chris@475 626
Chris@475 627 } else {
Chris@475 628
Chris@475 629 Layer::setLayerDormant(v, false);
Chris@475 630 }
Chris@475 631 }
Chris@475 632
Chris@465 633 bool
Chris@1150 634 Colour3DPlotLayer::isLayerScrollable(const LayerGeometryProvider * /* v */) const
Chris@25 635 {
Chris@1121 636 return false;
Chris@25 637 }
Chris@25 638
Chris@444 639 bool
Chris@904 640 Colour3DPlotLayer::getValueExtents(double &min, double &max,
Chris@444 641 bool &logarithmic, QString &unit) const
Chris@444 642 {
Chris@444 643 if (!m_model) return false;
Chris@444 644
Chris@444 645 min = 0;
Chris@904 646 max = double(m_model->getHeight());
Chris@444 647
Chris@1238 648 logarithmic = (m_binScale == BinScale::Log);
Chris@444 649 unit = "";
Chris@444 650
Chris@444 651 return true;
Chris@444 652 }
Chris@444 653
Chris@444 654 bool
Chris@904 655 Colour3DPlotLayer::getDisplayExtents(double &min, double &max) const
Chris@444 656 {
Chris@444 657 if (!m_model) return false;
Chris@444 658
Chris@904 659 double hmax = double(m_model->getHeight());
Chris@902 660
Chris@904 661 min = m_miny;
Chris@904 662 max = m_maxy;
Chris@444 663 if (max <= min) {
Chris@444 664 min = 0;
Chris@902 665 max = hmax;
Chris@444 666 }
Chris@444 667 if (min < 0) min = 0;
Chris@902 668 if (max > hmax) max = hmax;
Chris@444 669
Chris@444 670 return true;
Chris@444 671 }
Chris@444 672
Chris@444 673 bool
Chris@904 674 Colour3DPlotLayer::setDisplayExtents(double min, double max)
Chris@444 675 {
Chris@444 676 if (!m_model) return false;
Chris@444 677
Chris@904 678 m_miny = int(lrint(min));
Chris@904 679 m_maxy = int(lrint(max));
Chris@444 680
Chris@1133 681 invalidateRenderers();
Chris@1133 682
Chris@444 683 emit layerParametersChanged();
Chris@444 684 return true;
Chris@444 685 }
Chris@444 686
Chris@725 687 bool
Chris@916 688 Colour3DPlotLayer::getYScaleValue(const LayerGeometryProvider *, int,
Chris@904 689 double &, QString &) const
Chris@725 690 {
Chris@725 691 return false;//!!!
Chris@725 692 }
Chris@725 693
Chris@444 694 int
Chris@444 695 Colour3DPlotLayer::getVerticalZoomSteps(int &defaultStep) const
Chris@444 696 {
Chris@444 697 if (!m_model) return 0;
Chris@444 698
Chris@444 699 defaultStep = 0;
Chris@444 700 int h = m_model->getHeight();
Chris@444 701 return h;
Chris@444 702 }
Chris@444 703
Chris@444 704 int
Chris@444 705 Colour3DPlotLayer::getCurrentVerticalZoomStep() const
Chris@444 706 {
Chris@444 707 if (!m_model) return 0;
Chris@444 708
Chris@904 709 double min, max;
Chris@444 710 getDisplayExtents(min, max);
Chris@904 711 return m_model->getHeight() - int(lrint(max - min));
Chris@444 712 }
Chris@444 713
Chris@444 714 void
Chris@444 715 Colour3DPlotLayer::setVerticalZoomStep(int step)
Chris@444 716 {
Chris@444 717 if (!m_model) return;
Chris@444 718
Chris@587 719 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): before: miny = " << m_miny << ", maxy = " << m_maxy << endl;
Chris@444 720
Chris@444 721 int dist = m_model->getHeight() - step;
Chris@444 722 if (dist < 1) dist = 1;
Chris@904 723 double centre = m_miny + (m_maxy - m_miny) / 2.0;
Chris@904 724 m_miny = int(lrint(centre - dist/2.0));
Chris@444 725 if (m_miny < 0) m_miny = 0;
Chris@444 726 m_maxy = m_miny + dist;
Chris@444 727 if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight();
Chris@444 728
Chris@1133 729 invalidateRenderers();
Chris@1133 730
Chris@587 731 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): after: miny = " << m_miny << ", maxy = " << m_maxy << endl;
Chris@444 732
Chris@444 733 emit layerParametersChanged();
Chris@444 734 }
Chris@444 735
Chris@444 736 RangeMapper *
Chris@444 737 Colour3DPlotLayer::getNewVerticalZoomRangeMapper() const
Chris@444 738 {
Chris@444 739 if (!m_model) return 0;
Chris@444 740
Chris@444 741 return new LinearRangeMapper(0, m_model->getHeight(),
Chris@444 742 0, m_model->getHeight(), "");
Chris@444 743 }
Chris@444 744
Chris@904 745 double
Chris@1113 746 Colour3DPlotLayer::getYForBin(const LayerGeometryProvider *v, double bin) const
Chris@532 747 {
Chris@904 748 double y = bin;
Chris@532 749 if (!m_model) return y;
Chris@904 750 double mn = 0, mx = m_model->getHeight();
Chris@532 751 getDisplayExtents(mn, mx);
Chris@916 752 double h = v->getPaintHeight();
Chris@1103 753 if (m_binScale == BinScale::Linear) {
Chris@532 754 y = h - (((bin - mn) * h) / (mx - mn));
Chris@532 755 } else {
Chris@904 756 double logmin = mn + 1, logmax = mx + 1;
Chris@532 757 LogRange::mapRange(logmin, logmax);
Chris@532 758 y = h - (((LogRange::map(bin + 1) - logmin) * h) / (logmax - logmin));
Chris@532 759 }
Chris@532 760 return y;
Chris@532 761 }
Chris@532 762
Chris@904 763 double
Chris@1113 764 Colour3DPlotLayer::getBinForY(const LayerGeometryProvider *v, double y) const
Chris@532 765 {
Chris@904 766 double bin = y;
Chris@532 767 if (!m_model) return bin;
Chris@904 768 double mn = 0, mx = m_model->getHeight();
Chris@532 769 getDisplayExtents(mn, mx);
Chris@916 770 double h = v->getPaintHeight();
Chris@1103 771 if (m_binScale == BinScale::Linear) {
Chris@1220 772 // Arrange that the first bin (mn) appears as the exact result
Chris@1220 773 // for the first pixel (which is pixel h-1) and the first
Chris@1220 774 // out-of-range bin (mx) would appear as the exact result for
Chris@1220 775 // the first out-of-range pixel (which would be pixel -1)
Chris@1220 776 bin = mn + ((h - y - 1) * (mx - mn)) / h;
Chris@532 777 } else {
Chris@904 778 double logmin = mn + 1, logmax = mx + 1;
Chris@532 779 LogRange::mapRange(logmin, logmax);
Chris@1220 780 bin = LogRange::unmap(logmin + ((h - y - 1) * (logmax - logmin)) / h) - 1;
Chris@532 781 }
Chris@532 782 return bin;
Chris@532 783 }
Chris@532 784
Chris@25 785 QString
Chris@916 786 Colour3DPlotLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
Chris@25 787 {
Chris@25 788 if (!m_model) return "";
Chris@25 789
Chris@25 790 int x = pos.x();
Chris@25 791 int y = pos.y();
Chris@25 792
Chris@902 793 sv_frame_t modelStart = m_model->getStartFrame();
Chris@805 794 int modelResolution = m_model->getResolution();
Chris@25 795
Chris@902 796 double srRatio =
Chris@902 797 v->getViewManager()->getMainModelSampleRate() /
Chris@902 798 m_model->getSampleRate();
Chris@159 799
Chris@902 800 int sx0 = int((double(v->getFrameForX(x)) / srRatio - double(modelStart)) /
Chris@812 801 modelResolution);
Chris@25 802
Chris@160 803 int f0 = sx0 * modelResolution;
Chris@160 804 int f1 = f0 + modelResolution;
Chris@160 805
Chris@447 806 int sh = m_model->getHeight();
Chris@447 807
Chris@447 808 int symin = m_miny;
Chris@447 809 int symax = m_maxy;
Chris@447 810 if (symax <= symin) {
Chris@447 811 symin = 0;
Chris@447 812 symax = sh;
Chris@447 813 }
Chris@447 814 if (symin < 0) symin = 0;
Chris@447 815 if (symax > sh) symax = sh;
Chris@447 816
Chris@916 817 // double binHeight = double(v->getPaintHeight()) / (symax - symin);
Chris@916 818 // int sy = int((v->getPaintHeight() - y) / binHeight) + symin;
Chris@534 819
Chris@903 820 int sy = getIBinForY(v, y);
Chris@25 821
Chris@812 822 if (sy < 0 || sy >= m_model->getHeight()) {
Chris@812 823 return "";
Chris@812 824 }
Chris@812 825
Chris@357 826 if (m_invertVertical) sy = m_model->getHeight() - sy - 1;
Chris@357 827
Chris@160 828 float value = m_model->getValueAt(sx0, sy);
Chris@159 829
Chris@682 830 // cerr << "bin value (" << sx0 << "," << sy << ") is " << value << endl;
Chris@25 831
Chris@25 832 QString binName = m_model->getBinName(sy);
Chris@25 833 if (binName == "") binName = QString("[%1]").arg(sy + 1);
Chris@25 834 else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
Chris@25 835
Chris@25 836 QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
Chris@160 837 .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
Chris@25 838 .toText(true).c_str())
Chris@160 839 .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
Chris@25 840 .toText(true).c_str())
Chris@25 841 .arg(binName)
Chris@25 842 .arg(value);
Chris@25 843
Chris@25 844 return text;
Chris@25 845 }
Chris@25 846
Chris@25 847 int
Chris@969 848 Colour3DPlotLayer::getColourScaleWidth(QPainter &p) const
Chris@159 849 {
Chris@969 850 // Font is rotated
Chris@969 851 int cw = p.fontMetrics().height();
Chris@159 852 return cw;
Chris@159 853 }
Chris@159 854
Chris@159 855 int
Chris@916 856 Colour3DPlotLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const
Chris@25 857 {
Chris@25 858 if (!m_model) return 0;
Chris@25 859
Chris@160 860 QString sampleText = QString("[%1]").arg(m_model->getHeight());
Chris@25 861 int tw = paint.fontMetrics().width(sampleText);
Chris@98 862 bool another = false;
Chris@25 863
Chris@805 864 for (int i = 0; i < m_model->getHeight(); ++i) {
Chris@25 865 if (m_model->getBinName(i).length() > sampleText.length()) {
Chris@25 866 sampleText = m_model->getBinName(i);
Chris@98 867 another = true;
Chris@25 868 }
Chris@25 869 }
Chris@98 870 if (another) {
Chris@25 871 tw = std::max(tw, paint.fontMetrics().width(sampleText));
Chris@25 872 }
Chris@25 873
Chris@159 874 return tw + 13 + getColourScaleWidth(paint);
Chris@25 875 }
Chris@25 876
Chris@25 877 void
Chris@916 878 Colour3DPlotLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const
Chris@25 879 {
Chris@25 880 if (!m_model) return;
Chris@25 881
Chris@25 882 int h = rect.height(), w = rect.width();
Chris@25 883
Chris@159 884 int cw = getColourScaleWidth(paint);
Chris@159 885
Chris@159 886 int ch = h - 20;
Chris@1107 887 if (ch > 20) {
Chris@159 888
Chris@1131 889 double min = m_viewMags[v->getId()].getMin();
Chris@1131 890 double max = m_viewMags[v->getId()].getMax();
Chris@447 891
Chris@1131 892 if (max <= min) max = min + 0.1;
Chris@447 893
Chris@287 894 paint.setPen(v->getForeground());
Chris@447 895 paint.drawRect(4, 10, cw - 8, ch+1);
Chris@159 896
Chris@446 897 for (int y = 0; y < ch; ++y) {
Chris@904 898 double value = ((max - min) * (double(ch-y) - 1.0)) / double(ch) + min;
Chris@1131 899 paint.setPen(getRenderer(v)->getColour(value));
Chris@1131 900 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
Chris@159 901 }
Chris@446 902
Chris@446 903 QString minstr = QString("%1").arg(min);
Chris@446 904 QString maxstr = QString("%1").arg(max);
Chris@446 905
Chris@446 906 paint.save();
Chris@446 907
Chris@446 908 QFont font = paint.font();
Chris@1053 909 if (font.pixelSize() > 0) {
Chris@1053 910 int newSize = int(font.pixelSize() * 0.65);
Chris@1053 911 if (newSize < 6) newSize = 6;
Chris@1053 912 font.setPixelSize(newSize);
Chris@1053 913 paint.setFont(font);
Chris@1053 914 }
Chris@446 915
Chris@446 916 int msw = paint.fontMetrics().width(maxstr);
Chris@446 917
Chris@446 918 QMatrix m;
Chris@446 919 m.translate(cw - 6, ch + 10);
Chris@446 920 m.rotate(-90);
Chris@446 921
Chris@446 922 paint.setWorldMatrix(m);
Chris@446 923
Chris@1078 924 PaintAssistant::drawVisibleText(v, paint, 2, 0, minstr, PaintAssistant::OutlinedText);
Chris@446 925
Chris@446 926 m.translate(ch - msw - 2, 0);
Chris@446 927 paint.setWorldMatrix(m);
Chris@446 928
Chris@1078 929 PaintAssistant::drawVisibleText(v, paint, 0, 0, maxstr, PaintAssistant::OutlinedText);
Chris@446 930
Chris@446 931 paint.restore();
Chris@159 932 }
Chris@159 933
Chris@287 934 paint.setPen(v->getForeground());
Chris@159 935
Chris@445 936 int sh = m_model->getHeight();
Chris@445 937
Chris@445 938 int symin = m_miny;
Chris@445 939 int symax = m_maxy;
Chris@445 940 if (symax <= symin) {
Chris@445 941 symin = 0;
Chris@445 942 symax = sh;
Chris@445 943 }
Chris@445 944 if (symin < 0) symin = 0;
Chris@445 945 if (symax > sh) symax = sh;
Chris@445 946
Chris@532 947 paint.save();
Chris@456 948
Chris@533 949 int py = h;
Chris@25 950
Chris@969 951 int defaultFontHeight = paint.fontMetrics().height();
Chris@969 952
Chris@805 953 for (int i = symin; i <= symax; ++i) {
Chris@98 954
Chris@532 955 int y0;
Chris@534 956
Chris@903 957 y0 = getIYForBin(v, i);
Chris@532 958 int h = py - y0;
Chris@532 959
Chris@532 960 if (i > symin) {
Chris@532 961 if (paint.fontMetrics().height() >= h) {
Chris@969 962 if (h >= defaultFontHeight * 0.8) {
Chris@532 963 QFont tf = paint.font();
Chris@973 964 tf.setPixelSize(int(h * 0.8));
Chris@532 965 paint.setFont(tf);
Chris@532 966 } else {
Chris@532 967 continue;
Chris@532 968 }
Chris@532 969 }
Chris@532 970 }
Chris@25 971
Chris@532 972 py = y0;
Chris@532 973
Chris@534 974 if (i < symax) {
Chris@534 975 paint.drawLine(cw, y0, w, y0);
Chris@534 976 }
Chris@25 977
Chris@532 978 if (i > symin) {
Chris@534 979
Chris@805 980 int idx = i - 1;
Chris@534 981 if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
Chris@534 982
Chris@534 983 QString text = m_model->getBinName(idx);
Chris@534 984 if (text == "") text = QString("[%1]").arg(idx + 1);
Chris@534 985
Chris@534 986 int ty = y0 + (h/2) - (paint.fontMetrics().height()/2) +
Chris@534 987 paint.fontMetrics().ascent() + 1;
Chris@534 988
Chris@534 989 paint.drawText(cw + 5, ty, text);
Chris@457 990 }
Chris@25 991 }
Chris@456 992
Chris@456 993 paint.restore();
Chris@25 994 }
Chris@25 995
Chris@467 996 DenseThreeDimensionalModel::Column
Chris@805 997 Colour3DPlotLayer::getColumn(int col) const
Chris@197 998 {
Chris@812 999 Profiler profiler("Colour3DPlotLayer::getColumn");
Chris@812 1000
Chris@467 1001 DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
Chris@1019 1002 values.resize(m_model->getHeight(), 0.f);
Chris@1104 1003 if (m_normalization != ColumnNormalization::Max1 &&
Chris@1104 1004 m_normalization != ColumnNormalization::Hybrid) {
Chris@1099 1005 return values;
Chris@1099 1006 }
Chris@461 1007
Chris@904 1008 double colMax = 0.f, colMin = 0.f;
Chris@904 1009 double min = 0.f, max = 0.f;
Chris@197 1010
Chris@1019 1011 int nv = int(values.size());
Chris@1019 1012
Chris@461 1013 min = m_model->getMinimumLevel();
Chris@461 1014 max = m_model->getMaximumLevel();
Chris@461 1015
Chris@1019 1016 for (int y = 0; y < nv; ++y) {
Chris@467 1017 if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
Chris@467 1018 if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
Chris@197 1019 }
Chris@461 1020 if (colMin == colMax) colMax = colMin + 1;
Chris@197 1021
Chris@1019 1022 for (int y = 0; y < nv; ++y) {
Chris@461 1023
Chris@904 1024 double value = values.at(y);
Chris@904 1025 double norm = (value - colMin) / (colMax - colMin);
Chris@904 1026 double newvalue = min + (max - min) * norm;
Chris@197 1027
Chris@904 1028 if (value != newvalue) values[y] = float(newvalue);
Chris@468 1029 }
Chris@468 1030
Chris@1104 1031 if (m_normalization == ColumnNormalization::Hybrid
Chris@1099 1032 && (colMax > 0.0)) {
Chris@904 1033 double logmax = log10(colMax);
Chris@1019 1034 for (int y = 0; y < nv; ++y) {
Chris@904 1035 values[y] = float(values[y] * logmax);
Chris@719 1036 }
Chris@719 1037 }
Chris@719 1038
Chris@468 1039 return values;
Chris@197 1040 }
Chris@1114 1041
Chris@1100 1042 Colour3DPlotRenderer *
Chris@1113 1043 Colour3DPlotLayer::getRenderer(const LayerGeometryProvider *v) const
Chris@1100 1044 {
Chris@1235 1045 int viewId = v->getId();
Chris@1235 1046
Chris@1235 1047 if (m_renderers.find(viewId) == m_renderers.end()) {
Chris@1100 1048
Chris@1100 1049 Colour3DPlotRenderer::Sources sources;
Chris@1100 1050 sources.verticalBinLayer = this;
Chris@1100 1051 sources.fft = 0;
Chris@1100 1052 sources.source = m_model;
Chris@1212 1053 sources.peakCaches.push_back(getPeakCache());
Chris@1100 1054
Chris@1100 1055 ColourScale::Parameters cparams;
Chris@1100 1056 cparams.colourMap = m_colourMap;
Chris@1137 1057 cparams.scaleType = m_colourScale;
Chris@1100 1058 cparams.gain = m_gain;
Chris@1100 1059
Chris@1235 1060 double minValue = 0.0;
Chris@1235 1061 double maxValue = 1.0;
Chris@1235 1062
Chris@1235 1063 if (m_normalizeVisibleArea && m_viewMags[viewId].isSet()) {
Chris@1235 1064 minValue = m_viewMags[viewId].getMin();
Chris@1235 1065 maxValue = m_viewMags[viewId].getMax();
Chris@1235 1066 } else if (m_normalization == ColumnNormalization::None) {
Chris@1235 1067 minValue = m_model->getMinimumLevel();
Chris@1235 1068 maxValue = m_model->getMaximumLevel();
Chris@1131 1069 } else if (m_normalization == ColumnNormalization::Hybrid) {
Chris@1235 1070 minValue = 0;
Chris@1235 1071 maxValue = log10(m_model->getMaximumLevel() + 1.0);
Chris@1131 1072 }
Chris@1131 1073
Chris@1235 1074 if (maxValue <= minValue) {
Chris@1235 1075 maxValue = minValue + 0.1f;
Chris@1131 1076 }
Chris@1235 1077
Chris@1235 1078 cparams.minValue = minValue;
Chris@1235 1079 cparams.maxValue = maxValue;
Chris@1131 1080
Chris@1235 1081 m_lastRenderedMags[viewId] = MagnitudeRange(float(minValue),
Chris@1235 1082 float(maxValue));
Chris@1235 1083
Chris@1100 1084 Colour3DPlotRenderer::Parameters params;
Chris@1100 1085 params.colourScale = ColourScale(cparams);
Chris@1100 1086 params.normalization = m_normalization;
Chris@1100 1087 params.binScale = m_binScale;
Chris@1100 1088 params.alwaysOpaque = m_opaque;
Chris@1100 1089 params.invertVertical = m_invertVertical;
Chris@1100 1090 params.interpolate = m_smooth;
Chris@1100 1091
Chris@1235 1092 m_renderers[viewId] = new Colour3DPlotRenderer(sources, params);
Chris@1100 1093 }
Chris@1100 1094
Chris@1235 1095 return m_renderers[viewId];
Chris@1100 1096 }
Chris@1100 1097
Chris@197 1098 void
Chris@1107 1099 Colour3DPlotLayer::paintWithRenderer(LayerGeometryProvider *v,
Chris@1107 1100 QPainter &paint, QRect rect) const
Chris@1101 1101 {
Chris@1101 1102 Colour3DPlotRenderer *renderer = getRenderer(v);
Chris@1101 1103
Chris@1121 1104 Colour3DPlotRenderer::RenderResult result;
Chris@1123 1105 MagnitudeRange magRange;
Chris@1123 1106 int viewId = v->getId();
Chris@1123 1107
Chris@1235 1108 bool continuingPaint = !renderer->geometryChanged(v);
Chris@1235 1109
Chris@1235 1110 if (continuingPaint) {
Chris@1123 1111 magRange = m_viewMags[viewId];
Chris@1123 1112 }
Chris@1121 1113
Chris@1101 1114 if (m_synchronous) {
Chris@1121 1115
Chris@1121 1116 result = renderer->render(v, paint, rect);
Chris@1121 1117
Chris@1121 1118 } else {
Chris@1121 1119
Chris@1121 1120 result = renderer->renderTimeConstrained(v, paint, rect);
Chris@1121 1121
Chris@1121 1122 QRect uncached = renderer->getLargestUncachedRect(v);
Chris@1121 1123 if (uncached.width() > 0) {
Chris@1121 1124 v->updatePaintRect(uncached);
Chris@1121 1125 }
Chris@1101 1126 }
Chris@1121 1127
Chris@1123 1128 magRange.sample(result.range);
Chris@1101 1129
Chris@1123 1130 if (magRange.isSet()) {
Chris@1235 1131 if (m_viewMags[viewId] != magRange) {
Chris@1123 1132 m_viewMags[viewId] = magRange;
Chris@1235 1133 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@1235 1134 cerr << "mag range in this view has changed: "
Chris@1235 1135 << magRange.getMin() << " -> " << magRange.getMax() << endl;
Chris@1235 1136 #endif
Chris@1123 1137 }
Chris@1123 1138 }
Chris@1101 1139
Chris@1235 1140 if (!continuingPaint && m_normalizeVisibleArea &&
Chris@1235 1141 m_viewMags[viewId] != m_lastRenderedMags[viewId]) {
Chris@1235 1142 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@1235 1143 cerr << "mag range has changed from last rendered range: re-rendering"
Chris@1235 1144 << endl;
Chris@1235 1145 #endif
Chris@1235 1146 delete m_renderers[viewId];
Chris@1235 1147 m_renderers.erase(viewId);
Chris@1235 1148 v->updatePaintRect(v->getPaintRect());
Chris@1235 1149 }
Chris@1101 1150 }
Chris@1101 1151
Chris@1101 1152 void
Chris@916 1153 Colour3DPlotLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@0 1154 {
Chris@514 1155 /*
Chris@443 1156 if (m_model) {
Chris@587 1157 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
Chris@443 1158 }
Chris@514 1159 */
Chris@466 1160 Profiler profiler("Colour3DPlotLayer::paint");
Chris@125 1161 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1162 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 1163 #endif
Chris@0 1164
Chris@0 1165 int completion = 0;
Chris@0 1166 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
Chris@0 1167 if (completion > 0) {
Chris@916 1168 paint.fillRect(0, 10, v->getPaintWidth() * completion / 100,
Chris@0 1169 10, QColor(120, 120, 120));
Chris@0 1170 }
Chris@0 1171 return;
Chris@0 1172 }
Chris@0 1173
Chris@1053 1174 if (m_model->getWidth() == 0) {
Chris@1053 1175 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@1053 1176 cerr << "Colour3DPlotLayer::paint(): model width == 0, "
Chris@1053 1177 << "nothing to paint (yet)" << endl;
Chris@1053 1178 #endif
Chris@1053 1179 return;
Chris@1053 1180 }
Chris@1101 1181
Chris@1107 1182 paintWithRenderer(v, paint, rect);
Chris@1107 1183 }
Chris@1107 1184
Chris@28 1185 bool
Chris@916 1186 Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@805 1187 int &resolution,
Chris@28 1188 SnapType snap) const
Chris@24 1189 {
Chris@24 1190 if (!m_model) {
Chris@44 1191 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@24 1192 }
Chris@24 1193
Chris@130 1194 resolution = m_model->getResolution();
Chris@904 1195 sv_frame_t left = (frame / resolution) * resolution;
Chris@904 1196 sv_frame_t right = left + resolution;
Chris@28 1197
Chris@28 1198 switch (snap) {
Chris@28 1199 case SnapLeft: frame = left; break;
Chris@28 1200 case SnapRight: frame = right; break;
Chris@28 1201 case SnapNearest:
Chris@28 1202 case SnapNeighbouring:
Chris@28 1203 if (frame - left > right - frame) frame = right;
Chris@28 1204 else frame = left;
Chris@28 1205 break;
Chris@28 1206 }
Chris@24 1207
Chris@28 1208 return true;
Chris@24 1209 }
Chris@24 1210
Chris@316 1211 void
Chris@316 1212 Colour3DPlotLayer::toXml(QTextStream &stream,
Chris@316 1213 QString indent, QString extraAttributes) const
Chris@197 1214 {
Chris@316 1215 QString s = QString("scale=\"%1\" "
Chris@316 1216 "colourScheme=\"%2\" "
Chris@1099 1217 "minY=\"%3\" "
Chris@1099 1218 "maxY=\"%4\" "
Chris@1099 1219 "invertVertical=\"%5\" "
Chris@1099 1220 "opaque=\"%6\" %7")
Chris@1104 1221 .arg(convertFromColourScale(m_colourScale))
Chris@197 1222 .arg(m_colourMap)
Chris@445 1223 .arg(m_miny)
Chris@465 1224 .arg(m_maxy)
Chris@465 1225 .arg(m_invertVertical ? "true" : "false")
Chris@534 1226 .arg(m_opaque ? "true" : "false")
Chris@536 1227 .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
Chris@1103 1228 .arg(int(m_binScale))
Chris@536 1229 .arg(m_smooth ? "true" : "false")
Chris@536 1230 .arg(m_gain));
Chris@535 1231
Chris@1099 1232 // New-style normalization attributes, allowing for more types of
Chris@1099 1233 // normalization in future: write out the column normalization
Chris@1099 1234 // type separately, and then whether we are normalizing visible
Chris@1099 1235 // area as well afterwards
Chris@1099 1236
Chris@1099 1237 s += QString("columnNormalization=\"%1\" ")
Chris@1104 1238 .arg(m_normalization == ColumnNormalization::Max1 ? "peak" :
Chris@1104 1239 m_normalization == ColumnNormalization::Hybrid ? "hybrid" : "none");
Chris@1099 1240
Chris@1099 1241 // Old-style normalization attribute, for backward compatibility
Chris@1099 1242
Chris@1099 1243 s += QString("normalizeColumns=\"%1\" ")
Chris@1104 1244 .arg(m_normalization == ColumnNormalization::Max1 ? "true" : "false");
Chris@1099 1245
Chris@1099 1246 // And this applies to both old- and new-style attributes
Chris@1099 1247
Chris@1099 1248 s += QString("normalizeVisibleArea=\"%1\" ")
Chris@1104 1249 .arg(m_normalizeVisibleArea ? "true" : "false");
Chris@1099 1250
Chris@316 1251 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@197 1252 }
Chris@197 1253
Chris@197 1254 void
Chris@197 1255 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
Chris@197 1256 {
Chris@445 1257 bool ok = false, alsoOk = false;
Chris@197 1258
Chris@1105 1259 ColourScaleType colourScale = convertToColourScale
Chris@1099 1260 (attributes.value("colourScale").toInt(&ok));
Chris@1099 1261 if (ok) setColourScale(colourScale);
Chris@197 1262
Chris@197 1263 int colourMap = attributes.value("colourScheme").toInt(&ok);
Chris@197 1264 if (ok) setColourMap(colourMap);
Chris@197 1265
Chris@1103 1266 BinScale binScale = (BinScale)
Chris@1099 1267 attributes.value("binScale").toInt(&ok);
Chris@1099 1268 if (ok) setBinScale(binScale);
Chris@445 1269
Chris@465 1270 bool invertVertical =
Chris@465 1271 (attributes.value("invertVertical").trimmed() == "true");
Chris@465 1272 setInvertVertical(invertVertical);
Chris@465 1273
Chris@465 1274 bool opaque =
Chris@465 1275 (attributes.value("opaque").trimmed() == "true");
Chris@535 1276 setOpaque(opaque);
Chris@535 1277
Chris@535 1278 bool smooth =
Chris@535 1279 (attributes.value("smooth").trimmed() == "true");
Chris@535 1280 setSmooth(smooth);
Chris@465 1281
Chris@536 1282 float gain = attributes.value("gain").toFloat(&ok);
Chris@536 1283 if (ok) setGain(gain);
Chris@536 1284
Chris@445 1285 float min = attributes.value("minY").toFloat(&ok);
Chris@445 1286 float max = attributes.value("maxY").toFloat(&alsoOk);
Chris@445 1287 if (ok && alsoOk) setDisplayExtents(min, max);
Chris@1099 1288
Chris@1099 1289 bool haveNewStyleNormalization = false;
Chris@1099 1290
Chris@1099 1291 QString columnNormalization = attributes.value("columnNormalization");
Chris@1099 1292
Chris@1099 1293 if (columnNormalization != "") {
Chris@1099 1294
Chris@1099 1295 haveNewStyleNormalization = true;
Chris@1099 1296
Chris@1099 1297 if (columnNormalization == "peak") {
Chris@1104 1298 setNormalization(ColumnNormalization::Max1);
Chris@1099 1299 } else if (columnNormalization == "hybrid") {
Chris@1104 1300 setNormalization(ColumnNormalization::Hybrid);
Chris@1099 1301 } else if (columnNormalization == "none") {
Chris@1104 1302 setNormalization(ColumnNormalization::None);
Chris@1099 1303 } else {
Chris@1099 1304 cerr << "NOTE: Unknown or unsupported columnNormalization attribute \""
Chris@1099 1305 << columnNormalization << "\"" << endl;
Chris@1099 1306 }
Chris@1099 1307 }
Chris@1099 1308
Chris@1099 1309 if (!haveNewStyleNormalization) {
Chris@1099 1310
Chris@1104 1311 setNormalization(ColumnNormalization::None);
Chris@1104 1312
Chris@1099 1313 bool normalizeColumns =
Chris@1099 1314 (attributes.value("normalizeColumns").trimmed() == "true");
Chris@1099 1315 if (normalizeColumns) {
Chris@1104 1316 setNormalization(ColumnNormalization::Max1);
Chris@1099 1317 }
Chris@1099 1318
Chris@1099 1319 bool normalizeHybrid =
Chris@1099 1320 (attributes.value("normalizeHybrid").trimmed() == "true");
Chris@1099 1321 if (normalizeHybrid) {
Chris@1104 1322 setNormalization(ColumnNormalization::Hybrid);
Chris@1099 1323 }
Chris@1099 1324 }
Chris@1099 1325
Chris@1099 1326 bool normalizeVisibleArea =
Chris@1099 1327 (attributes.value("normalizeVisibleArea").trimmed() == "true");
Chris@1104 1328 setNormalizeVisibleArea(normalizeVisibleArea);
Chris@1099 1329
Chris@1099 1330 //!!! todo: check save/reload scaling, compare with
Chris@1099 1331 //!!! SpectrogramLayer, compare with prior SV versions, compare
Chris@1099 1332 //!!! with Tony v1 and v2 and their save files
Chris@197 1333 }
Chris@197 1334