annotate layer/Colour3DPlotLayer.cpp @ 1430:31499c3520ee single-point

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