annotate layer/Colour3DPlotLayer.cpp @ 1136:9ff838a64461 spectrogram-minor-refactor

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