annotate layer/Colour3DPlotLayer.cpp @ 1469:11a150e65ee1 by-id

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