annotate layer/Colour3DPlotLayer.cpp @ 1226:6f0d7aa25816

Scale pen used for centre line
author Chris Cannam
date Thu, 26 Jan 2017 21:16:37 +0000
parents eaab8bab3522
children dd3901fe8623
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@1220 764 // Arrange that the first bin (mn) appears as the exact result
Chris@1220 765 // for the first pixel (which is pixel h-1) and the first
Chris@1220 766 // out-of-range bin (mx) would appear as the exact result for
Chris@1220 767 // the first out-of-range pixel (which would be pixel -1)
Chris@1220 768 bin = mn + ((h - y - 1) * (mx - mn)) / h;
Chris@532 769 } else {
Chris@904 770 double logmin = mn + 1, logmax = mx + 1;
Chris@532 771 LogRange::mapRange(logmin, logmax);
Chris@1220 772 bin = LogRange::unmap(logmin + ((h - y - 1) * (logmax - logmin)) / h) - 1;
Chris@532 773 }
Chris@532 774 return bin;
Chris@532 775 }
Chris@532 776
Chris@25 777 QString
Chris@916 778 Colour3DPlotLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
Chris@25 779 {
Chris@25 780 if (!m_model) return "";
Chris@25 781
Chris@25 782 int x = pos.x();
Chris@25 783 int y = pos.y();
Chris@25 784
Chris@902 785 sv_frame_t modelStart = m_model->getStartFrame();
Chris@805 786 int modelResolution = m_model->getResolution();
Chris@25 787
Chris@902 788 double srRatio =
Chris@902 789 v->getViewManager()->getMainModelSampleRate() /
Chris@902 790 m_model->getSampleRate();
Chris@159 791
Chris@902 792 int sx0 = int((double(v->getFrameForX(x)) / srRatio - double(modelStart)) /
Chris@812 793 modelResolution);
Chris@25 794
Chris@160 795 int f0 = sx0 * modelResolution;
Chris@160 796 int f1 = f0 + modelResolution;
Chris@160 797
Chris@447 798 int sh = m_model->getHeight();
Chris@447 799
Chris@447 800 int symin = m_miny;
Chris@447 801 int symax = m_maxy;
Chris@447 802 if (symax <= symin) {
Chris@447 803 symin = 0;
Chris@447 804 symax = sh;
Chris@447 805 }
Chris@447 806 if (symin < 0) symin = 0;
Chris@447 807 if (symax > sh) symax = sh;
Chris@447 808
Chris@916 809 // double binHeight = double(v->getPaintHeight()) / (symax - symin);
Chris@916 810 // int sy = int((v->getPaintHeight() - y) / binHeight) + symin;
Chris@534 811
Chris@903 812 int sy = getIBinForY(v, y);
Chris@25 813
Chris@812 814 if (sy < 0 || sy >= m_model->getHeight()) {
Chris@812 815 return "";
Chris@812 816 }
Chris@812 817
Chris@357 818 if (m_invertVertical) sy = m_model->getHeight() - sy - 1;
Chris@357 819
Chris@160 820 float value = m_model->getValueAt(sx0, sy);
Chris@159 821
Chris@682 822 // cerr << "bin value (" << sx0 << "," << sy << ") is " << value << endl;
Chris@25 823
Chris@25 824 QString binName = m_model->getBinName(sy);
Chris@25 825 if (binName == "") binName = QString("[%1]").arg(sy + 1);
Chris@25 826 else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
Chris@25 827
Chris@25 828 QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
Chris@160 829 .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
Chris@25 830 .toText(true).c_str())
Chris@160 831 .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
Chris@25 832 .toText(true).c_str())
Chris@25 833 .arg(binName)
Chris@25 834 .arg(value);
Chris@25 835
Chris@25 836 return text;
Chris@25 837 }
Chris@25 838
Chris@25 839 int
Chris@969 840 Colour3DPlotLayer::getColourScaleWidth(QPainter &p) const
Chris@159 841 {
Chris@969 842 // Font is rotated
Chris@969 843 int cw = p.fontMetrics().height();
Chris@159 844 return cw;
Chris@159 845 }
Chris@159 846
Chris@159 847 int
Chris@916 848 Colour3DPlotLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const
Chris@25 849 {
Chris@25 850 if (!m_model) return 0;
Chris@25 851
Chris@160 852 QString sampleText = QString("[%1]").arg(m_model->getHeight());
Chris@25 853 int tw = paint.fontMetrics().width(sampleText);
Chris@98 854 bool another = false;
Chris@25 855
Chris@805 856 for (int i = 0; i < m_model->getHeight(); ++i) {
Chris@25 857 if (m_model->getBinName(i).length() > sampleText.length()) {
Chris@25 858 sampleText = m_model->getBinName(i);
Chris@98 859 another = true;
Chris@25 860 }
Chris@25 861 }
Chris@98 862 if (another) {
Chris@25 863 tw = std::max(tw, paint.fontMetrics().width(sampleText));
Chris@25 864 }
Chris@25 865
Chris@159 866 return tw + 13 + getColourScaleWidth(paint);
Chris@25 867 }
Chris@25 868
Chris@25 869 void
Chris@916 870 Colour3DPlotLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const
Chris@25 871 {
Chris@25 872 if (!m_model) return;
Chris@25 873
Chris@25 874 int h = rect.height(), w = rect.width();
Chris@25 875
Chris@159 876 int cw = getColourScaleWidth(paint);
Chris@159 877
Chris@159 878 int ch = h - 20;
Chris@1107 879 if (ch > 20) {
Chris@159 880
Chris@1131 881 double min = m_viewMags[v->getId()].getMin();
Chris@1131 882 double max = m_viewMags[v->getId()].getMax();
Chris@447 883
Chris@1131 884 if (max <= min) max = min + 0.1;
Chris@447 885
Chris@287 886 paint.setPen(v->getForeground());
Chris@447 887 paint.drawRect(4, 10, cw - 8, ch+1);
Chris@159 888
Chris@446 889 for (int y = 0; y < ch; ++y) {
Chris@904 890 double value = ((max - min) * (double(ch-y) - 1.0)) / double(ch) + min;
Chris@1131 891 paint.setPen(getRenderer(v)->getColour(value));
Chris@1131 892 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
Chris@159 893 }
Chris@446 894
Chris@446 895 QString minstr = QString("%1").arg(min);
Chris@446 896 QString maxstr = QString("%1").arg(max);
Chris@446 897
Chris@446 898 paint.save();
Chris@446 899
Chris@446 900 QFont font = paint.font();
Chris@1053 901 if (font.pixelSize() > 0) {
Chris@1053 902 int newSize = int(font.pixelSize() * 0.65);
Chris@1053 903 if (newSize < 6) newSize = 6;
Chris@1053 904 font.setPixelSize(newSize);
Chris@1053 905 paint.setFont(font);
Chris@1053 906 }
Chris@446 907
Chris@446 908 int msw = paint.fontMetrics().width(maxstr);
Chris@446 909
Chris@446 910 QMatrix m;
Chris@446 911 m.translate(cw - 6, ch + 10);
Chris@446 912 m.rotate(-90);
Chris@446 913
Chris@446 914 paint.setWorldMatrix(m);
Chris@446 915
Chris@1078 916 PaintAssistant::drawVisibleText(v, paint, 2, 0, minstr, PaintAssistant::OutlinedText);
Chris@446 917
Chris@446 918 m.translate(ch - msw - 2, 0);
Chris@446 919 paint.setWorldMatrix(m);
Chris@446 920
Chris@1078 921 PaintAssistant::drawVisibleText(v, paint, 0, 0, maxstr, PaintAssistant::OutlinedText);
Chris@446 922
Chris@446 923 paint.restore();
Chris@159 924 }
Chris@159 925
Chris@287 926 paint.setPen(v->getForeground());
Chris@159 927
Chris@445 928 int sh = m_model->getHeight();
Chris@445 929
Chris@445 930 int symin = m_miny;
Chris@445 931 int symax = m_maxy;
Chris@445 932 if (symax <= symin) {
Chris@445 933 symin = 0;
Chris@445 934 symax = sh;
Chris@445 935 }
Chris@445 936 if (symin < 0) symin = 0;
Chris@445 937 if (symax > sh) symax = sh;
Chris@445 938
Chris@532 939 paint.save();
Chris@456 940
Chris@533 941 int py = h;
Chris@25 942
Chris@969 943 int defaultFontHeight = paint.fontMetrics().height();
Chris@969 944
Chris@805 945 for (int i = symin; i <= symax; ++i) {
Chris@98 946
Chris@532 947 int y0;
Chris@534 948
Chris@903 949 y0 = getIYForBin(v, i);
Chris@532 950 int h = py - y0;
Chris@532 951
Chris@532 952 if (i > symin) {
Chris@532 953 if (paint.fontMetrics().height() >= h) {
Chris@969 954 if (h >= defaultFontHeight * 0.8) {
Chris@532 955 QFont tf = paint.font();
Chris@973 956 tf.setPixelSize(int(h * 0.8));
Chris@532 957 paint.setFont(tf);
Chris@532 958 } else {
Chris@532 959 continue;
Chris@532 960 }
Chris@532 961 }
Chris@532 962 }
Chris@25 963
Chris@532 964 py = y0;
Chris@532 965
Chris@534 966 if (i < symax) {
Chris@534 967 paint.drawLine(cw, y0, w, y0);
Chris@534 968 }
Chris@25 969
Chris@532 970 if (i > symin) {
Chris@534 971
Chris@805 972 int idx = i - 1;
Chris@534 973 if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
Chris@534 974
Chris@534 975 QString text = m_model->getBinName(idx);
Chris@534 976 if (text == "") text = QString("[%1]").arg(idx + 1);
Chris@534 977
Chris@534 978 int ty = y0 + (h/2) - (paint.fontMetrics().height()/2) +
Chris@534 979 paint.fontMetrics().ascent() + 1;
Chris@534 980
Chris@534 981 paint.drawText(cw + 5, ty, text);
Chris@457 982 }
Chris@25 983 }
Chris@456 984
Chris@456 985 paint.restore();
Chris@25 986 }
Chris@25 987
Chris@467 988 DenseThreeDimensionalModel::Column
Chris@805 989 Colour3DPlotLayer::getColumn(int col) const
Chris@197 990 {
Chris@812 991 Profiler profiler("Colour3DPlotLayer::getColumn");
Chris@812 992
Chris@467 993 DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
Chris@1019 994 values.resize(m_model->getHeight(), 0.f);
Chris@1104 995 if (m_normalization != ColumnNormalization::Max1 &&
Chris@1104 996 m_normalization != ColumnNormalization::Hybrid) {
Chris@1099 997 return values;
Chris@1099 998 }
Chris@461 999
Chris@904 1000 double colMax = 0.f, colMin = 0.f;
Chris@904 1001 double min = 0.f, max = 0.f;
Chris@197 1002
Chris@1019 1003 int nv = int(values.size());
Chris@1019 1004
Chris@461 1005 min = m_model->getMinimumLevel();
Chris@461 1006 max = m_model->getMaximumLevel();
Chris@461 1007
Chris@1019 1008 for (int y = 0; y < nv; ++y) {
Chris@467 1009 if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
Chris@467 1010 if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
Chris@197 1011 }
Chris@461 1012 if (colMin == colMax) colMax = colMin + 1;
Chris@197 1013
Chris@1019 1014 for (int y = 0; y < nv; ++y) {
Chris@461 1015
Chris@904 1016 double value = values.at(y);
Chris@904 1017 double norm = (value - colMin) / (colMax - colMin);
Chris@904 1018 double newvalue = min + (max - min) * norm;
Chris@197 1019
Chris@904 1020 if (value != newvalue) values[y] = float(newvalue);
Chris@468 1021 }
Chris@468 1022
Chris@1104 1023 if (m_normalization == ColumnNormalization::Hybrid
Chris@1099 1024 && (colMax > 0.0)) {
Chris@904 1025 double logmax = log10(colMax);
Chris@1019 1026 for (int y = 0; y < nv; ++y) {
Chris@904 1027 values[y] = float(values[y] * logmax);
Chris@719 1028 }
Chris@719 1029 }
Chris@719 1030
Chris@468 1031 return values;
Chris@197 1032 }
Chris@1114 1033
Chris@1100 1034 Colour3DPlotRenderer *
Chris@1113 1035 Colour3DPlotLayer::getRenderer(const LayerGeometryProvider *v) const
Chris@1100 1036 {
Chris@1100 1037 if (m_renderers.find(v->getId()) == m_renderers.end()) {
Chris@1100 1038
Chris@1100 1039 Colour3DPlotRenderer::Sources sources;
Chris@1100 1040 sources.verticalBinLayer = this;
Chris@1100 1041 sources.fft = 0;
Chris@1100 1042 sources.source = m_model;
Chris@1212 1043 sources.peakCaches.push_back(getPeakCache());
Chris@1100 1044
Chris@1100 1045 ColourScale::Parameters cparams;
Chris@1100 1046 cparams.colourMap = m_colourMap;
Chris@1137 1047 cparams.scaleType = m_colourScale;
Chris@1100 1048 cparams.gain = m_gain;
Chris@1100 1049
Chris@1131 1050 if (m_normalization == ColumnNormalization::None) {
Chris@1131 1051 cparams.minValue = m_model->getMinimumLevel();
Chris@1131 1052 cparams.maxValue = m_model->getMaximumLevel();
Chris@1131 1053 } else if (m_normalization == ColumnNormalization::Hybrid) {
Chris@1131 1054 cparams.minValue = 0;
Chris@1131 1055 cparams.maxValue = log10(m_model->getMaximumLevel() + 1.0);
Chris@1131 1056 }
Chris@1131 1057
Chris@1131 1058 if (cparams.maxValue <= cparams.minValue) {
Chris@1131 1059 cparams.maxValue = cparams.minValue + 0.1;
Chris@1131 1060 }
Chris@1131 1061
Chris@1100 1062 Colour3DPlotRenderer::Parameters params;
Chris@1100 1063 params.colourScale = ColourScale(cparams);
Chris@1100 1064 params.normalization = m_normalization;
Chris@1100 1065 params.binScale = m_binScale;
Chris@1100 1066 params.alwaysOpaque = m_opaque;
Chris@1100 1067 params.invertVertical = m_invertVertical;
Chris@1100 1068 params.interpolate = m_smooth;
Chris@1100 1069
Chris@1100 1070 m_renderers[v->getId()] = new Colour3DPlotRenderer(sources, params);
Chris@1100 1071 }
Chris@1100 1072
Chris@1100 1073 return m_renderers[v->getId()];
Chris@1100 1074 }
Chris@1100 1075
Chris@197 1076 void
Chris@1107 1077 Colour3DPlotLayer::paintWithRenderer(LayerGeometryProvider *v,
Chris@1107 1078 QPainter &paint, QRect rect) const
Chris@1101 1079 {
Chris@1101 1080 Colour3DPlotRenderer *renderer = getRenderer(v);
Chris@1101 1081
Chris@1121 1082 Colour3DPlotRenderer::RenderResult result;
Chris@1123 1083 MagnitudeRange magRange;
Chris@1123 1084 int viewId = v->getId();
Chris@1123 1085
Chris@1123 1086 if (!renderer->geometryChanged(v)) {
Chris@1123 1087 magRange = m_viewMags[viewId];
Chris@1123 1088 }
Chris@1121 1089
Chris@1101 1090 if (m_synchronous) {
Chris@1121 1091
Chris@1121 1092 result = renderer->render(v, paint, rect);
Chris@1121 1093
Chris@1121 1094 } else {
Chris@1121 1095
Chris@1121 1096 result = renderer->renderTimeConstrained(v, paint, rect);
Chris@1121 1097
Chris@1121 1098 QRect uncached = renderer->getLargestUncachedRect(v);
Chris@1121 1099 if (uncached.width() > 0) {
Chris@1121 1100 v->updatePaintRect(uncached);
Chris@1121 1101 }
Chris@1101 1102 }
Chris@1121 1103
Chris@1123 1104 magRange.sample(result.range);
Chris@1101 1105
Chris@1123 1106 if (magRange.isSet()) {
Chris@1123 1107 if (!(m_viewMags[viewId] == magRange)) {
Chris@1123 1108 m_viewMags[viewId] = magRange;
Chris@1123 1109 //!!! now need to do the normalise-visible thing
Chris@1123 1110 }
Chris@1123 1111 }
Chris@1101 1112
Chris@1221 1113 SVDEBUG << "Colour3DPlotRenderer::paintWithRenderer: mag range in this view: "
Chris@1221 1114 << m_viewMags[v->getId()].getMin()
Chris@1221 1115 << " -> "
Chris@1221 1116 << m_viewMags[v->getId()].getMax()
Chris@1221 1117 << endl;
Chris@1101 1118 }
Chris@1101 1119
Chris@1101 1120 void
Chris@916 1121 Colour3DPlotLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@0 1122 {
Chris@514 1123 /*
Chris@443 1124 if (m_model) {
Chris@587 1125 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
Chris@443 1126 }
Chris@514 1127 */
Chris@466 1128 Profiler profiler("Colour3DPlotLayer::paint");
Chris@125 1129 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1130 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 1131 #endif
Chris@0 1132
Chris@0 1133 int completion = 0;
Chris@0 1134 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
Chris@0 1135 if (completion > 0) {
Chris@916 1136 paint.fillRect(0, 10, v->getPaintWidth() * completion / 100,
Chris@0 1137 10, QColor(120, 120, 120));
Chris@0 1138 }
Chris@0 1139 return;
Chris@0 1140 }
Chris@0 1141
Chris@1053 1142 if (m_model->getWidth() == 0) {
Chris@1053 1143 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@1053 1144 cerr << "Colour3DPlotLayer::paint(): model width == 0, "
Chris@1053 1145 << "nothing to paint (yet)" << endl;
Chris@1053 1146 #endif
Chris@1053 1147 return;
Chris@1053 1148 }
Chris@1101 1149
Chris@1101 1150 //!!!???
Chris@1053 1151
Chris@1104 1152 if (m_normalizeVisibleArea) {
Chris@1099 1153 rect = v->getPaintRect();
Chris@1099 1154 }
Chris@197 1155
Chris@1107 1156 //!!! why is the setLayerDormant(false) found here in
Chris@1107 1157 //!!! SpectrogramLayer not present in Colour3DPlotLayer?
Chris@1107 1158 //!!! unnecessary? vestigial? forgotten?
Chris@1107 1159
Chris@1107 1160 paintWithRenderer(v, paint, rect);
Chris@1107 1161 }
Chris@1107 1162
Chris@28 1163 bool
Chris@916 1164 Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@805 1165 int &resolution,
Chris@28 1166 SnapType snap) const
Chris@24 1167 {
Chris@24 1168 if (!m_model) {
Chris@44 1169 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@24 1170 }
Chris@24 1171
Chris@130 1172 resolution = m_model->getResolution();
Chris@904 1173 sv_frame_t left = (frame / resolution) * resolution;
Chris@904 1174 sv_frame_t right = left + resolution;
Chris@28 1175
Chris@28 1176 switch (snap) {
Chris@28 1177 case SnapLeft: frame = left; break;
Chris@28 1178 case SnapRight: frame = right; break;
Chris@28 1179 case SnapNearest:
Chris@28 1180 case SnapNeighbouring:
Chris@28 1181 if (frame - left > right - frame) frame = right;
Chris@28 1182 else frame = left;
Chris@28 1183 break;
Chris@28 1184 }
Chris@24 1185
Chris@28 1186 return true;
Chris@24 1187 }
Chris@24 1188
Chris@316 1189 void
Chris@316 1190 Colour3DPlotLayer::toXml(QTextStream &stream,
Chris@316 1191 QString indent, QString extraAttributes) const
Chris@197 1192 {
Chris@316 1193 QString s = QString("scale=\"%1\" "
Chris@316 1194 "colourScheme=\"%2\" "
Chris@1099 1195 "minY=\"%3\" "
Chris@1099 1196 "maxY=\"%4\" "
Chris@1099 1197 "invertVertical=\"%5\" "
Chris@1099 1198 "opaque=\"%6\" %7")
Chris@1104 1199 .arg(convertFromColourScale(m_colourScale))
Chris@197 1200 .arg(m_colourMap)
Chris@445 1201 .arg(m_miny)
Chris@465 1202 .arg(m_maxy)
Chris@465 1203 .arg(m_invertVertical ? "true" : "false")
Chris@534 1204 .arg(m_opaque ? "true" : "false")
Chris@536 1205 .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
Chris@1103 1206 .arg(int(m_binScale))
Chris@536 1207 .arg(m_smooth ? "true" : "false")
Chris@536 1208 .arg(m_gain));
Chris@535 1209
Chris@1099 1210 // New-style normalization attributes, allowing for more types of
Chris@1099 1211 // normalization in future: write out the column normalization
Chris@1099 1212 // type separately, and then whether we are normalizing visible
Chris@1099 1213 // area as well afterwards
Chris@1099 1214
Chris@1099 1215 s += QString("columnNormalization=\"%1\" ")
Chris@1104 1216 .arg(m_normalization == ColumnNormalization::Max1 ? "peak" :
Chris@1104 1217 m_normalization == ColumnNormalization::Hybrid ? "hybrid" : "none");
Chris@1099 1218
Chris@1099 1219 // Old-style normalization attribute, for backward compatibility
Chris@1099 1220
Chris@1099 1221 s += QString("normalizeColumns=\"%1\" ")
Chris@1104 1222 .arg(m_normalization == ColumnNormalization::Max1 ? "true" : "false");
Chris@1099 1223
Chris@1099 1224 // And this applies to both old- and new-style attributes
Chris@1099 1225
Chris@1099 1226 s += QString("normalizeVisibleArea=\"%1\" ")
Chris@1104 1227 .arg(m_normalizeVisibleArea ? "true" : "false");
Chris@1099 1228
Chris@316 1229 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@197 1230 }
Chris@197 1231
Chris@197 1232 void
Chris@197 1233 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
Chris@197 1234 {
Chris@445 1235 bool ok = false, alsoOk = false;
Chris@197 1236
Chris@1105 1237 ColourScaleType colourScale = convertToColourScale
Chris@1099 1238 (attributes.value("colourScale").toInt(&ok));
Chris@1099 1239 if (ok) setColourScale(colourScale);
Chris@197 1240
Chris@197 1241 int colourMap = attributes.value("colourScheme").toInt(&ok);
Chris@197 1242 if (ok) setColourMap(colourMap);
Chris@197 1243
Chris@1103 1244 BinScale binScale = (BinScale)
Chris@1099 1245 attributes.value("binScale").toInt(&ok);
Chris@1099 1246 if (ok) setBinScale(binScale);
Chris@445 1247
Chris@465 1248 bool invertVertical =
Chris@465 1249 (attributes.value("invertVertical").trimmed() == "true");
Chris@465 1250 setInvertVertical(invertVertical);
Chris@465 1251
Chris@465 1252 bool opaque =
Chris@465 1253 (attributes.value("opaque").trimmed() == "true");
Chris@535 1254 setOpaque(opaque);
Chris@535 1255
Chris@535 1256 bool smooth =
Chris@535 1257 (attributes.value("smooth").trimmed() == "true");
Chris@535 1258 setSmooth(smooth);
Chris@465 1259
Chris@536 1260 float gain = attributes.value("gain").toFloat(&ok);
Chris@536 1261 if (ok) setGain(gain);
Chris@536 1262
Chris@445 1263 float min = attributes.value("minY").toFloat(&ok);
Chris@445 1264 float max = attributes.value("maxY").toFloat(&alsoOk);
Chris@445 1265 if (ok && alsoOk) setDisplayExtents(min, max);
Chris@1099 1266
Chris@1099 1267 bool haveNewStyleNormalization = false;
Chris@1099 1268
Chris@1099 1269 QString columnNormalization = attributes.value("columnNormalization");
Chris@1099 1270
Chris@1099 1271 if (columnNormalization != "") {
Chris@1099 1272
Chris@1099 1273 haveNewStyleNormalization = true;
Chris@1099 1274
Chris@1099 1275 if (columnNormalization == "peak") {
Chris@1104 1276 setNormalization(ColumnNormalization::Max1);
Chris@1099 1277 } else if (columnNormalization == "hybrid") {
Chris@1104 1278 setNormalization(ColumnNormalization::Hybrid);
Chris@1099 1279 } else if (columnNormalization == "none") {
Chris@1104 1280 setNormalization(ColumnNormalization::None);
Chris@1099 1281 } else {
Chris@1099 1282 cerr << "NOTE: Unknown or unsupported columnNormalization attribute \""
Chris@1099 1283 << columnNormalization << "\"" << endl;
Chris@1099 1284 }
Chris@1099 1285 }
Chris@1099 1286
Chris@1099 1287 if (!haveNewStyleNormalization) {
Chris@1099 1288
Chris@1104 1289 setNormalization(ColumnNormalization::None);
Chris@1104 1290
Chris@1099 1291 bool normalizeColumns =
Chris@1099 1292 (attributes.value("normalizeColumns").trimmed() == "true");
Chris@1099 1293 if (normalizeColumns) {
Chris@1104 1294 setNormalization(ColumnNormalization::Max1);
Chris@1099 1295 }
Chris@1099 1296
Chris@1099 1297 bool normalizeHybrid =
Chris@1099 1298 (attributes.value("normalizeHybrid").trimmed() == "true");
Chris@1099 1299 if (normalizeHybrid) {
Chris@1104 1300 setNormalization(ColumnNormalization::Hybrid);
Chris@1099 1301 }
Chris@1099 1302 }
Chris@1099 1303
Chris@1099 1304 bool normalizeVisibleArea =
Chris@1099 1305 (attributes.value("normalizeVisibleArea").trimmed() == "true");
Chris@1104 1306 setNormalizeVisibleArea(normalizeVisibleArea);
Chris@1099 1307
Chris@1099 1308 //!!! todo: check save/reload scaling, compare with
Chris@1099 1309 //!!! SpectrogramLayer, compare with prior SV versions, compare
Chris@1099 1310 //!!! with Tony v1 and v2 and their save files
Chris@197 1311 }
Chris@197 1312