annotate layer/Colour3DPlotLayer.cpp @ 1464:66bf1abfefc1

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