annotate layer/Colour3DPlotLayer.cpp @ 1431:af824022bffd single-point

Begin fixing the various snap operations. Also remove SnapNearest, which is never used and seems to consume more lines of code than the rest!
author Chris Cannam
date Wed, 20 Mar 2019 14:59:34 +0000
parents 8e40faa56ffd
children 39f1154c0e97
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 SnapNeighbouring:
Chris@1266 1193 if (frame - left > right - frame) frame = right;
Chris@1266 1194 else frame = left;
Chris@1266 1195 break;
Chris@28 1196 }
Chris@24 1197
Chris@28 1198 return true;
Chris@24 1199 }
Chris@24 1200
Chris@316 1201 void
Chris@316 1202 Colour3DPlotLayer::toXml(QTextStream &stream,
Chris@316 1203 QString indent, QString extraAttributes) const
Chris@197 1204 {
Chris@316 1205 QString s = QString("scale=\"%1\" "
Chris@1362 1206 "minY=\"%2\" "
Chris@1362 1207 "maxY=\"%3\" "
Chris@1362 1208 "invertVertical=\"%4\" "
Chris@1362 1209 "opaque=\"%5\" %6")
Chris@1266 1210 .arg(convertFromColourScale(m_colourScale))
Chris@445 1211 .arg(m_miny)
Chris@465 1212 .arg(m_maxy)
Chris@465 1213 .arg(m_invertVertical ? "true" : "false")
Chris@534 1214 .arg(m_opaque ? "true" : "false")
Chris@536 1215 .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
Chris@1103 1216 .arg(int(m_binScale))
Chris@536 1217 .arg(m_smooth ? "true" : "false")
Chris@536 1218 .arg(m_gain));
Chris@1362 1219
Chris@1362 1220 // New-style colour map attribute, by string id rather than by
Chris@1362 1221 // number
Chris@1362 1222
Chris@1362 1223 s += QString("colourMap=\"%1\" ")
Chris@1362 1224 .arg(ColourMapper::getColourMapId(m_colourMap));
Chris@1362 1225
Chris@1362 1226 // Old-style colour map attribute
Chris@1362 1227
Chris@1362 1228 s += QString("colourScheme=\"%1\" ")
Chris@1362 1229 .arg(ColourMapper::getBackwardCompatibilityColourMap(m_colourMap));
Chris@535 1230
Chris@1099 1231 // New-style normalization attributes, allowing for more types of
Chris@1099 1232 // normalization in future: write out the column normalization
Chris@1099 1233 // type separately, and then whether we are normalizing visible
Chris@1099 1234 // area as well afterwards
Chris@1099 1235
Chris@1099 1236 s += QString("columnNormalization=\"%1\" ")
Chris@1245 1237 .arg(m_normalization == ColumnNormalization::Range01 ? "peak" :
Chris@1104 1238 m_normalization == ColumnNormalization::Hybrid ? "hybrid" : "none");
Chris@1099 1239
Chris@1099 1240 // Old-style normalization attribute, for backward compatibility
Chris@1099 1241
Chris@1099 1242 s += QString("normalizeColumns=\"%1\" ")
Chris@1266 1243 .arg(m_normalization == ColumnNormalization::Range01 ? "true" : "false");
Chris@1099 1244
Chris@1099 1245 // And this applies to both old- and new-style attributes
Chris@1099 1246
Chris@1099 1247 s += QString("normalizeVisibleArea=\"%1\" ")
Chris@1104 1248 .arg(m_normalizeVisibleArea ? "true" : "false");
Chris@1099 1249
Chris@316 1250 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@197 1251 }
Chris@197 1252
Chris@197 1253 void
Chris@197 1254 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
Chris@197 1255 {
Chris@445 1256 bool ok = false, alsoOk = false;
Chris@197 1257
Chris@1105 1258 ColourScaleType colourScale = convertToColourScale
Chris@1252 1259 (attributes.value("scale").toInt(&ok));
Chris@1099 1260 if (ok) setColourScale(colourScale);
Chris@197 1261
Chris@1362 1262 QString colourMapId = attributes.value("colourMap");
Chris@1362 1263 int colourMap = ColourMapper::getColourMapById(colourMapId);
Chris@1362 1264 if (colourMap >= 0) {
Chris@1362 1265 setColourMap(colourMap);
Chris@1362 1266 } else {
Chris@1362 1267 colourMap = attributes.value("colourScheme").toInt(&ok);
Chris@1362 1268 if (ok && colourMap < ColourMapper::getColourMapCount()) {
Chris@1362 1269 setColourMap(colourMap);
Chris@1362 1270 }
Chris@1362 1271 }
Chris@197 1272
Chris@1103 1273 BinScale binScale = (BinScale)
Chris@1266 1274 attributes.value("binScale").toInt(&ok);
Chris@1099 1275 if (ok) setBinScale(binScale);
Chris@445 1276
Chris@465 1277 bool invertVertical =
Chris@465 1278 (attributes.value("invertVertical").trimmed() == "true");
Chris@465 1279 setInvertVertical(invertVertical);
Chris@465 1280
Chris@465 1281 bool opaque =
Chris@465 1282 (attributes.value("opaque").trimmed() == "true");
Chris@535 1283 setOpaque(opaque);
Chris@535 1284
Chris@535 1285 bool smooth =
Chris@535 1286 (attributes.value("smooth").trimmed() == "true");
Chris@535 1287 setSmooth(smooth);
Chris@465 1288
Chris@536 1289 float gain = attributes.value("gain").toFloat(&ok);
Chris@536 1290 if (ok) setGain(gain);
Chris@536 1291
Chris@445 1292 float min = attributes.value("minY").toFloat(&ok);
Chris@445 1293 float max = attributes.value("maxY").toFloat(&alsoOk);
Chris@445 1294 if (ok && alsoOk) setDisplayExtents(min, max);
Chris@1099 1295
Chris@1099 1296 bool haveNewStyleNormalization = false;
Chris@1099 1297
Chris@1099 1298 QString columnNormalization = attributes.value("columnNormalization");
Chris@1099 1299
Chris@1099 1300 if (columnNormalization != "") {
Chris@1099 1301
Chris@1099 1302 haveNewStyleNormalization = true;
Chris@1099 1303
Chris@1099 1304 if (columnNormalization == "peak") {
Chris@1245 1305 setNormalization(ColumnNormalization::Range01);
Chris@1099 1306 } else if (columnNormalization == "hybrid") {
Chris@1104 1307 setNormalization(ColumnNormalization::Hybrid);
Chris@1099 1308 } else if (columnNormalization == "none") {
Chris@1104 1309 setNormalization(ColumnNormalization::None);
Chris@1099 1310 } else {
Chris@1412 1311 SVCERR << "NOTE: Unknown or unsupported columnNormalization attribute \""
Chris@1412 1312 << columnNormalization << "\"" << endl;
Chris@1099 1313 }
Chris@1099 1314 }
Chris@1099 1315
Chris@1099 1316 if (!haveNewStyleNormalization) {
Chris@1099 1317
Chris@1104 1318 setNormalization(ColumnNormalization::None);
Chris@1104 1319
Chris@1099 1320 bool normalizeColumns =
Chris@1099 1321 (attributes.value("normalizeColumns").trimmed() == "true");
Chris@1099 1322 if (normalizeColumns) {
Chris@1245 1323 setNormalization(ColumnNormalization::Range01);
Chris@1099 1324 }
Chris@1099 1325
Chris@1099 1326 bool normalizeHybrid =
Chris@1099 1327 (attributes.value("normalizeHybrid").trimmed() == "true");
Chris@1099 1328 if (normalizeHybrid) {
Chris@1104 1329 setNormalization(ColumnNormalization::Hybrid);
Chris@1099 1330 }
Chris@1099 1331 }
Chris@1099 1332
Chris@1099 1333 bool normalizeVisibleArea =
Chris@1099 1334 (attributes.value("normalizeVisibleArea").trimmed() == "true");
Chris@1104 1335 setNormalizeVisibleArea(normalizeVisibleArea);
Chris@1099 1336
Chris@1099 1337 //!!! todo: check save/reload scaling, compare with
Chris@1099 1338 //!!! SpectrogramLayer, compare with prior SV versions, compare
Chris@1099 1339 //!!! with Tony v1 and v2 and their save files
Chris@197 1340 }
Chris@197 1341