annotate layer/Colour3DPlotLayer.cpp @ 855:57efeb75880d

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