annotate layer/Colour3DPlotLayer.cpp @ 1101:1364cbf4453d spectrogram-minor-refactor

Begin using renderer in colour 3d plot layer
author Chris Cannam
date Wed, 13 Jul 2016 13:30:39 +0100
parents 102f986ec032
children 36a981a0fa31
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@159 51 m_cache(0),
Chris@469 52 m_peaksCache(0),
Chris@461 53 m_cacheValidStart(0),
Chris@461 54 m_cacheValidEnd(0),
Chris@1099 55 m_colourScale(ColourScale::LinearColourScale),
Chris@461 56 m_colourScaleSet(false),
Chris@197 57 m_colourMap(0),
Chris@534 58 m_gain(1.0),
Chris@1099 59 m_binScale(Colour3DPlotRenderer::LinearBinScale),
Chris@1099 60 m_normalization(ColumnOp::NoNormalization),
Chris@444 61 m_invertVertical(false),
Chris@465 62 m_opaque(false),
Chris@535 63 m_smooth(false),
Chris@805 64 m_peakResolution(256),
Chris@444 65 m_miny(0),
Chris@1100 66 m_maxy(0),
Chris@1101 67 m_synchronous(false),
Chris@1100 68 m_peakCache(0),
Chris@1100 69 m_peakCacheDivisor(8)
Chris@0 70 {
Chris@1018 71 QSettings settings;
Chris@1018 72 settings.beginGroup("Preferences");
Chris@1018 73 setColourMap(settings.value("colour-3d-plot-colour", ColourMapper::Green).toInt());
Chris@1018 74 settings.endGroup();
Chris@0 75 }
Chris@0 76
Chris@0 77 Colour3DPlotLayer::~Colour3DPlotLayer()
Chris@0 78 {
Chris@461 79 delete m_cache;
Chris@1100 80 delete m_peaksCache; //!!! this one is to go...
Chris@1100 81 delete m_peakCache;
Chris@0 82 }
Chris@0 83
Chris@0 84 void
Chris@1101 85 Colour3DPlotLayer::setSynchronousPainting(bool synchronous)
Chris@1101 86 {
Chris@1101 87 m_synchronous = synchronous;
Chris@1101 88 }
Chris@1101 89
Chris@1101 90 void
Chris@0 91 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
Chris@0 92 {
Chris@193 93 if (m_model == model) return;
Chris@193 94 const DenseThreeDimensionalModel *oldModel = m_model;
Chris@0 95 m_model = model;
Chris@0 96 if (!m_model || !m_model->isOK()) return;
Chris@0 97
Chris@320 98 connectSignals(m_model);
Chris@0 99
Chris@461 100 connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
Chris@908 101 connect(m_model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@908 102 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
Chris@0 103
Chris@474 104 m_peakResolution = 256;
Chris@474 105 if (model->getResolution() > 512) {
Chris@474 106 m_peakResolution = 16;
Chris@474 107 } else if (model->getResolution() > 128) {
Chris@474 108 m_peakResolution = 64;
Chris@474 109 } else if (model->getResolution() > 2) {
Chris@474 110 m_peakResolution = 128;
Chris@474 111 }
Chris@1100 112
Chris@1100 113 delete m_peakCache;
Chris@1100 114 m_peakCache = 0;
Chris@1100 115
Chris@474 116 cacheInvalid();
Chris@474 117
Chris@0 118 emit modelReplaced();
Chris@193 119 emit sliceableModelReplaced(oldModel, model);
Chris@0 120 }
Chris@0 121
Chris@0 122 void
Chris@0 123 Colour3DPlotLayer::cacheInvalid()
Chris@0 124 {
Chris@1100 125 //!!! to go
Chris@1100 126
Chris@469 127 delete m_cache;
Chris@469 128 delete m_peaksCache;
Chris@0 129 m_cache = 0;
Chris@469 130 m_peaksCache = 0;
Chris@461 131 m_cacheValidStart = 0;
Chris@461 132 m_cacheValidEnd = 0;
Chris@0 133 }
Chris@0 134
Chris@0 135 void
Chris@908 136 Colour3DPlotLayer::cacheInvalid(sv_frame_t startFrame, sv_frame_t endFrame)
Chris@0 137 {
Chris@1100 138 //!!! to go
Chris@1100 139
Chris@843 140 if (!m_cache || !m_model) return;
Chris@461 141
Chris@805 142 int modelResolution = m_model->getResolution();
Chris@908 143 int start = int(startFrame / modelResolution);
Chris@908 144 int end = int(endFrame / modelResolution + 1);
Chris@461 145 if (m_cacheValidStart < end) m_cacheValidStart = end;
Chris@461 146 if (m_cacheValidEnd > start) m_cacheValidEnd = start;
Chris@461 147 if (m_cacheValidStart > m_cacheValidEnd) m_cacheValidEnd = m_cacheValidStart;
Chris@461 148 }
Chris@461 149
Chris@1100 150 Dense3DModelPeakCache *
Chris@1100 151 Colour3DPlotLayer::getPeakCache() const
Chris@1100 152 {
Chris@1100 153 if (!m_peakCache) {
Chris@1100 154 m_peakCache = new Dense3DModelPeakCache(m_model, m_peakCacheDivisor);
Chris@1100 155 }
Chris@1100 156 return m_peakCache;
Chris@1100 157 }
Chris@1100 158
Chris@461 159 void
Chris@461 160 Colour3DPlotLayer::modelChanged()
Chris@461 161 {
Chris@1099 162 if (!m_colourScaleSet && m_colourScale == ColourScale::LinearColourScale) {
Chris@461 163 if (m_model) {
Chris@461 164 if (m_model->shouldUseLogValueScale()) {
Chris@1099 165 setColourScale(ColourScale::LogColourScale);
Chris@461 166 } else {
Chris@461 167 m_colourScaleSet = true;
Chris@461 168 }
Chris@461 169 }
Chris@461 170 }
Chris@0 171 cacheInvalid();
Chris@0 172 }
Chris@0 173
Chris@461 174 void
Chris@908 175 Colour3DPlotLayer::modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame)
Chris@461 176 {
Chris@1099 177 if (!m_colourScaleSet && m_colourScale == ColourScale::LinearColourScale) {
Chris@461 178 if (m_model && m_model->getWidth() > 50) {
Chris@461 179 if (m_model->shouldUseLogValueScale()) {
Chris@1099 180 setColourScale(ColourScale::LogColourScale);
Chris@461 181 } else {
Chris@461 182 m_colourScaleSet = true;
Chris@461 183 }
Chris@461 184 }
Chris@461 185 }
Chris@461 186 cacheInvalid(startFrame, endFrame);
Chris@461 187 }
Chris@461 188
Chris@159 189 Layer::PropertyList
Chris@159 190 Colour3DPlotLayer::getProperties() const
Chris@159 191 {
Chris@159 192 PropertyList list;
Chris@197 193 list.push_back("Colour");
Chris@159 194 list.push_back("Colour Scale");
Chris@197 195 list.push_back("Normalize Columns");
Chris@197 196 list.push_back("Normalize Visible Area");
Chris@534 197 list.push_back("Gain");
Chris@531 198 list.push_back("Bin Scale");
Chris@357 199 list.push_back("Invert Vertical Scale");
Chris@465 200 list.push_back("Opaque");
Chris@535 201 list.push_back("Smooth");
Chris@159 202 return list;
Chris@159 203 }
Chris@159 204
Chris@159 205 QString
Chris@159 206 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
Chris@159 207 {
Chris@197 208 if (name == "Colour") return tr("Colour");
Chris@197 209 if (name == "Colour Scale") return tr("Scale");
Chris@197 210 if (name == "Normalize Columns") return tr("Normalize Columns");
Chris@197 211 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
Chris@357 212 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
Chris@534 213 if (name == "Gain") return tr("Gain");
Chris@465 214 if (name == "Opaque") return tr("Always Opaque");
Chris@535 215 if (name == "Smooth") return tr("Smooth");
Chris@531 216 if (name == "Bin Scale") return tr("Bin Scale");
Chris@159 217 return "";
Chris@159 218 }
Chris@159 219
Chris@346 220 QString
Chris@346 221 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
Chris@346 222 {
Chris@346 223 if (name == "Normalize Columns") return "normalise-columns";
Chris@346 224 if (name == "Normalize Visible Area") return "normalise";
Chris@357 225 if (name == "Invert Vertical Scale") return "invert-vertical";
Chris@465 226 if (name == "Opaque") return "opaque";
Chris@535 227 if (name == "Smooth") return "smooth";
Chris@346 228 return "";
Chris@346 229 }
Chris@346 230
Chris@159 231 Layer::PropertyType
Chris@159 232 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
Chris@159 233 {
Chris@534 234 if (name == "Gain") return RangeProperty;
Chris@197 235 if (name == "Normalize Columns") return ToggleProperty;
Chris@197 236 if (name == "Normalize Visible Area") return ToggleProperty;
Chris@357 237 if (name == "Invert Vertical Scale") return ToggleProperty;
Chris@465 238 if (name == "Opaque") return ToggleProperty;
Chris@535 239 if (name == "Smooth") return ToggleProperty;
Chris@159 240 return ValueProperty;
Chris@159 241 }
Chris@159 242
Chris@159 243 QString
Chris@159 244 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
Chris@159 245 {
Chris@197 246 if (name == "Normalize Columns" ||
Chris@197 247 name == "Normalize Visible Area" ||
Chris@534 248 name == "Colour Scale" ||
Chris@534 249 name == "Gain") return tr("Scale");
Chris@531 250 if (name == "Bin Scale" ||
Chris@531 251 name == "Invert Vertical Scale") return tr("Bins");
Chris@465 252 if (name == "Opaque" ||
Chris@535 253 name == "Smooth" ||
Chris@465 254 name == "Colour") return tr("Colour");
Chris@159 255 return QString();
Chris@159 256 }
Chris@159 257
Chris@159 258 int
Chris@159 259 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@216 260 int *min, int *max, int *deflt) const
Chris@159 261 {
Chris@216 262 int val = 0;
Chris@159 263
Chris@216 264 int garbage0, garbage1, garbage2;
Chris@159 265 if (!min) min = &garbage0;
Chris@159 266 if (!max) max = &garbage1;
Chris@216 267 if (!deflt) deflt = &garbage2;
Chris@159 268
Chris@534 269 if (name == "Gain") {
Chris@534 270
Chris@534 271 *min = -50;
Chris@534 272 *max = 50;
Chris@534 273
Chris@902 274 *deflt = int(lrint(log10(1.0) * 20.0));
Chris@534 275 if (*deflt < *min) *deflt = *min;
Chris@534 276 if (*deflt > *max) *deflt = *max;
Chris@534 277
Chris@902 278 val = int(lrint(log10(m_gain) * 20.0));
Chris@534 279 if (val < *min) val = *min;
Chris@534 280 if (val > *max) val = *max;
Chris@534 281
Chris@534 282 } else if (name == "Colour Scale") {
Chris@159 283
Chris@1099 284 // linear, log, +/-1, abs
Chris@159 285 *min = 0;
Chris@509 286 *max = 3;
Chris@1099 287 *deflt = 0;
Chris@159 288
Chris@216 289 val = (int)m_colourScale;
Chris@159 290
Chris@197 291 } else if (name == "Colour") {
Chris@197 292
Chris@197 293 *min = 0;
Chris@197 294 *max = ColourMapper::getColourMapCount() - 1;
Chris@216 295 *deflt = 0;
Chris@197 296
Chris@216 297 val = m_colourMap;
Chris@197 298
Chris@1099 299 } else if (name == "Normalization") {
Chris@197 300
Chris@1099 301 *min = 0;
Chris@1099 302 *max = 3;
Chris@1099 303 *deflt = int(ColumnOp::NoNormalization);
Chris@1099 304 val = (int)m_normalization;
Chris@197 305
Chris@357 306 } else if (name == "Invert Vertical Scale") {
Chris@357 307
Chris@357 308 *deflt = 0;
Chris@357 309 val = (m_invertVertical ? 1 : 0);
Chris@357 310
Chris@531 311 } else if (name == "Bin Scale") {
Chris@531 312
Chris@531 313 *min = 0;
Chris@531 314 *max = 1;
Chris@1099 315 *deflt = int(Colour3DPlotRenderer::LinearBinScale);
Chris@531 316 val = (int)m_binScale;
Chris@531 317
Chris@465 318 } else if (name == "Opaque") {
Chris@465 319
Chris@465 320 *deflt = 0;
Chris@465 321 val = (m_opaque ? 1 : 0);
Chris@465 322
Chris@535 323 } else if (name == "Smooth") {
Chris@535 324
Chris@535 325 *deflt = 0;
Chris@535 326 val = (m_smooth ? 1 : 0);
Chris@535 327
Chris@159 328 } else {
Chris@216 329 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@159 330 }
Chris@159 331
Chris@216 332 return val;
Chris@159 333 }
Chris@159 334
Chris@159 335 QString
Chris@159 336 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name,
Chris@159 337 int value) const
Chris@159 338 {
Chris@197 339 if (name == "Colour") {
Chris@197 340 return ColourMapper::getColourMapName(value);
Chris@197 341 }
Chris@159 342 if (name == "Colour Scale") {
Chris@159 343 switch (value) {
Chris@159 344 default:
Chris@1099 345 //!!! yuck
Chris@198 346 case 0: return tr("Linear");
Chris@198 347 case 1: return tr("Log");
Chris@198 348 case 2: return tr("+/-1");
Chris@509 349 case 3: return tr("Absolute");
Chris@159 350 }
Chris@159 351 }
Chris@1099 352 if (name == "Normalization") {
Chris@1099 353 return ""; // icon only
Chris@1099 354 }
Chris@531 355 if (name == "Bin Scale") {
Chris@531 356 switch (value) {
Chris@531 357 default:
Chris@531 358 case 0: return tr("Linear");
Chris@531 359 case 1: return tr("Log");
Chris@531 360 }
Chris@531 361 }
Chris@159 362 return tr("<unknown>");
Chris@159 363 }
Chris@159 364
Chris@1099 365 QString
Chris@1099 366 Colour3DPlotLayer::getPropertyValueIconName(const PropertyName &name,
Chris@1099 367 int value) const
Chris@1099 368 {
Chris@1099 369 if (name == "Normalization") {
Chris@1099 370 switch(value) {
Chris@1099 371 default:
Chris@1099 372 case 0: return "normalise-none";
Chris@1099 373 case 1: return "normalise-columns";
Chris@1099 374 case 2: return "normalise";
Chris@1099 375 case 3: return "normalise-hybrid";
Chris@1099 376 }
Chris@1099 377 }
Chris@1099 378 return "";
Chris@1099 379 }
Chris@1099 380
Chris@534 381 RangeMapper *
Chris@534 382 Colour3DPlotLayer::getNewPropertyRangeMapper(const PropertyName &name) const
Chris@534 383 {
Chris@534 384 if (name == "Gain") {
Chris@534 385 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
Chris@534 386 }
Chris@534 387 return 0;
Chris@534 388 }
Chris@534 389
Chris@159 390 void
Chris@159 391 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
Chris@159 392 {
Chris@534 393 if (name == "Gain") {
Chris@902 394 setGain(float(pow(10, value/20.0)));
Chris@534 395 } else if (name == "Colour Scale") {
Chris@159 396 switch (value) {
Chris@159 397 default:
Chris@1099 398 case 0: setColourScale(ColourScale::LinearColourScale); break;
Chris@1099 399 case 1: setColourScale(ColourScale::LogColourScale); break;
Chris@1099 400 case 2: setColourScale(ColourScale::PlusMinusOneScale); break;
Chris@1099 401 case 3: setColourScale(ColourScale::AbsoluteScale); break;
Chris@159 402 }
Chris@197 403 } else if (name == "Colour") {
Chris@197 404 setColourMap(value);
Chris@357 405 } else if (name == "Invert Vertical Scale") {
Chris@357 406 setInvertVertical(value ? true : false);
Chris@465 407 } else if (name == "Opaque") {
Chris@465 408 setOpaque(value ? true : false);
Chris@535 409 } else if (name == "Smooth") {
Chris@535 410 setSmooth(value ? true : false);
Chris@531 411 } else if (name == "Bin Scale") {
Chris@531 412 switch (value) {
Chris@531 413 default:
Chris@1099 414 case 0: setBinScale(Colour3DPlotRenderer::LinearBinScale); break;
Chris@1099 415 case 1: setBinScale(Colour3DPlotRenderer::LogBinScale); break;
Chris@531 416 }
Chris@1099 417 } else if (name == "Normalization") {
Chris@1099 418 switch (value) {
Chris@1099 419 default:
Chris@1099 420 case 0: setNormalization(ColumnOp::NoNormalization); break;
Chris@1099 421 case 1: setNormalization(ColumnOp::NormalizeColumns); break;
Chris@1099 422 case 2: setNormalization(ColumnOp::NormalizeVisibleArea); break;
Chris@1099 423 case 3: setNormalization(ColumnOp::NormalizeHybrid); break;
Chris@1099 424 }
Chris@159 425 }
Chris@159 426 }
Chris@159 427
Chris@159 428 void
Chris@1099 429 Colour3DPlotLayer::setColourScale(ColourScale::Scale scale)
Chris@159 430 {
Chris@159 431 if (m_colourScale == scale) return;
Chris@159 432 m_colourScale = scale;
Chris@461 433 m_colourScaleSet = true;
Chris@159 434 cacheInvalid();
Chris@159 435 emit layerParametersChanged();
Chris@159 436 }
Chris@159 437
Chris@197 438 void
Chris@197 439 Colour3DPlotLayer::setColourMap(int map)
Chris@197 440 {
Chris@197 441 if (m_colourMap == map) return;
Chris@197 442 m_colourMap = map;
Chris@197 443 cacheInvalid();
Chris@197 444 emit layerParametersChanged();
Chris@197 445 }
Chris@197 446
Chris@197 447 void
Chris@534 448 Colour3DPlotLayer::setGain(float gain)
Chris@534 449 {
Chris@534 450 if (m_gain == gain) return;
Chris@534 451 m_gain = gain;
Chris@534 452 cacheInvalid();
Chris@534 453 emit layerParametersChanged();
Chris@534 454 }
Chris@534 455
Chris@534 456 float
Chris@534 457 Colour3DPlotLayer::getGain() const
Chris@534 458 {
Chris@534 459 return m_gain;
Chris@534 460 }
Chris@534 461
Chris@534 462 void
Chris@1099 463 Colour3DPlotLayer::setBinScale(Colour3DPlotRenderer::BinScale binScale)
Chris@531 464 {
Chris@531 465 if (m_binScale == binScale) return;
Chris@531 466 m_binScale = binScale;
Chris@531 467 cacheInvalid();
Chris@531 468 emit layerParametersChanged();
Chris@531 469 }
Chris@531 470
Chris@1099 471 Colour3DPlotRenderer::BinScale
Chris@531 472 Colour3DPlotLayer::getBinScale() const
Chris@531 473 {
Chris@531 474 return m_binScale;
Chris@531 475 }
Chris@531 476
Chris@531 477 void
Chris@1099 478 Colour3DPlotLayer::setNormalization(ColumnOp::Normalization n)
Chris@197 479 {
Chris@1099 480 if (m_normalization == n) return;
Chris@1099 481
Chris@1099 482 m_normalization = n;
Chris@197 483 cacheInvalid();
Chris@1099 484
Chris@197 485 emit layerParametersChanged();
Chris@197 486 }
Chris@197 487
Chris@1099 488 ColumnOp::Normalization
Chris@1099 489 Colour3DPlotLayer::getNormalization() const
Chris@197 490 {
Chris@1099 491 return m_normalization;
Chris@197 492 }
Chris@197 493
Chris@357 494 void
Chris@357 495 Colour3DPlotLayer::setInvertVertical(bool n)
Chris@357 496 {
Chris@357 497 if (m_invertVertical == n) return;
Chris@357 498 m_invertVertical = n;
Chris@357 499 cacheInvalid();
Chris@357 500 emit layerParametersChanged();
Chris@357 501 }
Chris@357 502
Chris@465 503 void
Chris@465 504 Colour3DPlotLayer::setOpaque(bool n)
Chris@465 505 {
Chris@465 506 if (m_opaque == n) return;
Chris@465 507 m_opaque = n;
Chris@465 508 emit layerParametersChanged();
Chris@465 509 }
Chris@465 510
Chris@535 511 void
Chris@535 512 Colour3DPlotLayer::setSmooth(bool n)
Chris@535 513 {
Chris@535 514 if (m_smooth == n) return;
Chris@535 515 m_smooth = n;
Chris@535 516 emit layerParametersChanged();
Chris@535 517 }
Chris@535 518
Chris@357 519 bool
Chris@357 520 Colour3DPlotLayer::getInvertVertical() const
Chris@357 521 {
Chris@357 522 return m_invertVertical;
Chris@357 523 }
Chris@357 524
Chris@25 525 bool
Chris@465 526 Colour3DPlotLayer::getOpaque() const
Chris@465 527 {
Chris@465 528 return m_opaque;
Chris@465 529 }
Chris@465 530
Chris@535 531 bool
Chris@535 532 Colour3DPlotLayer::getSmooth() const
Chris@535 533 {
Chris@535 534 return m_smooth;
Chris@535 535 }
Chris@535 536
Chris@475 537 void
Chris@916 538 Colour3DPlotLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant)
Chris@475 539 {
Chris@475 540 if (dormant) {
Chris@475 541
Chris@475 542 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 543 cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")"
Chris@585 544 << endl;
Chris@475 545 #endif
Chris@475 546
Chris@475 547 if (isLayerDormant(v)) {
Chris@475 548 return;
Chris@475 549 }
Chris@475 550
Chris@475 551 Layer::setLayerDormant(v, true);
Chris@475 552
Chris@475 553 cacheInvalid();
Chris@475 554
Chris@475 555 } else {
Chris@475 556
Chris@475 557 Layer::setLayerDormant(v, false);
Chris@475 558 }
Chris@475 559 }
Chris@475 560
Chris@465 561 bool
Chris@916 562 Colour3DPlotLayer::isLayerScrollable(const LayerGeometryProvider *v) const
Chris@25 563 {
Chris@1099 564 if (m_normalization == ColumnOp::NormalizeVisibleArea) {
Chris@812 565 return false;
Chris@812 566 }
Chris@812 567 if (shouldPaintDenseIn(v)) {
Chris@812 568 return true;
Chris@812 569 }
Chris@25 570 QPoint discard;
Chris@44 571 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@25 572 }
Chris@25 573
Chris@444 574 bool
Chris@904 575 Colour3DPlotLayer::getValueExtents(double &min, double &max,
Chris@444 576 bool &logarithmic, QString &unit) const
Chris@444 577 {
Chris@444 578 if (!m_model) return false;
Chris@444 579
Chris@444 580 min = 0;
Chris@904 581 max = double(m_model->getHeight());
Chris@444 582
Chris@444 583 logarithmic = false;
Chris@444 584 unit = "";
Chris@444 585
Chris@444 586 return true;
Chris@444 587 }
Chris@444 588
Chris@444 589 bool
Chris@904 590 Colour3DPlotLayer::getDisplayExtents(double &min, double &max) const
Chris@444 591 {
Chris@444 592 if (!m_model) return false;
Chris@444 593
Chris@904 594 double hmax = double(m_model->getHeight());
Chris@902 595
Chris@904 596 min = m_miny;
Chris@904 597 max = m_maxy;
Chris@444 598 if (max <= min) {
Chris@444 599 min = 0;
Chris@902 600 max = hmax;
Chris@444 601 }
Chris@444 602 if (min < 0) min = 0;
Chris@902 603 if (max > hmax) max = hmax;
Chris@444 604
Chris@444 605 return true;
Chris@444 606 }
Chris@444 607
Chris@444 608 bool
Chris@904 609 Colour3DPlotLayer::setDisplayExtents(double min, double max)
Chris@444 610 {
Chris@444 611 if (!m_model) return false;
Chris@444 612
Chris@904 613 m_miny = int(lrint(min));
Chris@904 614 m_maxy = int(lrint(max));
Chris@444 615
Chris@444 616 emit layerParametersChanged();
Chris@444 617 return true;
Chris@444 618 }
Chris@444 619
Chris@725 620 bool
Chris@916 621 Colour3DPlotLayer::getYScaleValue(const LayerGeometryProvider *, int,
Chris@904 622 double &, QString &) const
Chris@725 623 {
Chris@725 624 return false;//!!!
Chris@725 625 }
Chris@725 626
Chris@444 627 int
Chris@444 628 Colour3DPlotLayer::getVerticalZoomSteps(int &defaultStep) const
Chris@444 629 {
Chris@444 630 if (!m_model) return 0;
Chris@444 631
Chris@444 632 defaultStep = 0;
Chris@444 633 int h = m_model->getHeight();
Chris@444 634 return h;
Chris@444 635 }
Chris@444 636
Chris@444 637 int
Chris@444 638 Colour3DPlotLayer::getCurrentVerticalZoomStep() const
Chris@444 639 {
Chris@444 640 if (!m_model) return 0;
Chris@444 641
Chris@904 642 double min, max;
Chris@444 643 getDisplayExtents(min, max);
Chris@904 644 return m_model->getHeight() - int(lrint(max - min));
Chris@444 645 }
Chris@444 646
Chris@444 647 void
Chris@444 648 Colour3DPlotLayer::setVerticalZoomStep(int step)
Chris@444 649 {
Chris@444 650 if (!m_model) return;
Chris@444 651
Chris@587 652 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): before: miny = " << m_miny << ", maxy = " << m_maxy << endl;
Chris@444 653
Chris@444 654 int dist = m_model->getHeight() - step;
Chris@444 655 if (dist < 1) dist = 1;
Chris@904 656 double centre = m_miny + (m_maxy - m_miny) / 2.0;
Chris@904 657 m_miny = int(lrint(centre - dist/2.0));
Chris@444 658 if (m_miny < 0) m_miny = 0;
Chris@444 659 m_maxy = m_miny + dist;
Chris@444 660 if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight();
Chris@444 661
Chris@587 662 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): after: miny = " << m_miny << ", maxy = " << m_maxy << endl;
Chris@444 663
Chris@444 664 emit layerParametersChanged();
Chris@444 665 }
Chris@444 666
Chris@444 667 RangeMapper *
Chris@444 668 Colour3DPlotLayer::getNewVerticalZoomRangeMapper() const
Chris@444 669 {
Chris@444 670 if (!m_model) return 0;
Chris@444 671
Chris@444 672 return new LinearRangeMapper(0, m_model->getHeight(),
Chris@444 673 0, m_model->getHeight(), "");
Chris@444 674 }
Chris@444 675
Chris@904 676 double
Chris@916 677 Colour3DPlotLayer::getYForBin(LayerGeometryProvider *v, double bin) const
Chris@532 678 {
Chris@904 679 double y = bin;
Chris@532 680 if (!m_model) return y;
Chris@904 681 double mn = 0, mx = m_model->getHeight();
Chris@532 682 getDisplayExtents(mn, mx);
Chris@916 683 double h = v->getPaintHeight();
Chris@1099 684 if (m_binScale == Colour3DPlotRenderer::LinearBinScale) {
Chris@532 685 y = h - (((bin - mn) * h) / (mx - mn));
Chris@532 686 } else {
Chris@904 687 double logmin = mn + 1, logmax = mx + 1;
Chris@532 688 LogRange::mapRange(logmin, logmax);
Chris@532 689 y = h - (((LogRange::map(bin + 1) - logmin) * h) / (logmax - logmin));
Chris@532 690 }
Chris@532 691 return y;
Chris@532 692 }
Chris@532 693
Chris@904 694 double
Chris@916 695 Colour3DPlotLayer::getBinForY(LayerGeometryProvider *v, double y) const
Chris@532 696 {
Chris@904 697 double bin = y;
Chris@532 698 if (!m_model) return bin;
Chris@904 699 double mn = 0, mx = m_model->getHeight();
Chris@532 700 getDisplayExtents(mn, mx);
Chris@916 701 double h = v->getPaintHeight();
Chris@1099 702 if (m_binScale == Colour3DPlotRenderer::LinearBinScale) {
Chris@532 703 bin = mn + ((h - y) * (mx - mn)) / h;
Chris@532 704 } else {
Chris@904 705 double logmin = mn + 1, logmax = mx + 1;
Chris@532 706 LogRange::mapRange(logmin, logmax);
Chris@532 707 bin = LogRange::unmap(logmin + ((h - y) * (logmax - logmin)) / h) - 1;
Chris@532 708 }
Chris@532 709 return bin;
Chris@532 710 }
Chris@532 711
Chris@25 712 QString
Chris@916 713 Colour3DPlotLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
Chris@25 714 {
Chris@25 715 if (!m_model) return "";
Chris@25 716
Chris@25 717 int x = pos.x();
Chris@25 718 int y = pos.y();
Chris@25 719
Chris@902 720 sv_frame_t modelStart = m_model->getStartFrame();
Chris@805 721 int modelResolution = m_model->getResolution();
Chris@25 722
Chris@902 723 double srRatio =
Chris@902 724 v->getViewManager()->getMainModelSampleRate() /
Chris@902 725 m_model->getSampleRate();
Chris@159 726
Chris@902 727 int sx0 = int((double(v->getFrameForX(x)) / srRatio - double(modelStart)) /
Chris@812 728 modelResolution);
Chris@25 729
Chris@160 730 int f0 = sx0 * modelResolution;
Chris@160 731 int f1 = f0 + modelResolution;
Chris@160 732
Chris@447 733 int sh = m_model->getHeight();
Chris@447 734
Chris@447 735 int symin = m_miny;
Chris@447 736 int symax = m_maxy;
Chris@447 737 if (symax <= symin) {
Chris@447 738 symin = 0;
Chris@447 739 symax = sh;
Chris@447 740 }
Chris@447 741 if (symin < 0) symin = 0;
Chris@447 742 if (symax > sh) symax = sh;
Chris@447 743
Chris@916 744 // double binHeight = double(v->getPaintHeight()) / (symax - symin);
Chris@916 745 // int sy = int((v->getPaintHeight() - y) / binHeight) + symin;
Chris@534 746
Chris@903 747 int sy = getIBinForY(v, y);
Chris@25 748
Chris@812 749 if (sy < 0 || sy >= m_model->getHeight()) {
Chris@812 750 return "";
Chris@812 751 }
Chris@812 752
Chris@357 753 if (m_invertVertical) sy = m_model->getHeight() - sy - 1;
Chris@357 754
Chris@160 755 float value = m_model->getValueAt(sx0, sy);
Chris@159 756
Chris@682 757 // cerr << "bin value (" << sx0 << "," << sy << ") is " << value << endl;
Chris@25 758
Chris@25 759 QString binName = m_model->getBinName(sy);
Chris@25 760 if (binName == "") binName = QString("[%1]").arg(sy + 1);
Chris@25 761 else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
Chris@25 762
Chris@25 763 QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
Chris@160 764 .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
Chris@25 765 .toText(true).c_str())
Chris@160 766 .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
Chris@25 767 .toText(true).c_str())
Chris@25 768 .arg(binName)
Chris@25 769 .arg(value);
Chris@25 770
Chris@25 771 return text;
Chris@25 772 }
Chris@25 773
Chris@25 774 int
Chris@969 775 Colour3DPlotLayer::getColourScaleWidth(QPainter &p) const
Chris@159 776 {
Chris@969 777 // Font is rotated
Chris@969 778 int cw = p.fontMetrics().height();
Chris@159 779 return cw;
Chris@159 780 }
Chris@159 781
Chris@159 782 int
Chris@916 783 Colour3DPlotLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const
Chris@25 784 {
Chris@25 785 if (!m_model) return 0;
Chris@25 786
Chris@160 787 QString sampleText = QString("[%1]").arg(m_model->getHeight());
Chris@25 788 int tw = paint.fontMetrics().width(sampleText);
Chris@98 789 bool another = false;
Chris@25 790
Chris@805 791 for (int i = 0; i < m_model->getHeight(); ++i) {
Chris@25 792 if (m_model->getBinName(i).length() > sampleText.length()) {
Chris@25 793 sampleText = m_model->getBinName(i);
Chris@98 794 another = true;
Chris@25 795 }
Chris@25 796 }
Chris@98 797 if (another) {
Chris@25 798 tw = std::max(tw, paint.fontMetrics().width(sampleText));
Chris@25 799 }
Chris@25 800
Chris@159 801 return tw + 13 + getColourScaleWidth(paint);
Chris@25 802 }
Chris@25 803
Chris@25 804 void
Chris@916 805 Colour3DPlotLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const
Chris@25 806 {
Chris@25 807 if (!m_model) return;
Chris@25 808
Chris@25 809 int h = rect.height(), w = rect.width();
Chris@25 810
Chris@159 811 int cw = getColourScaleWidth(paint);
Chris@159 812
Chris@159 813 int ch = h - 20;
Chris@159 814 if (ch > 20 && m_cache) {
Chris@159 815
Chris@904 816 double min = m_model->getMinimumLevel();
Chris@904 817 double max = m_model->getMaximumLevel();
Chris@447 818
Chris@904 819 double mmin = min;
Chris@904 820 double mmax = max;
Chris@447 821
Chris@1099 822 if (m_colourScale == ColourScale::LogColourScale) {
Chris@447 823 LogRange::mapRange(mmin, mmax);
Chris@1099 824 } else if (m_colourScale == ColourScale::PlusMinusOneScale) {
Chris@447 825 mmin = -1.f;
Chris@447 826 mmax = 1.f;
Chris@1099 827 } else if (m_colourScale == ColourScale::AbsoluteScale) {
Chris@509 828 if (mmin < 0) {
Chris@904 829 if (fabs(mmin) > fabs(mmax)) mmax = fabs(mmin);
Chris@904 830 else mmax = fabs(mmax);
Chris@509 831 mmin = 0;
Chris@509 832 } else {
Chris@904 833 mmin = fabs(mmin);
Chris@904 834 mmax = fabs(mmax);
Chris@509 835 }
Chris@447 836 }
Chris@447 837
Chris@902 838 if (max == min) max = min + 1.f;
Chris@902 839 if (mmax == mmin) mmax = mmin + 1.f;
Chris@447 840
Chris@287 841 paint.setPen(v->getForeground());
Chris@447 842 paint.drawRect(4, 10, cw - 8, ch+1);
Chris@159 843
Chris@446 844 for (int y = 0; y < ch; ++y) {
Chris@904 845 double value = ((max - min) * (double(ch-y) - 1.0)) / double(ch) + min;
Chris@1099 846 if (m_colourScale == ColourScale::LogColourScale) {
Chris@447 847 value = LogRange::map(value);
Chris@447 848 }
Chris@447 849 int pixel = int(((value - mmin) * 256) / (mmax - mmin));
Chris@465 850 if (pixel >= 0 && pixel < 256) {
Chris@465 851 QRgb c = m_cache->color(pixel);
Chris@465 852 paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c)));
Chris@465 853 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
Chris@465 854 } else {
Chris@682 855 cerr << "WARNING: Colour3DPlotLayer::paintVerticalScale: value " << value << ", mmin " << mmin << ", mmax " << mmax << " leads to invalid pixel " << pixel << endl;
Chris@465 856 }
Chris@159 857 }
Chris@446 858
Chris@446 859 QString minstr = QString("%1").arg(min);
Chris@446 860 QString maxstr = QString("%1").arg(max);
Chris@446 861
Chris@446 862 paint.save();
Chris@446 863
Chris@446 864 QFont font = paint.font();
Chris@1053 865 if (font.pixelSize() > 0) {
Chris@1053 866 int newSize = int(font.pixelSize() * 0.65);
Chris@1053 867 if (newSize < 6) newSize = 6;
Chris@1053 868 font.setPixelSize(newSize);
Chris@1053 869 paint.setFont(font);
Chris@1053 870 }
Chris@446 871
Chris@446 872 int msw = paint.fontMetrics().width(maxstr);
Chris@446 873
Chris@446 874 QMatrix m;
Chris@446 875 m.translate(cw - 6, ch + 10);
Chris@446 876 m.rotate(-90);
Chris@446 877
Chris@446 878 paint.setWorldMatrix(m);
Chris@446 879
Chris@1078 880 PaintAssistant::drawVisibleText(v, paint, 2, 0, minstr, PaintAssistant::OutlinedText);
Chris@446 881
Chris@446 882 m.translate(ch - msw - 2, 0);
Chris@446 883 paint.setWorldMatrix(m);
Chris@446 884
Chris@1078 885 PaintAssistant::drawVisibleText(v, paint, 0, 0, maxstr, PaintAssistant::OutlinedText);
Chris@446 886
Chris@446 887 paint.restore();
Chris@159 888 }
Chris@159 889
Chris@287 890 paint.setPen(v->getForeground());
Chris@159 891
Chris@445 892 int sh = m_model->getHeight();
Chris@445 893
Chris@445 894 int symin = m_miny;
Chris@445 895 int symax = m_maxy;
Chris@445 896 if (symax <= symin) {
Chris@445 897 symin = 0;
Chris@445 898 symax = sh;
Chris@445 899 }
Chris@445 900 if (symin < 0) symin = 0;
Chris@445 901 if (symax > sh) symax = sh;
Chris@445 902
Chris@532 903 paint.save();
Chris@456 904
Chris@533 905 int py = h;
Chris@25 906
Chris@969 907 int defaultFontHeight = paint.fontMetrics().height();
Chris@969 908
Chris@805 909 for (int i = symin; i <= symax; ++i) {
Chris@98 910
Chris@532 911 int y0;
Chris@534 912
Chris@903 913 y0 = getIYForBin(v, i);
Chris@532 914 int h = py - y0;
Chris@532 915
Chris@532 916 if (i > symin) {
Chris@532 917 if (paint.fontMetrics().height() >= h) {
Chris@969 918 if (h >= defaultFontHeight * 0.8) {
Chris@532 919 QFont tf = paint.font();
Chris@973 920 tf.setPixelSize(int(h * 0.8));
Chris@532 921 paint.setFont(tf);
Chris@532 922 } else {
Chris@532 923 continue;
Chris@532 924 }
Chris@532 925 }
Chris@532 926 }
Chris@25 927
Chris@532 928 py = y0;
Chris@532 929
Chris@534 930 if (i < symax) {
Chris@534 931 paint.drawLine(cw, y0, w, y0);
Chris@534 932 }
Chris@25 933
Chris@532 934 if (i > symin) {
Chris@534 935
Chris@805 936 int idx = i - 1;
Chris@534 937 if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
Chris@534 938
Chris@534 939 QString text = m_model->getBinName(idx);
Chris@534 940 if (text == "") text = QString("[%1]").arg(idx + 1);
Chris@534 941
Chris@534 942 int ty = y0 + (h/2) - (paint.fontMetrics().height()/2) +
Chris@534 943 paint.fontMetrics().ascent() + 1;
Chris@534 944
Chris@534 945 paint.drawText(cw + 5, ty, text);
Chris@457 946 }
Chris@25 947 }
Chris@456 948
Chris@456 949 paint.restore();
Chris@25 950 }
Chris@25 951
Chris@467 952 DenseThreeDimensionalModel::Column
Chris@805 953 Colour3DPlotLayer::getColumn(int col) const
Chris@197 954 {
Chris@812 955 Profiler profiler("Colour3DPlotLayer::getColumn");
Chris@812 956
Chris@467 957 DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
Chris@1019 958 values.resize(m_model->getHeight(), 0.f);
Chris@1099 959 if (m_normalization != ColumnOp::NormalizeColumns &&
Chris@1099 960 m_normalization != ColumnOp::NormalizeHybrid) {
Chris@1099 961 return values;
Chris@1099 962 }
Chris@461 963
Chris@904 964 double colMax = 0.f, colMin = 0.f;
Chris@904 965 double min = 0.f, max = 0.f;
Chris@197 966
Chris@1019 967 int nv = int(values.size());
Chris@1019 968
Chris@461 969 min = m_model->getMinimumLevel();
Chris@461 970 max = m_model->getMaximumLevel();
Chris@461 971
Chris@1019 972 for (int y = 0; y < nv; ++y) {
Chris@467 973 if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
Chris@467 974 if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
Chris@197 975 }
Chris@461 976 if (colMin == colMax) colMax = colMin + 1;
Chris@197 977
Chris@1019 978 for (int y = 0; y < nv; ++y) {
Chris@461 979
Chris@904 980 double value = values.at(y);
Chris@904 981 double norm = (value - colMin) / (colMax - colMin);
Chris@904 982 double newvalue = min + (max - min) * norm;
Chris@197 983
Chris@904 984 if (value != newvalue) values[y] = float(newvalue);
Chris@468 985 }
Chris@468 986
Chris@1099 987 if (m_normalization == ColumnOp::NormalizeHybrid
Chris@1099 988 && (colMax > 0.0)) {
Chris@904 989 double logmax = log10(colMax);
Chris@1019 990 for (int y = 0; y < nv; ++y) {
Chris@904 991 values[y] = float(values[y] * logmax);
Chris@719 992 }
Chris@719 993 }
Chris@719 994
Chris@468 995 return values;
Chris@197 996 }
Chris@197 997
Chris@197 998 void
Chris@1046 999 Colour3DPlotLayer::fillCache(int firstColumn, int lastColumn) const
Chris@197 1000 {
Chris@1046 1001 // This call requests a (perhaps partial) fill of the cache
Chris@1046 1002 // between model columns firstColumn and lastColumn inclusive.
Chris@1046 1003 // The cache itself always has size sufficient to contain the
Chris@1046 1004 // whole model, but its validity may be less, depending on which
Chris@1046 1005 // regions have been requested via calls to this function. Note
Chris@1046 1006 // that firstColumn and lastColumn are *model* column numbers. If
Chris@1046 1007 // the model starts at a frame > 0, a firstColumn of zero still
Chris@1046 1008 // corresponds to the first column in the model, not the first
Chris@1046 1009 // column on the resulting rendered layer.
Chris@1046 1010
Chris@812 1011 Profiler profiler("Colour3DPlotLayer::fillCache", true);
Chris@476 1012
Chris@1046 1013 int cacheWidth = m_model->getWidth();
Chris@1046 1014 int cacheHeight = m_model->getHeight();
Chris@461 1015
Chris@812 1016 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@1046 1017 cerr << "Colour3DPlotLayer::fillCache: range " << firstColumn << " -> " << lastColumn << " (cache size will be " << cacheWidth << " x " << cacheHeight << ")" << endl;
Chris@812 1018 #endif
Chris@812 1019
Chris@812 1020 if (m_cache && m_cache->height() != cacheHeight) {
Chris@742 1021 // height has changed: delete everything rather than resizing
Chris@812 1022 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1023 cerr << "Colour3DPlotLayer::fillCache: Cache height has changed, recreating" << endl;
Chris@812 1024 #endif
Chris@461 1025 delete m_cache;
Chris@469 1026 delete m_peaksCache;
Chris@461 1027 m_cache = 0;
Chris@469 1028 m_peaksCache = 0;
Chris@461 1029 }
Chris@461 1030
Chris@812 1031 if (m_cache && m_cache->width() != cacheWidth) {
Chris@742 1032 // width has changed and we have an existing cache: resize it
Chris@812 1033 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1034 cerr << "Colour3DPlotLayer::fillCache: Cache width has changed, resizing existing cache" << endl;
Chris@812 1035 #endif
Chris@469 1036 QImage *newCache =
Chris@469 1037 new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight));
Chris@461 1038 delete m_cache;
Chris@461 1039 m_cache = newCache;
Chris@469 1040 if (m_peaksCache) {
Chris@469 1041 QImage *newPeaksCache =
Chris@469 1042 new QImage(m_peaksCache->copy
Chris@742 1043 (0, 0, cacheWidth / m_peakResolution + 1, cacheHeight));
Chris@469 1044 delete m_peaksCache;
Chris@469 1045 m_peaksCache = newPeaksCache;
Chris@469 1046 }
Chris@197 1047 }
Chris@197 1048
Chris@461 1049 if (!m_cache) {
Chris@812 1050 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1051 cerr << "Colour3DPlotLayer::fillCache: Have no cache, making one" << endl;
Chris@812 1052 #endif
Chris@1046 1053 m_cache = new QImage(cacheWidth, cacheHeight, QImage::Format_Indexed8);
Chris@812 1054 m_cache->setColorCount(256);
Chris@514 1055 m_cache->fill(0);
Chris@1099 1056 if (m_normalization != ColumnOp::NormalizeVisibleArea) {
Chris@469 1057 m_peaksCache = new QImage
Chris@469 1058 (cacheWidth / m_peakResolution + 1, cacheHeight,
Chris@469 1059 QImage::Format_Indexed8);
Chris@812 1060 m_peaksCache->setColorCount(256);
Chris@514 1061 m_peaksCache->fill(0);
Chris@469 1062 } else if (m_peaksCache) {
Chris@469 1063 delete m_peaksCache;
Chris@469 1064 m_peaksCache = 0;
Chris@469 1065 }
Chris@461 1066 m_cacheValidStart = 0;
Chris@461 1067 m_cacheValidEnd = 0;
Chris@197 1068 }
Chris@197 1069
Chris@812 1070 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1071 cerr << "cache size = " << m_cache->width() << "x" << m_cache->height()
Chris@812 1072 << " peaks cache size = " << m_peaksCache->width() << "x" << m_peaksCache->height() << endl;
Chris@812 1073 #endif
Chris@742 1074
Chris@1046 1075 if (m_cacheValidStart <= firstColumn && m_cacheValidEnd >= lastColumn) {
Chris@519 1076 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@682 1077 cerr << "Cache is valid in this region already" << endl;
Chris@519 1078 #endif
Chris@461 1079 return;
Chris@461 1080 }
Chris@461 1081
Chris@1046 1082 int fillStart = firstColumn;
Chris@1046 1083 int fillEnd = lastColumn;
Chris@197 1084
Chris@1046 1085 if (fillStart >= cacheWidth) fillStart = cacheWidth-1;
Chris@1046 1086 if (fillStart < 0) fillStart = 0;
Chris@1046 1087 if (fillEnd >= cacheWidth) fillEnd = cacheWidth-1;
Chris@1046 1088 if (fillEnd < 0) fillEnd = 0;
Chris@1046 1089 if (fillEnd < fillStart) fillEnd = fillStart;
Chris@197 1090
Chris@1099 1091 bool normalizeVisible = (m_normalization == ColumnOp::NormalizeVisibleArea);
Chris@197 1092
Chris@461 1093 if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) {
Chris@461 1094
Chris@461 1095 if (m_cacheValidEnd < fillStart) {
Chris@461 1096 fillStart = m_cacheValidEnd + 1;
Chris@461 1097 }
Chris@461 1098 if (m_cacheValidStart > fillEnd) {
Chris@461 1099 fillEnd = m_cacheValidStart - 1;
Chris@461 1100 }
Chris@461 1101
Chris@461 1102 m_cacheValidStart = std::min(fillStart, m_cacheValidStart);
Chris@461 1103 m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd);
Chris@461 1104
Chris@461 1105 } else {
Chris@461 1106
Chris@812 1107 // when normalising the visible area, the only valid area,
Chris@812 1108 // ever, is the currently visible one
Chris@461 1109
Chris@461 1110 m_cacheValidStart = fillStart;
Chris@461 1111 m_cacheValidEnd = fillEnd;
Chris@461 1112 }
Chris@461 1113
Chris@519 1114 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1115 cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << " (fillStart = " << fillStart << ", fillEnd = " << fillEnd << ")" << endl;
Chris@519 1116 #endif
Chris@461 1117
Chris@197 1118 DenseThreeDimensionalModel::Column values;
Chris@197 1119
Chris@904 1120 double min = m_model->getMinimumLevel();
Chris@904 1121 double max = m_model->getMaximumLevel();
Chris@197 1122
Chris@1099 1123 if (m_colourScale == ColourScale::LogColourScale) {
Chris@197 1124 LogRange::mapRange(min, max);
Chris@1099 1125 } else if (m_colourScale == ColourScale::PlusMinusOneScale) {
Chris@197 1126 min = -1.f;
Chris@197 1127 max = 1.f;
Chris@1099 1128 } else if (m_colourScale == ColourScale::AbsoluteScale) {
Chris@509 1129 if (min < 0) {
Chris@904 1130 if (fabs(min) > fabs(max)) max = fabs(min);
Chris@904 1131 else max = fabs(max);
Chris@509 1132 min = 0;
Chris@509 1133 } else {
Chris@904 1134 min = fabs(min);
Chris@904 1135 max = fabs(max);
Chris@509 1136 }
Chris@197 1137 }
Chris@197 1138
Chris@902 1139 if (max == min) max = min + 1.f;
Chris@197 1140
Chris@197 1141 ColourMapper mapper(m_colourMap, 0.f, 255.f);
Chris@197 1142
Chris@197 1143 for (int index = 0; index < 256; ++index) {
Chris@197 1144 QColor colour = mapper.map(index);
Chris@469 1145 m_cache->setColor
Chris@469 1146 (index, qRgb(colour.red(), colour.green(), colour.blue()));
Chris@469 1147 if (m_peaksCache) {
Chris@469 1148 m_peaksCache->setColor
Chris@469 1149 (index, qRgb(colour.red(), colour.green(), colour.blue()));
Chris@469 1150 }
Chris@197 1151 }
Chris@197 1152
Chris@904 1153 double visibleMax = 0.f, visibleMin = 0.f;
Chris@197 1154
Chris@461 1155 if (normalizeVisible) {
Chris@197 1156
Chris@805 1157 for (int c = fillStart; c <= fillEnd; ++c) {
Chris@197 1158
Chris@467 1159 values = getColumn(c);
Chris@197 1160
Chris@904 1161 double colMax = 0.f, colMin = 0.f;
Chris@197 1162
Chris@805 1163 for (int y = 0; y < cacheHeight; ++y) {
Chris@1019 1164 if (!in_range_for(values, y)) break;
Chris@197 1165 if (y == 0 || values[y] > colMax) colMax = values[y];
Chris@224 1166 if (y == 0 || values[y] < colMin) colMin = values[y];
Chris@197 1167 }
Chris@197 1168
Chris@461 1169 if (c == fillStart || colMax > visibleMax) visibleMax = colMax;
Chris@461 1170 if (c == fillStart || colMin < visibleMin) visibleMin = colMin;
Chris@461 1171 }
Chris@461 1172
Chris@1099 1173 if (m_colourScale == ColourScale::LogColourScale) {
Chris@461 1174 visibleMin = LogRange::map(visibleMin);
Chris@461 1175 visibleMax = LogRange::map(visibleMax);
Chris@461 1176 if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax);
Chris@1099 1177 } else if (m_colourScale == ColourScale::AbsoluteScale) {
Chris@509 1178 if (visibleMin < 0) {
Chris@904 1179 if (fabs(visibleMin) > fabs(visibleMax)) visibleMax = fabs(visibleMin);
Chris@904 1180 else visibleMax = fabs(visibleMax);
Chris@509 1181 visibleMin = 0;
Chris@509 1182 } else {
Chris@904 1183 visibleMin = fabs(visibleMin);
Chris@904 1184 visibleMax = fabs(visibleMax);
Chris@509 1185 }
Chris@197 1186 }
Chris@197 1187 }
Chris@197 1188
Chris@224 1189 if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
Chris@224 1190
Chris@469 1191 int *peaks = 0;
Chris@469 1192 if (m_peaksCache) {
Chris@469 1193 peaks = new int[cacheHeight];
Chris@469 1194 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 1195 peaks[y] = 0;
Chris@469 1196 }
Chris@469 1197 }
Chris@469 1198
Chris@812 1199 Profiler profiler2("Colour3DPlotLayer::fillCache: filling", true);
Chris@812 1200
Chris@805 1201 for (int c = fillStart; c <= fillEnd; ++c) {
Chris@197 1202
Chris@467 1203 values = getColumn(c);
Chris@197 1204
Chris@742 1205 if (c >= m_cache->width()) {
Chris@742 1206 cerr << "ERROR: column " << c << " >= cache width "
Chris@742 1207 << m_cache->width() << endl;
Chris@742 1208 continue;
Chris@742 1209 }
Chris@742 1210
Chris@805 1211 for (int y = 0; y < cacheHeight; ++y) {
Chris@197 1212
Chris@904 1213 double value = min;
Chris@1019 1214 if (in_range_for(values, y)) {
Chris@469 1215 value = values.at(y);
Chris@197 1216 }
Chris@224 1217
Chris@534 1218 value = value * m_gain;
Chris@534 1219
Chris@1099 1220 if (m_colourScale == ColourScale::LogColourScale) {
Chris@224 1221 value = LogRange::map(value);
Chris@1099 1222 } else if (m_colourScale == ColourScale::AbsoluteScale) {
Chris@904 1223 value = fabs(value);
Chris@197 1224 }
Chris@461 1225
Chris@461 1226 if (normalizeVisible) {
Chris@904 1227 double norm = (value - visibleMin) / (visibleMax - visibleMin);
Chris@461 1228 value = min + (max - min) * norm;
Chris@461 1229 }
Chris@197 1230
Chris@197 1231 int pixel = int(((value - min) * 256) / (max - min));
Chris@197 1232 if (pixel < 0) pixel = 0;
Chris@197 1233 if (pixel > 255) pixel = 255;
Chris@469 1234 if (peaks && (pixel > peaks[y])) peaks[y] = pixel;
Chris@197 1235
Chris@357 1236 if (m_invertVertical) {
Chris@461 1237 m_cache->setPixel(c, cacheHeight - y - 1, pixel);
Chris@357 1238 } else {
Chris@742 1239 if (y >= m_cache->height()) {
Chris@742 1240 cerr << "ERROR: row " << y << " >= cache height " << m_cache->height() << endl;
Chris@742 1241 } else {
Chris@742 1242 m_cache->setPixel(c, y, pixel);
Chris@742 1243 }
Chris@357 1244 }
Chris@197 1245 }
Chris@469 1246
Chris@469 1247 if (peaks) {
Chris@805 1248 int notch = (c % m_peakResolution);
Chris@469 1249 if (notch == m_peakResolution-1 || c == fillEnd) {
Chris@805 1250 int pc = c / m_peakResolution;
Chris@742 1251 if (pc >= m_peaksCache->width()) {
Chris@742 1252 cerr << "ERROR: peak column " << pc
Chris@742 1253 << " (from col " << c << ") >= peaks cache width "
Chris@742 1254 << m_peaksCache->width() << endl;
Chris@742 1255 continue;
Chris@742 1256 }
Chris@805 1257 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 1258 if (m_invertVertical) {
Chris@469 1259 m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]);
Chris@469 1260 } else {
Chris@742 1261 if (y >= m_peaksCache->height()) {
Chris@742 1262 cerr << "ERROR: row " << y
Chris@742 1263 << " >= peaks cache height "
Chris@742 1264 << m_peaksCache->height() << endl;
Chris@742 1265 } else {
Chris@742 1266 m_peaksCache->setPixel(pc, y, peaks[y]);
Chris@742 1267 }
Chris@469 1268 }
Chris@469 1269 }
Chris@469 1270 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 1271 peaks[y] = 0;
Chris@469 1272 }
Chris@469 1273 }
Chris@469 1274 }
Chris@197 1275 }
Chris@469 1276
Chris@469 1277 delete[] peaks;
Chris@197 1278 }
Chris@197 1279
Chris@812 1280 bool
Chris@916 1281 Colour3DPlotLayer::shouldPaintDenseIn(const LayerGeometryProvider *v) const
Chris@812 1282 {
Chris@812 1283 if (!m_model || !v || !(v->getViewManager())) {
Chris@812 1284 return false;
Chris@812 1285 }
Chris@902 1286 double srRatio =
Chris@902 1287 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
Chris@812 1288 if (m_opaque ||
Chris@812 1289 m_smooth ||
Chris@916 1290 m_model->getHeight() >= v->getPaintHeight() ||
Chris@812 1291 ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) {
Chris@812 1292 return true;
Chris@812 1293 }
Chris@812 1294 return false;
Chris@812 1295 }
Chris@812 1296
Chris@1100 1297 Colour3DPlotRenderer *
Chris@1100 1298 Colour3DPlotLayer::getRenderer(LayerGeometryProvider *v) const
Chris@1100 1299 {
Chris@1100 1300 if (m_renderers.find(v->getId()) == m_renderers.end()) {
Chris@1100 1301
Chris@1100 1302 Colour3DPlotRenderer::Sources sources;
Chris@1100 1303 sources.verticalBinLayer = this;
Chris@1100 1304 sources.fft = 0;
Chris@1100 1305 sources.source = m_model;
Chris@1100 1306 sources.peaks = getPeakCache();
Chris@1100 1307
Chris@1100 1308 ColourScale::Parameters cparams;
Chris@1100 1309 cparams.colourMap = m_colourMap;
Chris@1100 1310 cparams.scale = m_colourScale;
Chris@1100 1311 cparams.gain = m_gain;
Chris@1100 1312
Chris@1100 1313 Colour3DPlotRenderer::Parameters params;
Chris@1100 1314 params.colourScale = ColourScale(cparams);
Chris@1100 1315 params.normalization = m_normalization;
Chris@1100 1316 params.binScale = m_binScale;
Chris@1100 1317 params.alwaysOpaque = m_opaque;
Chris@1100 1318 params.invertVertical = m_invertVertical;
Chris@1100 1319 params.interpolate = m_smooth;
Chris@1100 1320
Chris@1100 1321 m_renderers[v->getId()] = new Colour3DPlotRenderer(sources, params);
Chris@1100 1322 }
Chris@1100 1323
Chris@1100 1324 return m_renderers[v->getId()];
Chris@1100 1325 }
Chris@1100 1326
Chris@197 1327 void
Chris@1101 1328 Colour3DPlotLayer::paintAlternative(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@1101 1329 {
Chris@1101 1330 static int depth = 0;
Chris@1101 1331
Chris@1101 1332 Colour3DPlotRenderer *renderer = getRenderer(v);
Chris@1101 1333
Chris@1101 1334 if (m_synchronous) {
Chris@1101 1335 (void)renderer->render(v, paint, rect);
Chris@1101 1336 return;
Chris@1101 1337 }
Chris@1101 1338
Chris@1101 1339 ++depth;
Chris@1101 1340 cerr << "paint depth " << depth << endl;
Chris@1101 1341
Chris@1101 1342 (void)renderer->renderTimeConstrained(v, paint, rect);
Chris@1101 1343
Chris@1101 1344 //!!! + mag range
Chris@1101 1345
Chris@1101 1346 QRect uncached = renderer->getLargestUncachedRect();
Chris@1101 1347 if (uncached.width() > 0) {
Chris@1101 1348 cerr << "updating rect at " << uncached.x() << " width "
Chris@1101 1349 << uncached.width() << endl;
Chris@1101 1350 v->updatePaintRect(uncached);
Chris@1101 1351 }
Chris@1101 1352
Chris@1101 1353 cerr << "exiting paint depth " << depth << endl;
Chris@1101 1354 --depth;
Chris@1101 1355 }
Chris@1101 1356
Chris@1101 1357 void
Chris@916 1358 Colour3DPlotLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@0 1359 {
Chris@514 1360 /*
Chris@443 1361 if (m_model) {
Chris@587 1362 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
Chris@443 1363 }
Chris@514 1364 */
Chris@466 1365 Profiler profiler("Colour3DPlotLayer::paint");
Chris@125 1366 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1367 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 1368 #endif
Chris@0 1369
Chris@0 1370 int completion = 0;
Chris@0 1371 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
Chris@0 1372 if (completion > 0) {
Chris@916 1373 paint.fillRect(0, 10, v->getPaintWidth() * completion / 100,
Chris@0 1374 10, QColor(120, 120, 120));
Chris@0 1375 }
Chris@0 1376 return;
Chris@0 1377 }
Chris@0 1378
Chris@1053 1379 if (m_model->getWidth() == 0) {
Chris@1053 1380 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@1053 1381 cerr << "Colour3DPlotLayer::paint(): model width == 0, "
Chris@1053 1382 << "nothing to paint (yet)" << endl;
Chris@1053 1383 #endif
Chris@1053 1384 return;
Chris@1053 1385 }
Chris@1101 1386
Chris@1101 1387 //!!! why is the setLayerDormant(false) found here in
Chris@1101 1388 //!!! SpectrogramLayer not present in Colour3DPlotLayer?
Chris@1101 1389 //!!! unnecessary? vestigial? forgotten?
Chris@1101 1390
Chris@1101 1391 paintAlternative(v, paint, rect);
Chris@1101 1392 return;
Chris@1101 1393
Chris@1101 1394 //!!!???
Chris@1053 1395
Chris@1099 1396 if (m_normalization == ColumnOp::NormalizeVisibleArea) {
Chris@1099 1397 rect = v->getPaintRect();
Chris@1099 1398 }
Chris@197 1399
Chris@902 1400 sv_frame_t modelStart = m_model->getStartFrame();
Chris@902 1401 sv_frame_t modelEnd = m_model->getEndFrame();
Chris@805 1402 int modelResolution = m_model->getResolution();
Chris@0 1403
Chris@197 1404 // The cache is from the model's start frame to the model's end
Chris@197 1405 // frame at the model's window increment frames per pixel. We
Chris@197 1406 // want to draw from our start frame + x0 * zoomLevel to our start
Chris@197 1407 // frame + x1 * zoomLevel at zoomLevel frames per pixel.
Chris@12 1408
Chris@197 1409 // We have quite different paint mechanisms for rendering "large"
Chris@197 1410 // bins (more than one bin per pixel in both directions) and
Chris@197 1411 // "small". This is "large"; see paintDense below for "small".
Chris@12 1412
Chris@197 1413 int x0 = rect.left();
Chris@197 1414 int x1 = rect.right() + 1;
Chris@12 1415
Chris@916 1416 int h = v->getPaintHeight();
Chris@0 1417
Chris@902 1418 double srRatio =
Chris@902 1419 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
Chris@0 1420
Chris@1047 1421 // the s-prefix values are source, i.e. model, column and bin numbers
Chris@902 1422 int sx0 = int((double(v->getFrameForX(x0)) / srRatio - double(modelStart))
Chris@812 1423 / modelResolution);
Chris@902 1424 int sx1 = int((double(v->getFrameForX(x1)) / srRatio - double(modelStart))
Chris@812 1425 / modelResolution);
Chris@197 1426 int sh = m_model->getHeight();
Chris@159 1427
Chris@444 1428 int symin = m_miny;
Chris@444 1429 int symax = m_maxy;
Chris@444 1430 if (symax <= symin) {
Chris@444 1431 symin = 0;
Chris@444 1432 symax = sh;
Chris@444 1433 }
Chris@444 1434 if (symin < 0) symin = 0;
Chris@444 1435 if (symax > sh) symax = sh;
Chris@444 1436
Chris@197 1437 if (sx0 > 0) --sx0;
Chris@197 1438 fillCache(sx0 < 0 ? 0 : sx0,
Chris@197 1439 sx1 < 0 ? 0 : sx1);
Chris@0 1440
Chris@351 1441 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1442 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 1443 #endif
Chris@351 1444
Chris@812 1445 if (shouldPaintDenseIn(v)) {
Chris@347 1446 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1447 cerr << "calling paintDense" << endl;
Chris@347 1448 #endif
Chris@98 1449 paintDense(v, paint, rect);
Chris@98 1450 return;
Chris@98 1451 }
Chris@98 1452
Chris@125 1453 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1454 cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << endl;
Chris@682 1455 cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << endl;
Chris@125 1456 #endif
Chris@0 1457
Chris@25 1458 QPoint illuminatePos;
Chris@44 1459 bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
Chris@864 1460
Chris@864 1461 const int buflen = 40;
Chris@864 1462 char labelbuf[buflen];
Chris@25 1463
Chris@197 1464 for (int sx = sx0; sx <= sx1; ++sx) {
Chris@0 1465
Chris@1047 1466 sv_frame_t fx = sx * modelResolution + modelStart;
Chris@0 1467
Chris@812 1468 if (fx + modelResolution <= modelStart || fx > modelEnd) continue;
Chris@0 1469
Chris@1047 1470 int rx0 = v->getXForFrame(int(double(fx) * srRatio));
Chris@1047 1471 int rx1 = v->getXForFrame(int(double(fx + modelResolution + 1) * srRatio));
Chris@54 1472
Chris@159 1473 int rw = rx1 - rx0;
Chris@159 1474 if (rw < 1) rw = 1;
Chris@54 1475
Chris@159 1476 bool showLabel = (rw > 10 &&
Chris@159 1477 paint.fontMetrics().width("0.000000") < rw - 3 &&
Chris@54 1478 paint.fontMetrics().height() < (h / sh));
Chris@98 1479
Chris@444 1480 for (int sy = symin; sy < symax; ++sy) {
Chris@0 1481
Chris@903 1482 int ry0 = getIYForBin(v, sy);
Chris@903 1483 int ry1 = getIYForBin(v, sy + 1);
Chris@534 1484 QRect r(rx0, ry1, rw, ry0 - ry1);
Chris@534 1485
Chris@0 1486 QRgb pixel = qRgb(255, 255, 255);
Chris@461 1487 if (sx >= 0 && sx < m_cache->width() &&
Chris@0 1488 sy >= 0 && sy < m_cache->height()) {
Chris@461 1489 pixel = m_cache->pixel(sx, sy);
Chris@0 1490 }
Chris@0 1491
Chris@159 1492 if (rw == 1) {
Chris@159 1493 paint.setPen(pixel);
Chris@159 1494 paint.setBrush(Qt::NoBrush);
Chris@159 1495 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
Chris@159 1496 continue;
Chris@159 1497 }
Chris@159 1498
Chris@0 1499 QColor pen(255, 255, 255, 80);
Chris@0 1500 QColor brush(pixel);
Chris@159 1501
Chris@159 1502 if (rw > 3 && r.height() > 3) {
Chris@159 1503 brush.setAlpha(160);
Chris@159 1504 }
Chris@159 1505
Chris@0 1506 paint.setPen(Qt::NoPen);
Chris@0 1507 paint.setBrush(brush);
Chris@0 1508
Chris@25 1509 if (illuminate) {
Chris@25 1510 if (r.contains(illuminatePos)) {
Chris@287 1511 paint.setPen(v->getForeground());
Chris@25 1512 }
Chris@25 1513 }
Chris@76 1514
Chris@125 1515 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@682 1516 // cerr << "rect " << r.x() << "," << r.y() << " "
Chris@682 1517 // << r.width() << "x" << r.height() << endl;
Chris@125 1518 #endif
Chris@25 1519
Chris@25 1520 paint.drawRect(r);
Chris@0 1521
Chris@54 1522 if (showLabel) {
Chris@461 1523 if (sx >= 0 && sx < m_cache->width() &&
Chris@54 1524 sy >= 0 && sy < m_cache->height()) {
Chris@904 1525 double value = m_model->getValueAt(sx, sy);
Chris@864 1526 snprintf(labelbuf, buflen, "%06f", value);
Chris@54 1527 QString text(labelbuf);
Chris@1078 1528 PaintAssistant::drawVisibleText
Chris@1078 1529 (v,
Chris@1078 1530 paint,
Chris@1048 1531 rx0 + 2,
Chris@1048 1532 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
Chris@1048 1533 text,
Chris@1078 1534 PaintAssistant::OutlinedText);
Chris@0 1535 }
Chris@0 1536 }
Chris@0 1537 }
Chris@0 1538 }
Chris@98 1539 }
Chris@0 1540
Chris@98 1541 void
Chris@916 1542 Colour3DPlotLayer::paintDense(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@98 1543 {
Chris@812 1544 Profiler profiler("Colour3DPlotLayer::paintDense", true);
Chris@463 1545 if (!m_cache) return;
Chris@463 1546
Chris@903 1547 double modelStart = double(m_model->getStartFrame());
Chris@903 1548 double modelResolution = double(m_model->getResolution());
Chris@0 1549
Chris@903 1550 sv_samplerate_t mmsr = v->getViewManager()->getMainModelSampleRate();
Chris@903 1551 sv_samplerate_t msr = m_model->getSampleRate();
Chris@903 1552 double srRatio = mmsr / msr;
Chris@159 1553
Chris@98 1554 int x0 = rect.left();
Chris@98 1555 int x1 = rect.right() + 1;
Chris@0 1556
Chris@470 1557 const int w = x1 - x0; // const so it can be used as array size below
Chris@916 1558 int h = v->getPaintHeight(); // we always paint full height
Chris@160 1559 int sh = m_model->getHeight();
Chris@98 1560
Chris@444 1561 int symin = m_miny;
Chris@444 1562 int symax = m_maxy;
Chris@444 1563 if (symax <= symin) {
Chris@444 1564 symin = 0;
Chris@444 1565 symax = sh;
Chris@444 1566 }
Chris@444 1567 if (symin < 0) symin = 0;
Chris@444 1568 if (symax > sh) symax = sh;
Chris@444 1569
Chris@466 1570 QImage img(w, h, QImage::Format_Indexed8);
Chris@466 1571 img.setColorTable(m_cache->colorTable());
Chris@98 1572
Chris@466 1573 uchar *peaks = new uchar[w];
Chris@466 1574 memset(peaks, 0, w);
Chris@98 1575
Chris@469 1576 int zoomLevel = v->getZoomLevel();
Chris@469 1577
Chris@469 1578 QImage *source = m_cache;
Chris@812 1579
Chris@812 1580 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1581 cerr << "modelResolution " << modelResolution << ", srRatio "
Chris@812 1582 << srRatio << ", m_peakResolution " << m_peakResolution
Chris@812 1583 << ", zoomLevel " << zoomLevel << ", result "
Chris@812 1584 << ((modelResolution * srRatio * m_peakResolution) / zoomLevel)
Chris@812 1585 << endl;
Chris@812 1586 #endif
Chris@474 1587
Chris@474 1588 if (m_peaksCache) {
Chris@474 1589 if (((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
Chris@812 1590 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1591 cerr << "using peaks cache" << endl;
Chris@812 1592 #endif
Chris@474 1593 source = m_peaksCache;
Chris@474 1594 modelResolution *= m_peakResolution;
Chris@474 1595 } else {
Chris@812 1596 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1597 cerr << "not using peaks cache" << endl;
Chris@812 1598 #endif
Chris@474 1599 }
Chris@469 1600 } else {
Chris@812 1601 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1602 cerr << "have no peaks cache" << endl;
Chris@812 1603 #endif
Chris@469 1604 }
Chris@469 1605
Chris@469 1606 int sw = source->width();
Chris@470 1607
Chris@903 1608 sv_frame_t xf = -1;
Chris@903 1609 sv_frame_t nxf = v->getFrameForX(x0);
Chris@470 1610
Chris@903 1611 double epsilon = 0.000001;
Chris@535 1612
Chris@903 1613 vector<double> sxa(w*2);
Chris@903 1614
Chris@470 1615 for (int x = 0; x < w; ++x) {
Chris@470 1616
Chris@470 1617 xf = nxf;
Chris@470 1618 nxf = xf + zoomLevel;
Chris@470 1619
Chris@903 1620 double sx0 = (double(xf) / srRatio - modelStart) / modelResolution;
Chris@903 1621 double sx1 = (double(nxf) / srRatio - modelStart) / modelResolution;
Chris@470 1622
Chris@535 1623 sxa[x*2] = sx0;
Chris@535 1624 sxa[x*2 + 1] = sx1;
Chris@470 1625 }
Chris@466 1626
Chris@904 1627 double logmin = symin+1, logmax = symax+1;
Chris@532 1628 LogRange::mapRange(logmin, logmax);
Chris@532 1629
Chris@812 1630 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1631 cerr << "m_smooth = " << m_smooth << ", w = " << w << ", h = " << h << endl;
Chris@812 1632 #endif
Chris@812 1633
Chris@535 1634 if (m_smooth) {
Chris@535 1635
Chris@535 1636 for (int y = 0; y < h; ++y) {
Chris@466 1637
Chris@904 1638 double sy = getBinForY(v, y) - 0.5;
Chris@535 1639 int syi = int(sy + epsilon);
Chris@535 1640 if (syi < 0 || syi >= source->height()) continue;
Chris@531 1641
Chris@535 1642 uchar *targetLine = img.scanLine(y);
Chris@535 1643 uchar *sourceLine = source->scanLine(syi);
Chris@535 1644 uchar *nextSource;
Chris@535 1645 if (syi + 1 < source->height()) {
Chris@535 1646 nextSource = source->scanLine(syi + 1);
Chris@535 1647 } else {
Chris@535 1648 nextSource = sourceLine;
Chris@535 1649 }
Chris@466 1650
Chris@466 1651 for (int x = 0; x < w; ++x) {
Chris@98 1652
Chris@535 1653 targetLine[x] = 0;
Chris@474 1654
Chris@903 1655 double sx0 = sxa[x*2];
Chris@537 1656 if (sx0 < 0) continue;
Chris@535 1657 int sx0i = int(sx0 + epsilon);
Chris@474 1658 if (sx0i >= sw) break;
Chris@98 1659
Chris@903 1660 double a = sourceLine[sx0i];
Chris@903 1661 double b = a;
Chris@903 1662 double value;
Chris@535 1663
Chris@903 1664 double sx1 = sxa[x*2+1];
Chris@535 1665 if (sx1 > sx0 + 1.f) {
Chris@535 1666 int sx1i = int(sx1);
Chris@535 1667 bool have = false;
Chris@535 1668 for (int sx = sx0i; sx <= sx1i; ++sx) {
Chris@535 1669 if (sx < 0 || sx >= sw) continue;
Chris@535 1670 if (!have) {
Chris@903 1671 a = sourceLine[sx];
Chris@903 1672 b = nextSource[sx];
Chris@535 1673 have = true;
Chris@535 1674 } else {
Chris@903 1675 a = std::max(a, double(sourceLine[sx]));
Chris@903 1676 b = std::max(b, double(nextSource[sx]));
Chris@535 1677 }
Chris@535 1678 }
Chris@903 1679 double yprop = sy - syi;
Chris@535 1680 value = (a * (1.f - yprop) + b * yprop);
Chris@535 1681 } else {
Chris@903 1682 a = sourceLine[sx0i];
Chris@903 1683 b = nextSource[sx0i];
Chris@903 1684 double yprop = sy - syi;
Chris@535 1685 value = (a * (1.f - yprop) + b * yprop);
Chris@535 1686 int oi = sx0i + 1;
Chris@903 1687 double xprop = sx0 - sx0i;
Chris@535 1688 xprop -= 0.5;
Chris@535 1689 if (xprop < 0) {
Chris@535 1690 oi = sx0i - 1;
Chris@535 1691 xprop = -xprop;
Chris@535 1692 }
Chris@535 1693 if (oi < 0 || oi >= sw) oi = sx0i;
Chris@903 1694 a = sourceLine[oi];
Chris@903 1695 b = nextSource[oi];
Chris@535 1696 value = (value * (1.f - xprop) +
Chris@535 1697 (a * (1.f - yprop) + b * yprop) * xprop);
Chris@98 1698 }
Chris@535 1699
Chris@903 1700 int vi = int(lrint(value));
Chris@535 1701 if (vi > 255) vi = 255;
Chris@535 1702 if (vi < 0) vi = 0;
Chris@535 1703 targetLine[x] = uchar(vi);
Chris@98 1704 }
Chris@466 1705 }
Chris@535 1706 } else {
Chris@535 1707
Chris@904 1708 double sy0 = getBinForY(v, 0);
Chris@812 1709
Chris@812 1710 int psy0i = -1, psy1i = -1;
Chris@812 1711
Chris@535 1712 for (int y = 0; y < h; ++y) {
Chris@535 1713
Chris@904 1714 double sy1 = sy0;
Chris@904 1715 sy0 = getBinForY(v, double(y + 1));
Chris@535 1716
Chris@535 1717 int sy0i = int(sy0 + epsilon);
Chris@535 1718 int sy1i = int(sy1);
Chris@535 1719
Chris@535 1720 uchar *targetLine = img.scanLine(y);
Chris@535 1721
Chris@812 1722 if (sy0i == psy0i && sy1i == psy1i) {
Chris@812 1723 // same source scan line as just computed
Chris@535 1724 goto copy;
Chris@535 1725 }
Chris@535 1726
Chris@812 1727 psy0i = sy0i;
Chris@812 1728 psy1i = sy1i;
Chris@812 1729
Chris@535 1730 for (int x = 0; x < w; ++x) {
Chris@535 1731 peaks[x] = 0;
Chris@535 1732 }
Chris@466 1733
Chris@535 1734 for (int sy = sy0i; sy <= sy1i; ++sy) {
Chris@535 1735
Chris@535 1736 if (sy < 0 || sy >= source->height()) continue;
Chris@535 1737
Chris@535 1738 uchar *sourceLine = source->scanLine(sy);
Chris@535 1739
Chris@535 1740 for (int x = 0; x < w; ++x) {
Chris@535 1741
Chris@903 1742 double sx1 = sxa[x*2 + 1];
Chris@537 1743 if (sx1 < 0) continue;
Chris@537 1744 int sx1i = int(sx1);
Chris@535 1745
Chris@903 1746 double sx0 = sxa[x*2];
Chris@537 1747 if (sx0 < 0) continue;
Chris@537 1748 int sx0i = int(sx0 + epsilon);
Chris@535 1749 if (sx0i >= sw) break;
Chris@535 1750
Chris@535 1751 uchar peak = 0;
Chris@535 1752 for (int sx = sx0i; sx <= sx1i; ++sx) {
Chris@535 1753 if (sx < 0 || sx >= sw) continue;
Chris@535 1754 if (sourceLine[sx] > peak) peak = sourceLine[sx];
Chris@535 1755 }
Chris@535 1756 peaks[x] = peak;
Chris@535 1757 }
Chris@535 1758 }
Chris@535 1759
Chris@535 1760 copy:
Chris@535 1761 for (int x = 0; x < w; ++x) {
Chris@535 1762 targetLine[x] = peaks[x];
Chris@535 1763 }
Chris@98 1764 }
Chris@0 1765 }
Chris@0 1766
Chris@469 1767 delete[] peaks;
Chris@469 1768
Chris@98 1769 paint.drawImage(x0, 0, img);
Chris@0 1770 }
Chris@0 1771
Chris@28 1772 bool
Chris@916 1773 Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@805 1774 int &resolution,
Chris@28 1775 SnapType snap) const
Chris@24 1776 {
Chris@24 1777 if (!m_model) {
Chris@44 1778 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@24 1779 }
Chris@24 1780
Chris@130 1781 resolution = m_model->getResolution();
Chris@904 1782 sv_frame_t left = (frame / resolution) * resolution;
Chris@904 1783 sv_frame_t right = left + resolution;
Chris@28 1784
Chris@28 1785 switch (snap) {
Chris@28 1786 case SnapLeft: frame = left; break;
Chris@28 1787 case SnapRight: frame = right; break;
Chris@28 1788 case SnapNearest:
Chris@28 1789 case SnapNeighbouring:
Chris@28 1790 if (frame - left > right - frame) frame = right;
Chris@28 1791 else frame = left;
Chris@28 1792 break;
Chris@28 1793 }
Chris@24 1794
Chris@28 1795 return true;
Chris@24 1796 }
Chris@24 1797
Chris@1099 1798 static ColourScale::Scale
Chris@1099 1799 convertInColourScale(int fileScale)
Chris@1099 1800 {
Chris@1099 1801 //!!! this is very badly handled, switching the enum directly for
Chris@1099 1802 //!!! the ColourScale one did not work out well!
Chris@1099 1803
Chris@1099 1804 switch (fileScale) {
Chris@1099 1805 default:
Chris@1099 1806 case 0: return ColourScale::LinearColourScale;
Chris@1099 1807 case 1: return ColourScale::LogColourScale;
Chris@1099 1808 case 2: return ColourScale::PlusMinusOneScale;
Chris@1099 1809 case 3: return ColourScale::AbsoluteScale;
Chris@1099 1810 }
Chris@1099 1811 }
Chris@1099 1812
Chris@1099 1813 static int
Chris@1099 1814 convertOutColourScale(ColourScale::Scale scale)
Chris@1099 1815 {
Chris@1099 1816 switch (scale) {
Chris@1099 1817 case ColourScale::LinearColourScale: return 0;
Chris@1099 1818 case ColourScale::LogColourScale: return 1;
Chris@1099 1819 case ColourScale::PlusMinusOneScale: return 2;
Chris@1099 1820 case ColourScale::AbsoluteScale: return 3;
Chris@1099 1821
Chris@1099 1822 case ColourScale::MeterColourScale:
Chris@1099 1823 case ColourScale::PhaseColourScale:
Chris@1099 1824 default: return 0;
Chris@1099 1825 }
Chris@1099 1826 }
Chris@1099 1827
Chris@316 1828 void
Chris@316 1829 Colour3DPlotLayer::toXml(QTextStream &stream,
Chris@316 1830 QString indent, QString extraAttributes) const
Chris@197 1831 {
Chris@316 1832 QString s = QString("scale=\"%1\" "
Chris@316 1833 "colourScheme=\"%2\" "
Chris@1099 1834 "minY=\"%3\" "
Chris@1099 1835 "maxY=\"%4\" "
Chris@1099 1836 "invertVertical=\"%5\" "
Chris@1099 1837 "opaque=\"%6\" %7")
Chris@1099 1838 .arg(convertOutColourScale(m_colourScale))
Chris@197 1839 .arg(m_colourMap)
Chris@445 1840 .arg(m_miny)
Chris@465 1841 .arg(m_maxy)
Chris@465 1842 .arg(m_invertVertical ? "true" : "false")
Chris@534 1843 .arg(m_opaque ? "true" : "false")
Chris@536 1844 .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
Chris@535 1845 .arg((int)m_binScale)
Chris@536 1846 .arg(m_smooth ? "true" : "false")
Chris@536 1847 .arg(m_gain));
Chris@535 1848
Chris@1099 1849 // New-style normalization attributes, allowing for more types of
Chris@1099 1850 // normalization in future: write out the column normalization
Chris@1099 1851 // type separately, and then whether we are normalizing visible
Chris@1099 1852 // area as well afterwards
Chris@1099 1853
Chris@1099 1854 s += QString("columnNormalization=\"%1\" ")
Chris@1099 1855 .arg(m_normalization == ColumnOp::NormalizeColumns ? "peak" :
Chris@1099 1856 m_normalization == ColumnOp::NormalizeHybrid ? "hybrid" : "none");
Chris@1099 1857
Chris@1099 1858 // Old-style normalization attribute, for backward compatibility
Chris@1099 1859
Chris@1099 1860 s += QString("normalizeColumns=\"%1\" ")
Chris@1099 1861 .arg(m_normalization == ColumnOp::NormalizeColumns ? "true" : "false");
Chris@1099 1862
Chris@1099 1863 // And this applies to both old- and new-style attributes
Chris@1099 1864
Chris@1099 1865 s += QString("normalizeVisibleArea=\"%1\" ")
Chris@1099 1866 .arg(m_normalization == ColumnOp::NormalizeVisibleArea ? "true" : "false");
Chris@1099 1867
Chris@316 1868 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@197 1869 }
Chris@197 1870
Chris@197 1871 void
Chris@197 1872 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
Chris@197 1873 {
Chris@445 1874 bool ok = false, alsoOk = false;
Chris@197 1875
Chris@1099 1876 ColourScale::Scale colourScale = convertInColourScale
Chris@1099 1877 (attributes.value("colourScale").toInt(&ok));
Chris@1099 1878 if (ok) setColourScale(colourScale);
Chris@197 1879
Chris@197 1880 int colourMap = attributes.value("colourScheme").toInt(&ok);
Chris@197 1881 if (ok) setColourMap(colourMap);
Chris@197 1882
Chris@1099 1883 Colour3DPlotRenderer::BinScale binScale = (Colour3DPlotRenderer::BinScale)
Chris@1099 1884 attributes.value("binScale").toInt(&ok);
Chris@1099 1885 if (ok) setBinScale(binScale);
Chris@445 1886
Chris@465 1887 bool invertVertical =
Chris@465 1888 (attributes.value("invertVertical").trimmed() == "true");
Chris@465 1889 setInvertVertical(invertVertical);
Chris@465 1890
Chris@465 1891 bool opaque =
Chris@465 1892 (attributes.value("opaque").trimmed() == "true");
Chris@535 1893 setOpaque(opaque);
Chris@535 1894
Chris@535 1895 bool smooth =
Chris@535 1896 (attributes.value("smooth").trimmed() == "true");
Chris@535 1897 setSmooth(smooth);
Chris@465 1898
Chris@536 1899 float gain = attributes.value("gain").toFloat(&ok);
Chris@536 1900 if (ok) setGain(gain);
Chris@536 1901
Chris@445 1902 float min = attributes.value("minY").toFloat(&ok);
Chris@445 1903 float max = attributes.value("maxY").toFloat(&alsoOk);
Chris@445 1904 if (ok && alsoOk) setDisplayExtents(min, max);
Chris@1099 1905
Chris@1099 1906 bool haveNewStyleNormalization = false;
Chris@1099 1907
Chris@1099 1908 QString columnNormalization = attributes.value("columnNormalization");
Chris@1099 1909
Chris@1099 1910 if (columnNormalization != "") {
Chris@1099 1911
Chris@1099 1912 haveNewStyleNormalization = true;
Chris@1099 1913
Chris@1099 1914 if (columnNormalization == "peak") {
Chris@1099 1915 setNormalization(ColumnOp::NormalizeColumns);
Chris@1099 1916 } else if (columnNormalization == "hybrid") {
Chris@1099 1917 setNormalization(ColumnOp::NormalizeHybrid);
Chris@1099 1918 } else if (columnNormalization == "none") {
Chris@1099 1919 // do nothing
Chris@1099 1920 } else {
Chris@1099 1921 cerr << "NOTE: Unknown or unsupported columnNormalization attribute \""
Chris@1099 1922 << columnNormalization << "\"" << endl;
Chris@1099 1923 }
Chris@1099 1924 }
Chris@1099 1925
Chris@1099 1926 if (!haveNewStyleNormalization) {
Chris@1099 1927
Chris@1099 1928 bool normalizeColumns =
Chris@1099 1929 (attributes.value("normalizeColumns").trimmed() == "true");
Chris@1099 1930 if (normalizeColumns) {
Chris@1099 1931 setNormalization(ColumnOp::NormalizeColumns);
Chris@1099 1932 }
Chris@1099 1933
Chris@1099 1934 bool normalizeHybrid =
Chris@1099 1935 (attributes.value("normalizeHybrid").trimmed() == "true");
Chris@1099 1936 if (normalizeHybrid) {
Chris@1099 1937 setNormalization(ColumnOp::NormalizeHybrid);
Chris@1099 1938 }
Chris@1099 1939 }
Chris@1099 1940
Chris@1099 1941 bool normalizeVisibleArea =
Chris@1099 1942 (attributes.value("normalizeVisibleArea").trimmed() == "true");
Chris@1099 1943 if (normalizeVisibleArea) {
Chris@1099 1944 setNormalization(ColumnOp::NormalizeVisibleArea);
Chris@1099 1945 }
Chris@1099 1946
Chris@1099 1947 //!!! todo: check save/reload scaling, compare with
Chris@1099 1948 //!!! SpectrogramLayer, compare with prior SV versions, compare
Chris@1099 1949 //!!! with Tony v1 and v2 and their save files
Chris@197 1950 }
Chris@197 1951