annotate layer/Colour3DPlotLayer.cpp @ 1284:51e6125627fa

Hack to ensure vertical scale lines are in the right place in pixel-doubling rendering
author Chris Cannam
date Tue, 08 May 2018 14:27:54 +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