annotate layer/Colour3DPlotLayer.cpp @ 1135:628cd329c241 spectrogram-minor-refactor

Use a count of bins rather than min and max bins (because the name maxbin tells us nothing about whether the range is inclusive or not)
author Chris Cannam
date Wed, 03 Aug 2016 14:20:27 +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