annotate layer/Colour3DPlotLayer.cpp @ 1221:eaab8bab3522

Measure time taken to render per pixel, and use the time last time around to decide whether to be time constrained this time around
author Chris Cannam
date Thu, 26 Jan 2017 11:55:11 +0000
parents 2954e9952b78
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