annotate layer/Colour3DPlotLayer.cpp @ 1245:f0e291fa7b9c

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