annotate layer/Colour3DPlotLayer.cpp @ 1481:e540aa5d89cd by-id

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