annotate layer/Colour3DPlotLayer.cpp @ 1269:f2894944c6b8

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