annotate layer/Colour3DPlotLayer.cpp @ 1216:dc2af6616c83

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