annotate layer/Colour3DPlotLayer.cpp @ 1064:77564d4fff43 spectrogram-minor-refactor

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