annotate layer/Colour3DPlotLayer.cpp @ 1457:160e6d010141 single-point

Avoid showing progress bars for dormant layers. They'll typically be duplicates, e.g. in the vect app you can get many dormant layers all reporting the alignment completion at the same time. (Maybe it would be better just to reject progress bars for alignment in dormant layers? Hm)
author Chris Cannam
date Thu, 16 May 2019 15:50:02 +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