annotate layer/Colour3DPlotLayer.cpp @ 959:2633a1d73e39

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