annotate layer/Colour3DPlotLayer.cpp @ 1363:bbeffb29bf09

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