annotate layer/Colour3DPlotLayer.cpp @ 1212:a1ee3108d1d3 3.0-integration

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