annotate layer/Colour3DPlotLayer.cpp @ 1238:4d0ca1ab4cd0

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