annotate layer/Colour3DPlotLayer.cpp @ 1024:3bce4c45b681 spectrogram-minor-refactor

Rearrange cache update calculations so as to use the actual painted width returned by paint functions (though they only ever return the same width as requested, at this point)
author Chris Cannam
date Mon, 25 Jan 2016 15:52:26 +0000
parents 25ec2390fad3
children 40480e4bab6a
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@973 852 font.setPixelSize(int(font.pixelSize() * 0.65));
Chris@446 853 paint.setFont(font);
Chris@446 854
Chris@446 855 int msw = paint.fontMetrics().width(maxstr);
Chris@446 856
Chris@446 857 QMatrix m;
Chris@446 858 m.translate(cw - 6, ch + 10);
Chris@446 859 m.rotate(-90);
Chris@446 860
Chris@446 861 paint.setWorldMatrix(m);
Chris@446 862
Chris@446 863 v->drawVisibleText(paint, 2, 0, minstr, View::OutlinedText);
Chris@446 864
Chris@446 865 m.translate(ch - msw - 2, 0);
Chris@446 866 paint.setWorldMatrix(m);
Chris@446 867
Chris@446 868 v->drawVisibleText(paint, 0, 0, maxstr, View::OutlinedText);
Chris@446 869
Chris@446 870 paint.restore();
Chris@159 871 }
Chris@159 872
Chris@287 873 paint.setPen(v->getForeground());
Chris@159 874
Chris@445 875 int sh = m_model->getHeight();
Chris@445 876
Chris@445 877 int symin = m_miny;
Chris@445 878 int symax = m_maxy;
Chris@445 879 if (symax <= symin) {
Chris@445 880 symin = 0;
Chris@445 881 symax = sh;
Chris@445 882 }
Chris@445 883 if (symin < 0) symin = 0;
Chris@445 884 if (symax > sh) symax = sh;
Chris@445 885
Chris@532 886 paint.save();
Chris@456 887
Chris@533 888 int py = h;
Chris@25 889
Chris@969 890 int defaultFontHeight = paint.fontMetrics().height();
Chris@969 891
Chris@805 892 for (int i = symin; i <= symax; ++i) {
Chris@98 893
Chris@532 894 int y0;
Chris@534 895
Chris@903 896 y0 = getIYForBin(v, i);
Chris@532 897 int h = py - y0;
Chris@532 898
Chris@532 899 if (i > symin) {
Chris@532 900 if (paint.fontMetrics().height() >= h) {
Chris@969 901 if (h >= defaultFontHeight * 0.8) {
Chris@532 902 QFont tf = paint.font();
Chris@973 903 tf.setPixelSize(int(h * 0.8));
Chris@532 904 paint.setFont(tf);
Chris@532 905 } else {
Chris@532 906 continue;
Chris@532 907 }
Chris@532 908 }
Chris@532 909 }
Chris@25 910
Chris@532 911 py = y0;
Chris@532 912
Chris@534 913 if (i < symax) {
Chris@534 914 paint.drawLine(cw, y0, w, y0);
Chris@534 915 }
Chris@25 916
Chris@532 917 if (i > symin) {
Chris@534 918
Chris@805 919 int idx = i - 1;
Chris@534 920 if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
Chris@534 921
Chris@534 922 QString text = m_model->getBinName(idx);
Chris@534 923 if (text == "") text = QString("[%1]").arg(idx + 1);
Chris@534 924
Chris@534 925 int ty = y0 + (h/2) - (paint.fontMetrics().height()/2) +
Chris@534 926 paint.fontMetrics().ascent() + 1;
Chris@534 927
Chris@534 928 paint.drawText(cw + 5, ty, text);
Chris@457 929 }
Chris@25 930 }
Chris@456 931
Chris@456 932 paint.restore();
Chris@25 933 }
Chris@25 934
Chris@467 935 DenseThreeDimensionalModel::Column
Chris@805 936 Colour3DPlotLayer::getColumn(int col) const
Chris@197 937 {
Chris@812 938 Profiler profiler("Colour3DPlotLayer::getColumn");
Chris@812 939
Chris@467 940 DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
Chris@1019 941 values.resize(m_model->getHeight(), 0.f);
Chris@719 942 if (!m_normalizeColumns && !m_normalizeHybrid) return values;
Chris@461 943
Chris@904 944 double colMax = 0.f, colMin = 0.f;
Chris@904 945 double min = 0.f, max = 0.f;
Chris@197 946
Chris@1019 947 int nv = int(values.size());
Chris@1019 948
Chris@461 949 min = m_model->getMinimumLevel();
Chris@461 950 max = m_model->getMaximumLevel();
Chris@461 951
Chris@1019 952 for (int y = 0; y < nv; ++y) {
Chris@467 953 if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
Chris@467 954 if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
Chris@197 955 }
Chris@461 956 if (colMin == colMax) colMax = colMin + 1;
Chris@197 957
Chris@1019 958 for (int y = 0; y < nv; ++y) {
Chris@461 959
Chris@904 960 double value = values.at(y);
Chris@904 961 double norm = (value - colMin) / (colMax - colMin);
Chris@904 962 double newvalue = min + (max - min) * norm;
Chris@197 963
Chris@904 964 if (value != newvalue) values[y] = float(newvalue);
Chris@468 965 }
Chris@468 966
Chris@719 967 if (m_normalizeHybrid && (colMax > 0.0)) {
Chris@904 968 double logmax = log10(colMax);
Chris@1019 969 for (int y = 0; y < nv; ++y) {
Chris@904 970 values[y] = float(values[y] * logmax);
Chris@719 971 }
Chris@719 972 }
Chris@719 973
Chris@468 974 return values;
Chris@197 975 }
Chris@197 976
Chris@197 977 void
Chris@805 978 Colour3DPlotLayer::fillCache(int firstBin, int lastBin) const
Chris@197 979 {
Chris@812 980 Profiler profiler("Colour3DPlotLayer::fillCache", true);
Chris@476 981
Chris@902 982 sv_frame_t modelStart = m_model->getStartFrame();
Chris@902 983 sv_frame_t modelEnd = m_model->getEndFrame();
Chris@805 984 int modelResolution = m_model->getResolution();
Chris@197 985
Chris@902 986 int modelStartBin = int(modelStart / modelResolution);
Chris@902 987 int modelEndBin = int(modelEnd / modelResolution);
Chris@461 988
Chris@812 989 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 990 cerr << "Colour3DPlotLayer::fillCache: range " << firstBin << " -> " << lastBin << " of model range " << modelStartBin << " -> " << modelEndBin << " (model resolution " << modelResolution << ")" << endl;
Chris@812 991 #endif
Chris@812 992
Chris@805 993 int cacheWidth = modelEndBin - modelStartBin + 1;
Chris@471 994 if (lastBin > modelEndBin) cacheWidth = lastBin - modelStartBin + 1;
Chris@805 995 int cacheHeight = m_model->getHeight();
Chris@461 996
Chris@812 997 if (m_cache && m_cache->height() != cacheHeight) {
Chris@742 998 // height has changed: delete everything rather than resizing
Chris@812 999 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1000 cerr << "Colour3DPlotLayer::fillCache: Cache height has changed, recreating" << endl;
Chris@812 1001 #endif
Chris@461 1002 delete m_cache;
Chris@469 1003 delete m_peaksCache;
Chris@461 1004 m_cache = 0;
Chris@469 1005 m_peaksCache = 0;
Chris@461 1006 }
Chris@461 1007
Chris@812 1008 if (m_cache && m_cache->width() != cacheWidth) {
Chris@742 1009 // width has changed and we have an existing cache: resize it
Chris@812 1010 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1011 cerr << "Colour3DPlotLayer::fillCache: Cache width has changed, resizing existing cache" << endl;
Chris@812 1012 #endif
Chris@469 1013 QImage *newCache =
Chris@469 1014 new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight));
Chris@461 1015 delete m_cache;
Chris@461 1016 m_cache = newCache;
Chris@469 1017 if (m_peaksCache) {
Chris@469 1018 QImage *newPeaksCache =
Chris@469 1019 new QImage(m_peaksCache->copy
Chris@742 1020 (0, 0, cacheWidth / m_peakResolution + 1, cacheHeight));
Chris@469 1021 delete m_peaksCache;
Chris@469 1022 m_peaksCache = newPeaksCache;
Chris@469 1023 }
Chris@197 1024 }
Chris@197 1025
Chris@461 1026 if (!m_cache) {
Chris@812 1027 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1028 cerr << "Colour3DPlotLayer::fillCache: Have no cache, making one" << endl;
Chris@812 1029 #endif
Chris@469 1030 m_cache = new QImage
Chris@469 1031 (cacheWidth, cacheHeight, QImage::Format_Indexed8);
Chris@812 1032 m_cache->setColorCount(256);
Chris@514 1033 m_cache->fill(0);
Chris@474 1034 if (!m_normalizeVisibleArea) {
Chris@469 1035 m_peaksCache = new QImage
Chris@469 1036 (cacheWidth / m_peakResolution + 1, cacheHeight,
Chris@469 1037 QImage::Format_Indexed8);
Chris@812 1038 m_peaksCache->setColorCount(256);
Chris@514 1039 m_peaksCache->fill(0);
Chris@469 1040 } else if (m_peaksCache) {
Chris@469 1041 delete m_peaksCache;
Chris@469 1042 m_peaksCache = 0;
Chris@469 1043 }
Chris@461 1044 m_cacheValidStart = 0;
Chris@461 1045 m_cacheValidEnd = 0;
Chris@197 1046 }
Chris@197 1047
Chris@812 1048 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1049 cerr << "cache size = " << m_cache->width() << "x" << m_cache->height()
Chris@812 1050 << " peaks cache size = " << m_peaksCache->width() << "x" << m_peaksCache->height() << endl;
Chris@812 1051 #endif
Chris@742 1052
Chris@461 1053 if (m_cacheValidStart <= firstBin && m_cacheValidEnd >= lastBin) {
Chris@519 1054 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@682 1055 cerr << "Cache is valid in this region already" << endl;
Chris@519 1056 #endif
Chris@461 1057 return;
Chris@461 1058 }
Chris@461 1059
Chris@805 1060 int fillStart = firstBin;
Chris@805 1061 int fillEnd = lastBin;
Chris@197 1062
Chris@461 1063 if (fillStart < modelStartBin) fillStart = modelStartBin;
Chris@461 1064 if (fillStart > modelEndBin) fillStart = modelEndBin;
Chris@461 1065 if (fillEnd < modelStartBin) fillEnd = modelStartBin;
Chris@461 1066 if (fillEnd > modelEndBin) fillEnd = modelEndBin;
Chris@197 1067
Chris@461 1068 bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns);
Chris@197 1069
Chris@461 1070 if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) {
Chris@461 1071
Chris@461 1072 if (m_cacheValidEnd < fillStart) {
Chris@461 1073 fillStart = m_cacheValidEnd + 1;
Chris@461 1074 }
Chris@461 1075 if (m_cacheValidStart > fillEnd) {
Chris@461 1076 fillEnd = m_cacheValidStart - 1;
Chris@461 1077 }
Chris@461 1078
Chris@461 1079 m_cacheValidStart = std::min(fillStart, m_cacheValidStart);
Chris@461 1080 m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd);
Chris@461 1081
Chris@461 1082 } else {
Chris@461 1083
Chris@812 1084 // when normalising the visible area, the only valid area,
Chris@812 1085 // ever, is the currently visible one
Chris@461 1086
Chris@461 1087 m_cacheValidStart = fillStart;
Chris@461 1088 m_cacheValidEnd = fillEnd;
Chris@461 1089 }
Chris@461 1090
Chris@519 1091 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1092 cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << " (fillStart = " << fillStart << ", fillEnd = " << fillEnd << ")" << endl;
Chris@519 1093 #endif
Chris@461 1094
Chris@197 1095 DenseThreeDimensionalModel::Column values;
Chris@197 1096
Chris@904 1097 double min = m_model->getMinimumLevel();
Chris@904 1098 double max = m_model->getMaximumLevel();
Chris@197 1099
Chris@197 1100 if (m_colourScale == LogScale) {
Chris@197 1101 LogRange::mapRange(min, max);
Chris@197 1102 } else if (m_colourScale == PlusMinusOneScale) {
Chris@197 1103 min = -1.f;
Chris@197 1104 max = 1.f;
Chris@509 1105 } else if (m_colourScale == AbsoluteScale) {
Chris@509 1106 if (min < 0) {
Chris@904 1107 if (fabs(min) > fabs(max)) max = fabs(min);
Chris@904 1108 else max = fabs(max);
Chris@509 1109 min = 0;
Chris@509 1110 } else {
Chris@904 1111 min = fabs(min);
Chris@904 1112 max = fabs(max);
Chris@509 1113 }
Chris@197 1114 }
Chris@197 1115
Chris@902 1116 if (max == min) max = min + 1.f;
Chris@197 1117
Chris@197 1118 ColourMapper mapper(m_colourMap, 0.f, 255.f);
Chris@197 1119
Chris@197 1120 for (int index = 0; index < 256; ++index) {
Chris@197 1121 QColor colour = mapper.map(index);
Chris@469 1122 m_cache->setColor
Chris@469 1123 (index, qRgb(colour.red(), colour.green(), colour.blue()));
Chris@469 1124 if (m_peaksCache) {
Chris@469 1125 m_peaksCache->setColor
Chris@469 1126 (index, qRgb(colour.red(), colour.green(), colour.blue()));
Chris@469 1127 }
Chris@197 1128 }
Chris@197 1129
Chris@904 1130 double visibleMax = 0.f, visibleMin = 0.f;
Chris@197 1131
Chris@461 1132 if (normalizeVisible) {
Chris@197 1133
Chris@805 1134 for (int c = fillStart; c <= fillEnd; ++c) {
Chris@197 1135
Chris@467 1136 values = getColumn(c);
Chris@197 1137
Chris@904 1138 double colMax = 0.f, colMin = 0.f;
Chris@197 1139
Chris@805 1140 for (int y = 0; y < cacheHeight; ++y) {
Chris@1019 1141 if (!in_range_for(values, y)) break;
Chris@197 1142 if (y == 0 || values[y] > colMax) colMax = values[y];
Chris@224 1143 if (y == 0 || values[y] < colMin) colMin = values[y];
Chris@197 1144 }
Chris@197 1145
Chris@461 1146 if (c == fillStart || colMax > visibleMax) visibleMax = colMax;
Chris@461 1147 if (c == fillStart || colMin < visibleMin) visibleMin = colMin;
Chris@461 1148 }
Chris@461 1149
Chris@461 1150 if (m_colourScale == LogScale) {
Chris@461 1151 visibleMin = LogRange::map(visibleMin);
Chris@461 1152 visibleMax = LogRange::map(visibleMax);
Chris@461 1153 if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax);
Chris@509 1154 } else if (m_colourScale == AbsoluteScale) {
Chris@509 1155 if (visibleMin < 0) {
Chris@904 1156 if (fabs(visibleMin) > fabs(visibleMax)) visibleMax = fabs(visibleMin);
Chris@904 1157 else visibleMax = fabs(visibleMax);
Chris@509 1158 visibleMin = 0;
Chris@509 1159 } else {
Chris@904 1160 visibleMin = fabs(visibleMin);
Chris@904 1161 visibleMax = fabs(visibleMax);
Chris@509 1162 }
Chris@197 1163 }
Chris@197 1164 }
Chris@197 1165
Chris@224 1166 if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
Chris@224 1167
Chris@469 1168 int *peaks = 0;
Chris@469 1169 if (m_peaksCache) {
Chris@469 1170 peaks = new int[cacheHeight];
Chris@469 1171 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 1172 peaks[y] = 0;
Chris@469 1173 }
Chris@469 1174 }
Chris@469 1175
Chris@812 1176 Profiler profiler2("Colour3DPlotLayer::fillCache: filling", true);
Chris@812 1177
Chris@805 1178 for (int c = fillStart; c <= fillEnd; ++c) {
Chris@197 1179
Chris@467 1180 values = getColumn(c);
Chris@197 1181
Chris@742 1182 if (c >= m_cache->width()) {
Chris@742 1183 cerr << "ERROR: column " << c << " >= cache width "
Chris@742 1184 << m_cache->width() << endl;
Chris@742 1185 continue;
Chris@742 1186 }
Chris@742 1187
Chris@805 1188 for (int y = 0; y < cacheHeight; ++y) {
Chris@197 1189
Chris@904 1190 double value = min;
Chris@1019 1191 if (in_range_for(values, y)) {
Chris@469 1192 value = values.at(y);
Chris@197 1193 }
Chris@224 1194
Chris@534 1195 value = value * m_gain;
Chris@534 1196
Chris@224 1197 if (m_colourScale == LogScale) {
Chris@224 1198 value = LogRange::map(value);
Chris@509 1199 } else if (m_colourScale == AbsoluteScale) {
Chris@904 1200 value = fabs(value);
Chris@197 1201 }
Chris@461 1202
Chris@461 1203 if (normalizeVisible) {
Chris@904 1204 double norm = (value - visibleMin) / (visibleMax - visibleMin);
Chris@461 1205 value = min + (max - min) * norm;
Chris@461 1206 }
Chris@197 1207
Chris@197 1208 int pixel = int(((value - min) * 256) / (max - min));
Chris@197 1209 if (pixel < 0) pixel = 0;
Chris@197 1210 if (pixel > 255) pixel = 255;
Chris@469 1211 if (peaks && (pixel > peaks[y])) peaks[y] = pixel;
Chris@197 1212
Chris@357 1213 if (m_invertVertical) {
Chris@461 1214 m_cache->setPixel(c, cacheHeight - y - 1, pixel);
Chris@357 1215 } else {
Chris@742 1216 if (y >= m_cache->height()) {
Chris@742 1217 cerr << "ERROR: row " << y << " >= cache height " << m_cache->height() << endl;
Chris@742 1218 } else {
Chris@742 1219 m_cache->setPixel(c, y, pixel);
Chris@742 1220 }
Chris@357 1221 }
Chris@197 1222 }
Chris@469 1223
Chris@469 1224 if (peaks) {
Chris@805 1225 int notch = (c % m_peakResolution);
Chris@469 1226 if (notch == m_peakResolution-1 || c == fillEnd) {
Chris@805 1227 int pc = c / m_peakResolution;
Chris@742 1228 if (pc >= m_peaksCache->width()) {
Chris@742 1229 cerr << "ERROR: peak column " << pc
Chris@742 1230 << " (from col " << c << ") >= peaks cache width "
Chris@742 1231 << m_peaksCache->width() << endl;
Chris@742 1232 continue;
Chris@742 1233 }
Chris@805 1234 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 1235 if (m_invertVertical) {
Chris@469 1236 m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]);
Chris@469 1237 } else {
Chris@742 1238 if (y >= m_peaksCache->height()) {
Chris@742 1239 cerr << "ERROR: row " << y
Chris@742 1240 << " >= peaks cache height "
Chris@742 1241 << m_peaksCache->height() << endl;
Chris@742 1242 } else {
Chris@742 1243 m_peaksCache->setPixel(pc, y, peaks[y]);
Chris@742 1244 }
Chris@469 1245 }
Chris@469 1246 }
Chris@469 1247 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 1248 peaks[y] = 0;
Chris@469 1249 }
Chris@469 1250 }
Chris@469 1251 }
Chris@197 1252 }
Chris@469 1253
Chris@469 1254 delete[] peaks;
Chris@197 1255 }
Chris@197 1256
Chris@812 1257 bool
Chris@916 1258 Colour3DPlotLayer::shouldPaintDenseIn(const LayerGeometryProvider *v) const
Chris@812 1259 {
Chris@812 1260 if (!m_model || !v || !(v->getViewManager())) {
Chris@812 1261 return false;
Chris@812 1262 }
Chris@902 1263 double srRatio =
Chris@902 1264 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
Chris@812 1265 if (m_opaque ||
Chris@812 1266 m_smooth ||
Chris@916 1267 m_model->getHeight() >= v->getPaintHeight() ||
Chris@812 1268 ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) {
Chris@812 1269 return true;
Chris@812 1270 }
Chris@812 1271 return false;
Chris@812 1272 }
Chris@812 1273
Chris@197 1274 void
Chris@916 1275 Colour3DPlotLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@0 1276 {
Chris@514 1277 /*
Chris@443 1278 if (m_model) {
Chris@587 1279 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
Chris@443 1280 }
Chris@514 1281 */
Chris@466 1282 Profiler profiler("Colour3DPlotLayer::paint");
Chris@125 1283 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1284 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 1285 #endif
Chris@0 1286
Chris@0 1287 int completion = 0;
Chris@0 1288 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
Chris@0 1289 if (completion > 0) {
Chris@916 1290 paint.fillRect(0, 10, v->getPaintWidth() * completion / 100,
Chris@0 1291 10, QColor(120, 120, 120));
Chris@0 1292 }
Chris@0 1293 return;
Chris@0 1294 }
Chris@0 1295
Chris@916 1296 if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->getPaintRect();
Chris@197 1297
Chris@902 1298 sv_frame_t modelStart = m_model->getStartFrame();
Chris@902 1299 sv_frame_t modelEnd = m_model->getEndFrame();
Chris@805 1300 int modelResolution = m_model->getResolution();
Chris@0 1301
Chris@197 1302 // The cache is from the model's start frame to the model's end
Chris@197 1303 // frame at the model's window increment frames per pixel. We
Chris@197 1304 // want to draw from our start frame + x0 * zoomLevel to our start
Chris@197 1305 // frame + x1 * zoomLevel at zoomLevel frames per pixel.
Chris@12 1306
Chris@197 1307 // We have quite different paint mechanisms for rendering "large"
Chris@197 1308 // bins (more than one bin per pixel in both directions) and
Chris@197 1309 // "small". This is "large"; see paintDense below for "small".
Chris@12 1310
Chris@197 1311 int x0 = rect.left();
Chris@197 1312 int x1 = rect.right() + 1;
Chris@12 1313
Chris@916 1314 int h = v->getPaintHeight();
Chris@0 1315
Chris@902 1316 double srRatio =
Chris@902 1317 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
Chris@0 1318
Chris@902 1319 int sx0 = int((double(v->getFrameForX(x0)) / srRatio - double(modelStart))
Chris@812 1320 / modelResolution);
Chris@902 1321 int sx1 = int((double(v->getFrameForX(x1)) / srRatio - double(modelStart))
Chris@812 1322 / modelResolution);
Chris@197 1323 int sh = m_model->getHeight();
Chris@159 1324
Chris@444 1325 int symin = m_miny;
Chris@444 1326 int symax = m_maxy;
Chris@444 1327 if (symax <= symin) {
Chris@444 1328 symin = 0;
Chris@444 1329 symax = sh;
Chris@444 1330 }
Chris@444 1331 if (symin < 0) symin = 0;
Chris@444 1332 if (symax > sh) symax = sh;
Chris@444 1333
Chris@197 1334 if (sx0 > 0) --sx0;
Chris@197 1335 fillCache(sx0 < 0 ? 0 : sx0,
Chris@197 1336 sx1 < 0 ? 0 : sx1);
Chris@0 1337
Chris@351 1338 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1339 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 1340 #endif
Chris@351 1341
Chris@812 1342 if (shouldPaintDenseIn(v)) {
Chris@347 1343 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1344 cerr << "calling paintDense" << endl;
Chris@347 1345 #endif
Chris@98 1346 paintDense(v, paint, rect);
Chris@98 1347 return;
Chris@98 1348 }
Chris@98 1349
Chris@125 1350 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1351 cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << endl;
Chris@682 1352 cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << endl;
Chris@125 1353 #endif
Chris@0 1354
Chris@25 1355 QPoint illuminatePos;
Chris@44 1356 bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
Chris@864 1357
Chris@864 1358 const int buflen = 40;
Chris@864 1359 char labelbuf[buflen];
Chris@25 1360
Chris@197 1361 for (int sx = sx0; sx <= sx1; ++sx) {
Chris@0 1362
Chris@902 1363 sv_frame_t fx = sx * modelResolution;
Chris@0 1364
Chris@812 1365 if (fx + modelResolution <= modelStart || fx > modelEnd) continue;
Chris@0 1366
Chris@902 1367 int rx0 = v->getXForFrame(int(double(fx + modelStart) * srRatio));
Chris@902 1368 int rx1 = v->getXForFrame(int(double(fx + modelStart + modelResolution + 1) * srRatio));
Chris@54 1369
Chris@159 1370 int rw = rx1 - rx0;
Chris@159 1371 if (rw < 1) rw = 1;
Chris@54 1372
Chris@159 1373 bool showLabel = (rw > 10 &&
Chris@159 1374 paint.fontMetrics().width("0.000000") < rw - 3 &&
Chris@54 1375 paint.fontMetrics().height() < (h / sh));
Chris@98 1376
Chris@444 1377 for (int sy = symin; sy < symax; ++sy) {
Chris@0 1378
Chris@903 1379 int ry0 = getIYForBin(v, sy);
Chris@903 1380 int ry1 = getIYForBin(v, sy + 1);
Chris@534 1381 QRect r(rx0, ry1, rw, ry0 - ry1);
Chris@534 1382
Chris@0 1383 QRgb pixel = qRgb(255, 255, 255);
Chris@461 1384 if (sx >= 0 && sx < m_cache->width() &&
Chris@0 1385 sy >= 0 && sy < m_cache->height()) {
Chris@461 1386 pixel = m_cache->pixel(sx, sy);
Chris@0 1387 }
Chris@0 1388
Chris@159 1389 if (rw == 1) {
Chris@159 1390 paint.setPen(pixel);
Chris@159 1391 paint.setBrush(Qt::NoBrush);
Chris@159 1392 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
Chris@159 1393 continue;
Chris@159 1394 }
Chris@159 1395
Chris@0 1396 QColor pen(255, 255, 255, 80);
Chris@0 1397 QColor brush(pixel);
Chris@159 1398
Chris@159 1399 if (rw > 3 && r.height() > 3) {
Chris@159 1400 brush.setAlpha(160);
Chris@159 1401 }
Chris@159 1402
Chris@0 1403 paint.setPen(Qt::NoPen);
Chris@0 1404 paint.setBrush(brush);
Chris@0 1405
Chris@25 1406 if (illuminate) {
Chris@25 1407 if (r.contains(illuminatePos)) {
Chris@287 1408 paint.setPen(v->getForeground());
Chris@25 1409 }
Chris@25 1410 }
Chris@76 1411
Chris@125 1412 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@682 1413 // cerr << "rect " << r.x() << "," << r.y() << " "
Chris@682 1414 // << r.width() << "x" << r.height() << endl;
Chris@125 1415 #endif
Chris@25 1416
Chris@25 1417 paint.drawRect(r);
Chris@0 1418
Chris@54 1419 if (showLabel) {
Chris@461 1420 if (sx >= 0 && sx < m_cache->width() &&
Chris@54 1421 sy >= 0 && sy < m_cache->height()) {
Chris@904 1422 double value = m_model->getValueAt(sx, sy);
Chris@864 1423 snprintf(labelbuf, buflen, "%06f", value);
Chris@54 1424 QString text(labelbuf);
Chris@287 1425 paint.setPen(v->getBackground());
Chris@54 1426 paint.drawText(rx0 + 2,
Chris@54 1427 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
Chris@54 1428 text);
Chris@0 1429 }
Chris@0 1430 }
Chris@0 1431 }
Chris@0 1432 }
Chris@98 1433 }
Chris@0 1434
Chris@98 1435 void
Chris@916 1436 Colour3DPlotLayer::paintDense(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@98 1437 {
Chris@812 1438 Profiler profiler("Colour3DPlotLayer::paintDense", true);
Chris@463 1439 if (!m_cache) return;
Chris@463 1440
Chris@903 1441 double modelStart = double(m_model->getStartFrame());
Chris@903 1442 double modelResolution = double(m_model->getResolution());
Chris@0 1443
Chris@903 1444 sv_samplerate_t mmsr = v->getViewManager()->getMainModelSampleRate();
Chris@903 1445 sv_samplerate_t msr = m_model->getSampleRate();
Chris@903 1446 double srRatio = mmsr / msr;
Chris@159 1447
Chris@98 1448 int x0 = rect.left();
Chris@98 1449 int x1 = rect.right() + 1;
Chris@0 1450
Chris@470 1451 const int w = x1 - x0; // const so it can be used as array size below
Chris@916 1452 int h = v->getPaintHeight(); // we always paint full height
Chris@160 1453 int sh = m_model->getHeight();
Chris@98 1454
Chris@444 1455 int symin = m_miny;
Chris@444 1456 int symax = m_maxy;
Chris@444 1457 if (symax <= symin) {
Chris@444 1458 symin = 0;
Chris@444 1459 symax = sh;
Chris@444 1460 }
Chris@444 1461 if (symin < 0) symin = 0;
Chris@444 1462 if (symax > sh) symax = sh;
Chris@444 1463
Chris@466 1464 QImage img(w, h, QImage::Format_Indexed8);
Chris@466 1465 img.setColorTable(m_cache->colorTable());
Chris@98 1466
Chris@466 1467 uchar *peaks = new uchar[w];
Chris@466 1468 memset(peaks, 0, w);
Chris@98 1469
Chris@469 1470 int zoomLevel = v->getZoomLevel();
Chris@469 1471
Chris@469 1472 QImage *source = m_cache;
Chris@812 1473
Chris@812 1474 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1475 cerr << "modelResolution " << modelResolution << ", srRatio "
Chris@812 1476 << srRatio << ", m_peakResolution " << m_peakResolution
Chris@812 1477 << ", zoomLevel " << zoomLevel << ", result "
Chris@812 1478 << ((modelResolution * srRatio * m_peakResolution) / zoomLevel)
Chris@812 1479 << endl;
Chris@812 1480 #endif
Chris@474 1481
Chris@474 1482 if (m_peaksCache) {
Chris@474 1483 if (((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
Chris@812 1484 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1485 cerr << "using peaks cache" << endl;
Chris@812 1486 #endif
Chris@474 1487 source = m_peaksCache;
Chris@474 1488 modelResolution *= m_peakResolution;
Chris@474 1489 } else {
Chris@812 1490 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1491 cerr << "not using peaks cache" << endl;
Chris@812 1492 #endif
Chris@474 1493 }
Chris@469 1494 } else {
Chris@812 1495 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1496 cerr << "have no peaks cache" << endl;
Chris@812 1497 #endif
Chris@469 1498 }
Chris@469 1499
Chris@469 1500 int sw = source->width();
Chris@470 1501
Chris@903 1502 sv_frame_t xf = -1;
Chris@903 1503 sv_frame_t nxf = v->getFrameForX(x0);
Chris@470 1504
Chris@903 1505 double epsilon = 0.000001;
Chris@535 1506
Chris@903 1507 vector<double> sxa(w*2);
Chris@903 1508
Chris@470 1509 for (int x = 0; x < w; ++x) {
Chris@470 1510
Chris@470 1511 xf = nxf;
Chris@470 1512 nxf = xf + zoomLevel;
Chris@470 1513
Chris@903 1514 double sx0 = (double(xf) / srRatio - modelStart) / modelResolution;
Chris@903 1515 double sx1 = (double(nxf) / srRatio - modelStart) / modelResolution;
Chris@470 1516
Chris@535 1517 sxa[x*2] = sx0;
Chris@535 1518 sxa[x*2 + 1] = sx1;
Chris@470 1519 }
Chris@466 1520
Chris@904 1521 double logmin = symin+1, logmax = symax+1;
Chris@532 1522 LogRange::mapRange(logmin, logmax);
Chris@532 1523
Chris@812 1524 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@812 1525 cerr << "m_smooth = " << m_smooth << ", w = " << w << ", h = " << h << endl;
Chris@812 1526 #endif
Chris@812 1527
Chris@535 1528 if (m_smooth) {
Chris@535 1529
Chris@535 1530 for (int y = 0; y < h; ++y) {
Chris@466 1531
Chris@904 1532 double sy = getBinForY(v, y) - 0.5;
Chris@535 1533 int syi = int(sy + epsilon);
Chris@535 1534 if (syi < 0 || syi >= source->height()) continue;
Chris@531 1535
Chris@535 1536 uchar *targetLine = img.scanLine(y);
Chris@535 1537 uchar *sourceLine = source->scanLine(syi);
Chris@535 1538 uchar *nextSource;
Chris@535 1539 if (syi + 1 < source->height()) {
Chris@535 1540 nextSource = source->scanLine(syi + 1);
Chris@535 1541 } else {
Chris@535 1542 nextSource = sourceLine;
Chris@535 1543 }
Chris@466 1544
Chris@466 1545 for (int x = 0; x < w; ++x) {
Chris@98 1546
Chris@535 1547 targetLine[x] = 0;
Chris@474 1548
Chris@903 1549 double sx0 = sxa[x*2];
Chris@537 1550 if (sx0 < 0) continue;
Chris@535 1551 int sx0i = int(sx0 + epsilon);
Chris@474 1552 if (sx0i >= sw) break;
Chris@98 1553
Chris@903 1554 double a = sourceLine[sx0i];
Chris@903 1555 double b = a;
Chris@903 1556 double value;
Chris@535 1557
Chris@903 1558 double sx1 = sxa[x*2+1];
Chris@535 1559 if (sx1 > sx0 + 1.f) {
Chris@535 1560 int sx1i = int(sx1);
Chris@535 1561 bool have = false;
Chris@535 1562 for (int sx = sx0i; sx <= sx1i; ++sx) {
Chris@535 1563 if (sx < 0 || sx >= sw) continue;
Chris@535 1564 if (!have) {
Chris@903 1565 a = sourceLine[sx];
Chris@903 1566 b = nextSource[sx];
Chris@535 1567 have = true;
Chris@535 1568 } else {
Chris@903 1569 a = std::max(a, double(sourceLine[sx]));
Chris@903 1570 b = std::max(b, double(nextSource[sx]));
Chris@535 1571 }
Chris@535 1572 }
Chris@903 1573 double yprop = sy - syi;
Chris@535 1574 value = (a * (1.f - yprop) + b * yprop);
Chris@535 1575 } else {
Chris@903 1576 a = sourceLine[sx0i];
Chris@903 1577 b = nextSource[sx0i];
Chris@903 1578 double yprop = sy - syi;
Chris@535 1579 value = (a * (1.f - yprop) + b * yprop);
Chris@535 1580 int oi = sx0i + 1;
Chris@903 1581 double xprop = sx0 - sx0i;
Chris@535 1582 xprop -= 0.5;
Chris@535 1583 if (xprop < 0) {
Chris@535 1584 oi = sx0i - 1;
Chris@535 1585 xprop = -xprop;
Chris@535 1586 }
Chris@535 1587 if (oi < 0 || oi >= sw) oi = sx0i;
Chris@903 1588 a = sourceLine[oi];
Chris@903 1589 b = nextSource[oi];
Chris@535 1590 value = (value * (1.f - xprop) +
Chris@535 1591 (a * (1.f - yprop) + b * yprop) * xprop);
Chris@98 1592 }
Chris@535 1593
Chris@903 1594 int vi = int(lrint(value));
Chris@535 1595 if (vi > 255) vi = 255;
Chris@535 1596 if (vi < 0) vi = 0;
Chris@535 1597 targetLine[x] = uchar(vi);
Chris@98 1598 }
Chris@466 1599 }
Chris@535 1600 } else {
Chris@535 1601
Chris@904 1602 double sy0 = getBinForY(v, 0);
Chris@812 1603
Chris@812 1604 int psy0i = -1, psy1i = -1;
Chris@812 1605
Chris@535 1606 for (int y = 0; y < h; ++y) {
Chris@535 1607
Chris@904 1608 double sy1 = sy0;
Chris@904 1609 sy0 = getBinForY(v, double(y + 1));
Chris@535 1610
Chris@535 1611 int sy0i = int(sy0 + epsilon);
Chris@535 1612 int sy1i = int(sy1);
Chris@535 1613
Chris@535 1614 uchar *targetLine = img.scanLine(y);
Chris@535 1615
Chris@812 1616 if (sy0i == psy0i && sy1i == psy1i) {
Chris@812 1617 // same source scan line as just computed
Chris@535 1618 goto copy;
Chris@535 1619 }
Chris@535 1620
Chris@812 1621 psy0i = sy0i;
Chris@812 1622 psy1i = sy1i;
Chris@812 1623
Chris@535 1624 for (int x = 0; x < w; ++x) {
Chris@535 1625 peaks[x] = 0;
Chris@535 1626 }
Chris@466 1627
Chris@535 1628 for (int sy = sy0i; sy <= sy1i; ++sy) {
Chris@535 1629
Chris@535 1630 if (sy < 0 || sy >= source->height()) continue;
Chris@535 1631
Chris@535 1632 uchar *sourceLine = source->scanLine(sy);
Chris@535 1633
Chris@535 1634 for (int x = 0; x < w; ++x) {
Chris@535 1635
Chris@903 1636 double sx1 = sxa[x*2 + 1];
Chris@537 1637 if (sx1 < 0) continue;
Chris@537 1638 int sx1i = int(sx1);
Chris@535 1639
Chris@903 1640 double sx0 = sxa[x*2];
Chris@537 1641 if (sx0 < 0) continue;
Chris@537 1642 int sx0i = int(sx0 + epsilon);
Chris@535 1643 if (sx0i >= sw) break;
Chris@535 1644
Chris@535 1645 uchar peak = 0;
Chris@535 1646 for (int sx = sx0i; sx <= sx1i; ++sx) {
Chris@535 1647 if (sx < 0 || sx >= sw) continue;
Chris@535 1648 if (sourceLine[sx] > peak) peak = sourceLine[sx];
Chris@535 1649 }
Chris@535 1650 peaks[x] = peak;
Chris@535 1651 }
Chris@535 1652 }
Chris@535 1653
Chris@535 1654 copy:
Chris@535 1655 for (int x = 0; x < w; ++x) {
Chris@535 1656 targetLine[x] = peaks[x];
Chris@535 1657 }
Chris@98 1658 }
Chris@0 1659 }
Chris@0 1660
Chris@469 1661 delete[] peaks;
Chris@469 1662
Chris@98 1663 paint.drawImage(x0, 0, img);
Chris@0 1664 }
Chris@0 1665
Chris@28 1666 bool
Chris@916 1667 Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@805 1668 int &resolution,
Chris@28 1669 SnapType snap) const
Chris@24 1670 {
Chris@24 1671 if (!m_model) {
Chris@44 1672 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@24 1673 }
Chris@24 1674
Chris@130 1675 resolution = m_model->getResolution();
Chris@904 1676 sv_frame_t left = (frame / resolution) * resolution;
Chris@904 1677 sv_frame_t right = left + resolution;
Chris@28 1678
Chris@28 1679 switch (snap) {
Chris@28 1680 case SnapLeft: frame = left; break;
Chris@28 1681 case SnapRight: frame = right; break;
Chris@28 1682 case SnapNearest:
Chris@28 1683 case SnapNeighbouring:
Chris@28 1684 if (frame - left > right - frame) frame = right;
Chris@28 1685 else frame = left;
Chris@28 1686 break;
Chris@28 1687 }
Chris@24 1688
Chris@28 1689 return true;
Chris@24 1690 }
Chris@24 1691
Chris@316 1692 void
Chris@316 1693 Colour3DPlotLayer::toXml(QTextStream &stream,
Chris@316 1694 QString indent, QString extraAttributes) const
Chris@197 1695 {
Chris@316 1696 QString s = QString("scale=\"%1\" "
Chris@316 1697 "colourScheme=\"%2\" "
Chris@316 1698 "normalizeColumns=\"%3\" "
Chris@445 1699 "normalizeVisibleArea=\"%4\" "
Chris@445 1700 "minY=\"%5\" "
Chris@465 1701 "maxY=\"%6\" "
Chris@465 1702 "invertVertical=\"%7\" "
Chris@535 1703 "opaque=\"%8\" %9")
Chris@197 1704 .arg((int)m_colourScale)
Chris@197 1705 .arg(m_colourMap)
Chris@197 1706 .arg(m_normalizeColumns ? "true" : "false")
Chris@445 1707 .arg(m_normalizeVisibleArea ? "true" : "false")
Chris@445 1708 .arg(m_miny)
Chris@465 1709 .arg(m_maxy)
Chris@465 1710 .arg(m_invertVertical ? "true" : "false")
Chris@534 1711 .arg(m_opaque ? "true" : "false")
Chris@536 1712 .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
Chris@535 1713 .arg((int)m_binScale)
Chris@536 1714 .arg(m_smooth ? "true" : "false")
Chris@536 1715 .arg(m_gain));
Chris@535 1716
Chris@316 1717 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@197 1718 }
Chris@197 1719
Chris@197 1720 void
Chris@197 1721 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
Chris@197 1722 {
Chris@445 1723 bool ok = false, alsoOk = false;
Chris@197 1724
Chris@197 1725 ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok);
Chris@197 1726 if (ok) setColourScale(scale);
Chris@197 1727
Chris@197 1728 int colourMap = attributes.value("colourScheme").toInt(&ok);
Chris@197 1729 if (ok) setColourMap(colourMap);
Chris@197 1730
Chris@534 1731 BinScale binscale = (BinScale)attributes.value("binScale").toInt(&ok);
Chris@534 1732 if (ok) setBinScale(binscale);
Chris@534 1733
Chris@197 1734 bool normalizeColumns =
Chris@197 1735 (attributes.value("normalizeColumns").trimmed() == "true");
Chris@197 1736 setNormalizeColumns(normalizeColumns);
Chris@197 1737
Chris@197 1738 bool normalizeVisibleArea =
Chris@197 1739 (attributes.value("normalizeVisibleArea").trimmed() == "true");
Chris@197 1740 setNormalizeVisibleArea(normalizeVisibleArea);
Chris@445 1741
Chris@465 1742 bool invertVertical =
Chris@465 1743 (attributes.value("invertVertical").trimmed() == "true");
Chris@465 1744 setInvertVertical(invertVertical);
Chris@465 1745
Chris@465 1746 bool opaque =
Chris@465 1747 (attributes.value("opaque").trimmed() == "true");
Chris@535 1748 setOpaque(opaque);
Chris@535 1749
Chris@535 1750 bool smooth =
Chris@535 1751 (attributes.value("smooth").trimmed() == "true");
Chris@535 1752 setSmooth(smooth);
Chris@465 1753
Chris@536 1754 float gain = attributes.value("gain").toFloat(&ok);
Chris@536 1755 if (ok) setGain(gain);
Chris@536 1756
Chris@445 1757 float min = attributes.value("minY").toFloat(&ok);
Chris@445 1758 float max = attributes.value("maxY").toFloat(&alsoOk);
Chris@445 1759 if (ok && alsoOk) setDisplayExtents(min, max);
Chris@197 1760 }
Chris@197 1761