annotate layer/Colour3DPlotLayer.cpp @ 1204:d421df27e184 3.0-integration

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