annotate layer/Colour3DPlotLayer.cpp @ 1091:ac10a087e045 spectrogram-minor-refactor

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