annotate layer/Colour3DPlotLayer.cpp @ 1107:6d720fe1c8cc spectrogram-minor-refactor

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