annotate layer/Colour3DPlotLayer.cpp @ 473:4f4f943bfdfc

* Merge from one-fftdataserver-per-fftmodel branch. This bit of reworking (which is not described very accurately by the title of the branch) turns the MatrixFile object into something that either reads or writes, but not both, and separates the FFT file cache reader and writer implementations separately. This allows the FFT data server to have a single thread owning writers and one reader per "customer" thread, and for all locking to be vastly simplified and concentrated in the data server alone (because none of the classes it makes use of is used in more than one thread at a time). The result is faster and more trustworthy code.
author Chris Cannam
date Tue, 27 Jan 2009 13:25:10 +0000
parents 13e8edbffbd7
children efc2bd6d3611
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@353 33 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
Chris@125 34
Chris@0 35
Chris@44 36 Colour3DPlotLayer::Colour3DPlotLayer() :
Chris@0 37 m_model(0),
Chris@159 38 m_cache(0),
Chris@469 39 m_peaksCache(0),
Chris@469 40 m_peakResolution(128),
Chris@461 41 m_cacheValidStart(0),
Chris@461 42 m_cacheValidEnd(0),
Chris@197 43 m_colourScale(LinearScale),
Chris@461 44 m_colourScaleSet(false),
Chris@197 45 m_colourMap(0),
Chris@197 46 m_normalizeColumns(false),
Chris@357 47 m_normalizeVisibleArea(false),
Chris@444 48 m_invertVertical(false),
Chris@465 49 m_opaque(false),
Chris@444 50 m_miny(0),
Chris@444 51 m_maxy(0)
Chris@0 52 {
Chris@44 53
Chris@0 54 }
Chris@0 55
Chris@0 56 Colour3DPlotLayer::~Colour3DPlotLayer()
Chris@0 57 {
Chris@461 58 delete m_cache;
Chris@469 59 delete m_peaksCache;
Chris@0 60 }
Chris@0 61
Chris@0 62 void
Chris@0 63 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
Chris@0 64 {
Chris@193 65 if (m_model == model) return;
Chris@193 66 const DenseThreeDimensionalModel *oldModel = m_model;
Chris@0 67 m_model = model;
Chris@0 68 if (!m_model || !m_model->isOK()) return;
Chris@0 69
Chris@320 70 connectSignals(m_model);
Chris@0 71
Chris@461 72 connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
Chris@0 73 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@461 74 this, SLOT(modelChanged(size_t, size_t)));
Chris@0 75
Chris@0 76 emit modelReplaced();
Chris@193 77 emit sliceableModelReplaced(oldModel, model);
Chris@0 78 }
Chris@0 79
Chris@0 80 void
Chris@0 81 Colour3DPlotLayer::cacheInvalid()
Chris@0 82 {
Chris@469 83 delete m_cache;
Chris@469 84 delete m_peaksCache;
Chris@0 85 m_cache = 0;
Chris@469 86 m_peaksCache = 0;
Chris@461 87 m_cacheValidStart = 0;
Chris@461 88 m_cacheValidEnd = 0;
Chris@0 89 }
Chris@0 90
Chris@0 91 void
Chris@461 92 Colour3DPlotLayer::cacheInvalid(size_t startFrame, size_t endFrame)
Chris@0 93 {
Chris@461 94 if (!m_cache) return;
Chris@461 95
Chris@461 96 size_t modelResolution = m_model->getResolution();
Chris@461 97 size_t start = startFrame / modelResolution;
Chris@461 98 size_t end = endFrame / modelResolution + 1;
Chris@461 99 if (m_cacheValidStart < end) m_cacheValidStart = end;
Chris@461 100 if (m_cacheValidEnd > start) m_cacheValidEnd = start;
Chris@461 101 if (m_cacheValidStart > m_cacheValidEnd) m_cacheValidEnd = m_cacheValidStart;
Chris@461 102 }
Chris@461 103
Chris@461 104 void
Chris@461 105 Colour3DPlotLayer::modelChanged()
Chris@461 106 {
Chris@461 107 if (!m_colourScaleSet && m_colourScale == LinearScale) {
Chris@461 108 if (m_model) {
Chris@461 109 if (m_model->shouldUseLogValueScale()) {
Chris@461 110 setColourScale(LogScale);
Chris@461 111 } else {
Chris@461 112 m_colourScaleSet = true;
Chris@461 113 }
Chris@461 114 }
Chris@461 115 }
Chris@0 116 cacheInvalid();
Chris@0 117 }
Chris@0 118
Chris@461 119 void
Chris@461 120 Colour3DPlotLayer::modelChanged(size_t startFrame, size_t endFrame)
Chris@461 121 {
Chris@461 122 if (!m_colourScaleSet && m_colourScale == LinearScale) {
Chris@461 123 if (m_model && m_model->getWidth() > 50) {
Chris@461 124 if (m_model->shouldUseLogValueScale()) {
Chris@461 125 setColourScale(LogScale);
Chris@461 126 } else {
Chris@461 127 m_colourScaleSet = true;
Chris@461 128 }
Chris@461 129 }
Chris@461 130 }
Chris@461 131 cacheInvalid(startFrame, endFrame);
Chris@461 132 }
Chris@461 133
Chris@159 134 Layer::PropertyList
Chris@159 135 Colour3DPlotLayer::getProperties() const
Chris@159 136 {
Chris@159 137 PropertyList list;
Chris@197 138 list.push_back("Colour");
Chris@159 139 list.push_back("Colour Scale");
Chris@197 140 list.push_back("Normalize Columns");
Chris@197 141 list.push_back("Normalize Visible Area");
Chris@357 142 list.push_back("Invert Vertical Scale");
Chris@465 143 list.push_back("Opaque");
Chris@159 144 return list;
Chris@159 145 }
Chris@159 146
Chris@159 147 QString
Chris@159 148 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
Chris@159 149 {
Chris@197 150 if (name == "Colour") return tr("Colour");
Chris@197 151 if (name == "Colour Scale") return tr("Scale");
Chris@197 152 if (name == "Normalize Columns") return tr("Normalize Columns");
Chris@197 153 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
Chris@357 154 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
Chris@465 155 if (name == "Opaque") return tr("Always Opaque");
Chris@159 156 return "";
Chris@159 157 }
Chris@159 158
Chris@346 159 QString
Chris@346 160 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
Chris@346 161 {
Chris@346 162 if (name == "Normalize Columns") return "normalise-columns";
Chris@346 163 if (name == "Normalize Visible Area") return "normalise";
Chris@357 164 if (name == "Invert Vertical Scale") return "invert-vertical";
Chris@465 165 if (name == "Opaque") return "opaque";
Chris@346 166 return "";
Chris@346 167 }
Chris@346 168
Chris@159 169 Layer::PropertyType
Chris@159 170 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
Chris@159 171 {
Chris@197 172 if (name == "Normalize Columns") return ToggleProperty;
Chris@197 173 if (name == "Normalize Visible Area") return ToggleProperty;
Chris@357 174 if (name == "Invert Vertical Scale") return ToggleProperty;
Chris@465 175 if (name == "Opaque") return ToggleProperty;
Chris@159 176 return ValueProperty;
Chris@159 177 }
Chris@159 178
Chris@159 179 QString
Chris@159 180 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
Chris@159 181 {
Chris@197 182 if (name == "Normalize Columns" ||
Chris@197 183 name == "Normalize Visible Area" ||
Chris@357 184 name == "Invert Vertical Scale" ||
Chris@197 185 name == "Colour Scale") return tr("Scale");
Chris@465 186 if (name == "Opaque" ||
Chris@465 187 name == "Colour") return tr("Colour");
Chris@159 188 return QString();
Chris@159 189 }
Chris@159 190
Chris@159 191 int
Chris@159 192 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@216 193 int *min, int *max, int *deflt) const
Chris@159 194 {
Chris@216 195 int val = 0;
Chris@159 196
Chris@216 197 int garbage0, garbage1, garbage2;
Chris@159 198 if (!min) min = &garbage0;
Chris@159 199 if (!max) max = &garbage1;
Chris@216 200 if (!deflt) deflt = &garbage2;
Chris@159 201
Chris@159 202 if (name == "Colour Scale") {
Chris@159 203
Chris@159 204 *min = 0;
Chris@197 205 *max = 2;
Chris@216 206 *deflt = (int)LinearScale;
Chris@159 207
Chris@216 208 val = (int)m_colourScale;
Chris@159 209
Chris@197 210 } else if (name == "Colour") {
Chris@197 211
Chris@197 212 *min = 0;
Chris@197 213 *max = ColourMapper::getColourMapCount() - 1;
Chris@216 214 *deflt = 0;
Chris@197 215
Chris@216 216 val = m_colourMap;
Chris@197 217
Chris@197 218 } else if (name == "Normalize Columns") {
Chris@197 219
Chris@216 220 *deflt = 0;
Chris@216 221 val = (m_normalizeColumns ? 1 : 0);
Chris@197 222
Chris@197 223 } else if (name == "Normalize Visible Area") {
Chris@197 224
Chris@216 225 *deflt = 0;
Chris@216 226 val = (m_normalizeVisibleArea ? 1 : 0);
Chris@197 227
Chris@357 228 } else if (name == "Invert Vertical Scale") {
Chris@357 229
Chris@357 230 *deflt = 0;
Chris@357 231 val = (m_invertVertical ? 1 : 0);
Chris@357 232
Chris@465 233 } else if (name == "Opaque") {
Chris@465 234
Chris@465 235 *deflt = 0;
Chris@465 236 val = (m_opaque ? 1 : 0);
Chris@465 237
Chris@159 238 } else {
Chris@216 239 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@159 240 }
Chris@159 241
Chris@216 242 return val;
Chris@159 243 }
Chris@159 244
Chris@159 245 QString
Chris@159 246 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name,
Chris@159 247 int value) const
Chris@159 248 {
Chris@197 249 if (name == "Colour") {
Chris@197 250 return ColourMapper::getColourMapName(value);
Chris@197 251 }
Chris@159 252 if (name == "Colour Scale") {
Chris@159 253 switch (value) {
Chris@159 254 default:
Chris@198 255 case 0: return tr("Linear");
Chris@198 256 case 1: return tr("Log");
Chris@198 257 case 2: return tr("+/-1");
Chris@159 258 }
Chris@159 259 }
Chris@159 260 return tr("<unknown>");
Chris@159 261 }
Chris@159 262
Chris@159 263 void
Chris@159 264 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
Chris@159 265 {
Chris@159 266 if (name == "Colour Scale") {
Chris@159 267 switch (value) {
Chris@159 268 default:
Chris@159 269 case 0: setColourScale(LinearScale); break;
Chris@197 270 case 1: setColourScale(LogScale); break;
Chris@197 271 case 2: setColourScale(PlusMinusOneScale); break;
Chris@159 272 }
Chris@197 273 } else if (name == "Colour") {
Chris@197 274 setColourMap(value);
Chris@197 275 } else if (name == "Normalize Columns") {
Chris@197 276 setNormalizeColumns(value ? true : false);
Chris@197 277 } else if (name == "Normalize Visible Area") {
Chris@197 278 setNormalizeVisibleArea(value ? true : false);
Chris@357 279 } else if (name == "Invert Vertical Scale") {
Chris@357 280 setInvertVertical(value ? true : false);
Chris@465 281 } else if (name == "Opaque") {
Chris@465 282 setOpaque(value ? true : false);
Chris@159 283 }
Chris@159 284 }
Chris@159 285
Chris@159 286 void
Chris@159 287 Colour3DPlotLayer::setColourScale(ColourScale scale)
Chris@159 288 {
Chris@159 289 if (m_colourScale == scale) return;
Chris@159 290 m_colourScale = scale;
Chris@461 291 m_colourScaleSet = true;
Chris@159 292 cacheInvalid();
Chris@159 293 emit layerParametersChanged();
Chris@159 294 }
Chris@159 295
Chris@197 296 void
Chris@197 297 Colour3DPlotLayer::setColourMap(int map)
Chris@197 298 {
Chris@197 299 if (m_colourMap == map) return;
Chris@197 300 m_colourMap = map;
Chris@197 301 cacheInvalid();
Chris@197 302 emit layerParametersChanged();
Chris@197 303 }
Chris@197 304
Chris@197 305 void
Chris@197 306 Colour3DPlotLayer::setNormalizeColumns(bool n)
Chris@197 307 {
Chris@197 308 if (m_normalizeColumns == n) return;
Chris@197 309 m_normalizeColumns = n;
Chris@197 310 cacheInvalid();
Chris@197 311 emit layerParametersChanged();
Chris@197 312 }
Chris@197 313
Chris@197 314 bool
Chris@197 315 Colour3DPlotLayer::getNormalizeColumns() const
Chris@197 316 {
Chris@197 317 return m_normalizeColumns;
Chris@197 318 }
Chris@197 319
Chris@197 320 void
Chris@197 321 Colour3DPlotLayer::setNormalizeVisibleArea(bool n)
Chris@197 322 {
Chris@197 323 if (m_normalizeVisibleArea == n) return;
Chris@197 324 m_normalizeVisibleArea = n;
Chris@197 325 cacheInvalid();
Chris@197 326 emit layerParametersChanged();
Chris@197 327 }
Chris@197 328
Chris@197 329 bool
Chris@197 330 Colour3DPlotLayer::getNormalizeVisibleArea() const
Chris@197 331 {
Chris@197 332 return m_normalizeVisibleArea;
Chris@197 333 }
Chris@197 334
Chris@357 335 void
Chris@357 336 Colour3DPlotLayer::setInvertVertical(bool n)
Chris@357 337 {
Chris@357 338 if (m_invertVertical == n) return;
Chris@357 339 m_invertVertical = n;
Chris@357 340 cacheInvalid();
Chris@357 341 emit layerParametersChanged();
Chris@357 342 }
Chris@357 343
Chris@465 344 void
Chris@465 345 Colour3DPlotLayer::setOpaque(bool n)
Chris@465 346 {
Chris@465 347 if (m_opaque == n) return;
Chris@465 348 m_opaque = n;
Chris@465 349 emit layerParametersChanged();
Chris@465 350 }
Chris@465 351
Chris@357 352 bool
Chris@357 353 Colour3DPlotLayer::getInvertVertical() const
Chris@357 354 {
Chris@357 355 return m_invertVertical;
Chris@357 356 }
Chris@357 357
Chris@25 358 bool
Chris@465 359 Colour3DPlotLayer::getOpaque() const
Chris@465 360 {
Chris@465 361 return m_opaque;
Chris@465 362 }
Chris@465 363
Chris@465 364 bool
Chris@44 365 Colour3DPlotLayer::isLayerScrollable(const View *v) const
Chris@25 366 {
Chris@197 367 if (m_normalizeVisibleArea) return false;
Chris@25 368 QPoint discard;
Chris@44 369 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@25 370 }
Chris@25 371
Chris@444 372 bool
Chris@444 373 Colour3DPlotLayer::getValueExtents(float &min, float &max,
Chris@444 374 bool &logarithmic, QString &unit) const
Chris@444 375 {
Chris@444 376 if (!m_model) return false;
Chris@444 377
Chris@444 378 min = 0;
Chris@444 379 max = m_model->getHeight();
Chris@444 380
Chris@444 381 logarithmic = false;
Chris@444 382 unit = "";
Chris@444 383
Chris@444 384 return true;
Chris@444 385 }
Chris@444 386
Chris@444 387 bool
Chris@444 388 Colour3DPlotLayer::getDisplayExtents(float &min, float &max) const
Chris@444 389 {
Chris@444 390 if (!m_model) return false;
Chris@444 391
Chris@444 392 min = m_miny;
Chris@444 393 max = m_maxy;
Chris@444 394 if (max <= min) {
Chris@444 395 min = 0;
Chris@444 396 max = m_model->getHeight();
Chris@444 397 }
Chris@444 398 if (min < 0) min = 0;
Chris@444 399 if (max > m_model->getHeight()) max = m_model->getHeight();
Chris@444 400
Chris@444 401 return true;
Chris@444 402 }
Chris@444 403
Chris@444 404 bool
Chris@444 405 Colour3DPlotLayer::setDisplayExtents(float min, float max)
Chris@444 406 {
Chris@444 407 if (!m_model) return false;
Chris@444 408
Chris@444 409 m_miny = lrintf(min);
Chris@444 410 m_maxy = lrintf(max);
Chris@444 411
Chris@444 412 emit layerParametersChanged();
Chris@444 413 return true;
Chris@444 414 }
Chris@444 415
Chris@444 416 int
Chris@444 417 Colour3DPlotLayer::getVerticalZoomSteps(int &defaultStep) const
Chris@444 418 {
Chris@444 419 if (!m_model) return 0;
Chris@444 420
Chris@444 421 defaultStep = 0;
Chris@444 422 int h = m_model->getHeight();
Chris@444 423 return h;
Chris@444 424 }
Chris@444 425
Chris@444 426 int
Chris@444 427 Colour3DPlotLayer::getCurrentVerticalZoomStep() const
Chris@444 428 {
Chris@444 429 if (!m_model) return 0;
Chris@444 430
Chris@444 431 float min, max;
Chris@444 432 getDisplayExtents(min, max);
Chris@444 433 return m_model->getHeight() - lrintf(max - min);
Chris@444 434 }
Chris@444 435
Chris@444 436 void
Chris@444 437 Colour3DPlotLayer::setVerticalZoomStep(int step)
Chris@444 438 {
Chris@444 439 if (!m_model) return;
Chris@444 440
Chris@445 441 // std::cerr << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): before: miny = " << m_miny << ", maxy = " << m_maxy << std::endl;
Chris@444 442
Chris@444 443 int dist = m_model->getHeight() - step;
Chris@444 444 if (dist < 1) dist = 1;
Chris@444 445 float centre = m_miny + (float(m_maxy) - float(m_miny)) / 2.f;
Chris@444 446 m_miny = lrintf(centre - float(dist)/2);
Chris@444 447 if (m_miny < 0) m_miny = 0;
Chris@444 448 m_maxy = m_miny + dist;
Chris@444 449 if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight();
Chris@444 450
Chris@445 451 // std::cerr << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): after: miny = " << m_miny << ", maxy = " << m_maxy << std::endl;
Chris@444 452
Chris@444 453 emit layerParametersChanged();
Chris@444 454 }
Chris@444 455
Chris@444 456 RangeMapper *
Chris@444 457 Colour3DPlotLayer::getNewVerticalZoomRangeMapper() const
Chris@444 458 {
Chris@444 459 if (!m_model) return 0;
Chris@444 460
Chris@444 461 return new LinearRangeMapper(0, m_model->getHeight(),
Chris@444 462 0, m_model->getHeight(), "");
Chris@444 463 }
Chris@444 464
Chris@25 465 QString
Chris@44 466 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const
Chris@25 467 {
Chris@25 468 if (!m_model) return "";
Chris@25 469
Chris@25 470 int x = pos.x();
Chris@25 471 int y = pos.y();
Chris@25 472
Chris@25 473 size_t modelStart = m_model->getStartFrame();
Chris@130 474 size_t modelResolution = m_model->getResolution();
Chris@25 475
Chris@159 476 float srRatio =
Chris@159 477 float(v->getViewManager()->getMainModelSampleRate()) /
Chris@159 478 float(m_model->getSampleRate());
Chris@159 479
Chris@160 480 int sx0 = int((v->getFrameForX(x) / srRatio - long(modelStart)) /
Chris@160 481 long(modelResolution));
Chris@25 482
Chris@160 483 int f0 = sx0 * modelResolution;
Chris@160 484 int f1 = f0 + modelResolution;
Chris@160 485
Chris@447 486 int sh = m_model->getHeight();
Chris@447 487
Chris@447 488 int symin = m_miny;
Chris@447 489 int symax = m_maxy;
Chris@447 490 if (symax <= symin) {
Chris@447 491 symin = 0;
Chris@447 492 symax = sh;
Chris@447 493 }
Chris@447 494 if (symin < 0) symin = 0;
Chris@447 495 if (symax > sh) symax = sh;
Chris@447 496
Chris@447 497 float binHeight = float(v->height()) / (symax - symin);
Chris@447 498 int sy = int((v->height() - y) / binHeight) + symin;
Chris@25 499
Chris@357 500 if (m_invertVertical) sy = m_model->getHeight() - sy - 1;
Chris@357 501
Chris@160 502 float value = m_model->getValueAt(sx0, sy);
Chris@159 503
Chris@159 504 // std::cerr << "bin value (" << sx0 << "," << sy << ") is " << value << std::endl;
Chris@25 505
Chris@25 506 QString binName = m_model->getBinName(sy);
Chris@25 507 if (binName == "") binName = QString("[%1]").arg(sy + 1);
Chris@25 508 else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
Chris@25 509
Chris@25 510 QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
Chris@160 511 .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
Chris@25 512 .toText(true).c_str())
Chris@160 513 .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
Chris@25 514 .toText(true).c_str())
Chris@25 515 .arg(binName)
Chris@25 516 .arg(value);
Chris@25 517
Chris@25 518 return text;
Chris@25 519 }
Chris@25 520
Chris@25 521 int
Chris@248 522 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const
Chris@159 523 {
Chris@159 524 int cw = 20;
Chris@159 525 return cw;
Chris@159 526 }
Chris@159 527
Chris@159 528 int
Chris@248 529 Colour3DPlotLayer::getVerticalScaleWidth(View *, QPainter &paint) const
Chris@25 530 {
Chris@25 531 if (!m_model) return 0;
Chris@25 532
Chris@160 533 QString sampleText = QString("[%1]").arg(m_model->getHeight());
Chris@25 534 int tw = paint.fontMetrics().width(sampleText);
Chris@98 535 bool another = false;
Chris@25 536
Chris@160 537 for (size_t i = 0; i < m_model->getHeight(); ++i) {
Chris@25 538 if (m_model->getBinName(i).length() > sampleText.length()) {
Chris@25 539 sampleText = m_model->getBinName(i);
Chris@98 540 another = true;
Chris@25 541 }
Chris@25 542 }
Chris@98 543 if (another) {
Chris@25 544 tw = std::max(tw, paint.fontMetrics().width(sampleText));
Chris@25 545 }
Chris@25 546
Chris@159 547 return tw + 13 + getColourScaleWidth(paint);
Chris@25 548 }
Chris@25 549
Chris@25 550 void
Chris@44 551 Colour3DPlotLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
Chris@25 552 {
Chris@25 553 if (!m_model) return;
Chris@25 554
Chris@25 555 int h = rect.height(), w = rect.width();
Chris@25 556
Chris@159 557 int cw = getColourScaleWidth(paint);
Chris@159 558
Chris@159 559 int ch = h - 20;
Chris@159 560 if (ch > 20 && m_cache) {
Chris@159 561
Chris@447 562 float min = m_model->getMinimumLevel();
Chris@447 563 float max = m_model->getMaximumLevel();
Chris@447 564
Chris@447 565 float mmin = min;
Chris@447 566 float mmax = max;
Chris@447 567
Chris@447 568 if (m_colourScale == LogScale) {
Chris@447 569 LogRange::mapRange(mmin, mmax);
Chris@447 570 } else if (m_colourScale == PlusMinusOneScale) {
Chris@447 571 mmin = -1.f;
Chris@447 572 mmax = 1.f;
Chris@447 573 }
Chris@447 574
Chris@447 575 if (max == min) max = min + 1.0;
Chris@465 576 if (mmax == mmin) mmax = mmin + 1.0;
Chris@447 577
Chris@287 578 paint.setPen(v->getForeground());
Chris@447 579 paint.drawRect(4, 10, cw - 8, ch+1);
Chris@159 580
Chris@446 581 for (int y = 0; y < ch; ++y) {
Chris@447 582 float value = ((max - min) * (ch - y - 1)) / ch + min;
Chris@447 583 if (m_colourScale == LogScale) {
Chris@447 584 value = LogRange::map(value);
Chris@447 585 }
Chris@447 586 int pixel = int(((value - mmin) * 256) / (mmax - mmin));
Chris@465 587 if (pixel >= 0 && pixel < 256) {
Chris@465 588 QRgb c = m_cache->color(pixel);
Chris@465 589 paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c)));
Chris@465 590 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
Chris@465 591 } else {
Chris@465 592 std::cerr << "WARNING: Colour3DPlotLayer::paintVerticalScale: value " << value << ", mmin " << mmin << ", mmax " << mmax << " leads to invalid pixel " << pixel << std::endl;
Chris@465 593 }
Chris@159 594 }
Chris@446 595
Chris@446 596 QString minstr = QString("%1").arg(min);
Chris@446 597 QString maxstr = QString("%1").arg(max);
Chris@446 598
Chris@446 599 paint.save();
Chris@446 600
Chris@446 601 QFont font = paint.font();
Chris@446 602 font.setPixelSize(10);
Chris@446 603 paint.setFont(font);
Chris@446 604
Chris@446 605 int msw = paint.fontMetrics().width(maxstr);
Chris@446 606
Chris@446 607 QMatrix m;
Chris@446 608 m.translate(cw - 6, ch + 10);
Chris@446 609 m.rotate(-90);
Chris@446 610
Chris@446 611 paint.setWorldMatrix(m);
Chris@446 612
Chris@446 613 v->drawVisibleText(paint, 2, 0, minstr, View::OutlinedText);
Chris@446 614
Chris@446 615 m.translate(ch - msw - 2, 0);
Chris@446 616 paint.setWorldMatrix(m);
Chris@446 617
Chris@446 618 v->drawVisibleText(paint, 0, 0, maxstr, View::OutlinedText);
Chris@446 619
Chris@446 620 paint.restore();
Chris@159 621 }
Chris@159 622
Chris@287 623 paint.setPen(v->getForeground());
Chris@159 624
Chris@445 625 int sh = m_model->getHeight();
Chris@445 626
Chris@445 627 int symin = m_miny;
Chris@445 628 int symax = m_maxy;
Chris@445 629 if (symax <= symin) {
Chris@445 630 symin = 0;
Chris@445 631 symax = sh;
Chris@445 632 }
Chris@445 633 if (symin < 0) symin = 0;
Chris@445 634 if (symax > sh) symax = sh;
Chris@445 635
Chris@456 636 float binHeight = float(v->height()) / (symax - symin);
Chris@456 637
Chris@456 638 paint.save();
Chris@456 639
Chris@456 640 QFont tf = paint.font();
Chris@456 641 if (paint.fontMetrics().height() >= binHeight) {
Chris@457 642 tf.setPixelSize(binHeight > 7 ? binHeight - 2 : 5);
Chris@456 643 paint.setFont(tf);
Chris@456 644 }
Chris@456 645
Chris@98 646 int count = v->height() / paint.fontMetrics().height();
Chris@445 647 int step = (symax - symin) / count;
Chris@98 648 if (step == 0) step = 1;
Chris@25 649
Chris@445 650 for (size_t i = symin; i < symax; ++i) {
Chris@25 651
Chris@357 652 size_t idx = i;
Chris@357 653 if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
Chris@357 654
Chris@357 655 if ((idx % step) != 0) continue;
Chris@98 656
Chris@445 657 int y0 = int(v->height() - ((i - symin) * binHeight) - 1);
Chris@25 658
Chris@357 659 QString text = m_model->getBinName(idx);
Chris@357 660 if (text == "") text = QString("[%1]").arg(idx + 1);
Chris@25 661
Chris@159 662 paint.drawLine(cw, y0, w, y0);
Chris@25 663
Chris@457 664 if (step > 1) {
Chris@457 665 paint.drawLine(w - 1, y0 - (step * binHeight) + 1,
Chris@457 666 w - 1, y0 - binHeight - 1);
Chris@457 667 paint.drawLine(w - 2, y0 - (step * binHeight) + 1,
Chris@457 668 w - 2, y0 - binHeight - 2);
Chris@457 669 }
Chris@457 670
Chris@248 671 int cy = int(y0 - (step * binHeight)/2);
Chris@25 672 int ty = cy + paint.fontMetrics().ascent()/2;
Chris@25 673
Chris@159 674 paint.drawText(cw + 5, ty, text);
Chris@25 675 }
Chris@456 676
Chris@456 677 paint.restore();
Chris@25 678 }
Chris@25 679
Chris@467 680 DenseThreeDimensionalModel::Column
Chris@467 681 Colour3DPlotLayer::getColumn(size_t col) const
Chris@197 682 {
Chris@467 683 DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
Chris@468 684 while (values.size() < m_model->getHeight()) values.push_back(0.f);
Chris@467 685 if (!m_normalizeColumns) return values;
Chris@461 686
Chris@224 687 float colMax = 0.f, colMin = 0.f;
Chris@461 688 float min = 0.f, max = 0.f;
Chris@197 689
Chris@461 690 min = m_model->getMinimumLevel();
Chris@461 691 max = m_model->getMaximumLevel();
Chris@461 692
Chris@461 693 for (size_t y = 0; y < values.size(); ++y) {
Chris@467 694 if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
Chris@467 695 if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
Chris@197 696 }
Chris@461 697 if (colMin == colMax) colMax = colMin + 1;
Chris@197 698
Chris@197 699 for (size_t y = 0; y < values.size(); ++y) {
Chris@461 700
Chris@467 701 float value = values.at(y);
Chris@461 702 float norm = (value - colMin) / (colMax - colMin);
Chris@467 703 float newvalue = min + (max - min) * norm;
Chris@197 704
Chris@467 705 if (value != newvalue) values[y] = newvalue;
Chris@468 706 }
Chris@468 707
Chris@468 708 return values;
Chris@197 709 }
Chris@197 710
Chris@197 711 void
Chris@197 712 Colour3DPlotLayer::fillCache(size_t firstBin, size_t lastBin) const
Chris@197 713 {
Chris@466 714 Profiler profiler("Colour3DPlotLayer::fillCache");
Chris@197 715 size_t modelStart = m_model->getStartFrame();
Chris@197 716 size_t modelEnd = m_model->getEndFrame();
Chris@197 717 size_t modelResolution = m_model->getResolution();
Chris@197 718
Chris@224 719 // std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl;
Chris@197 720
Chris@461 721 size_t modelStartBin = modelStart / modelResolution;
Chris@461 722 size_t modelEndBin = modelEnd / modelResolution;
Chris@461 723
Chris@461 724 size_t cacheWidth = modelEndBin - modelStartBin + 1;
Chris@471 725 if (lastBin > modelEndBin) cacheWidth = lastBin - modelStartBin + 1;
Chris@461 726 size_t cacheHeight = m_model->getHeight();
Chris@461 727
Chris@461 728 if (m_cache && (m_cache->height() != int(cacheHeight))) {
Chris@461 729 delete m_cache;
Chris@469 730 delete m_peaksCache;
Chris@461 731 m_cache = 0;
Chris@469 732 m_peaksCache = 0;
Chris@461 733 }
Chris@461 734
Chris@461 735 if (m_cache && (m_cache->width() != int(cacheWidth))) {
Chris@469 736 QImage *newCache =
Chris@469 737 new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight));
Chris@461 738 delete m_cache;
Chris@461 739 m_cache = newCache;
Chris@469 740 if (m_peaksCache) {
Chris@469 741 QImage *newPeaksCache =
Chris@469 742 new QImage(m_peaksCache->copy
Chris@469 743 (0, 0, cacheWidth / m_peakResolution, cacheHeight));
Chris@469 744 delete m_peaksCache;
Chris@469 745 m_peaksCache = newPeaksCache;
Chris@469 746 }
Chris@197 747 }
Chris@197 748
Chris@461 749 if (!m_cache) {
Chris@469 750 m_cache = new QImage
Chris@469 751 (cacheWidth, cacheHeight, QImage::Format_Indexed8);
Chris@461 752 m_cache->setNumColors(256);
Chris@469 753 if (modelResolution < m_peakResolution / 2 && !m_normalizeVisibleArea) {
Chris@469 754 m_peaksCache = new QImage
Chris@469 755 (cacheWidth / m_peakResolution + 1, cacheHeight,
Chris@469 756 QImage::Format_Indexed8);
Chris@469 757 m_peaksCache->setNumColors(256);
Chris@469 758 } else if (m_peaksCache) {
Chris@469 759 delete m_peaksCache;
Chris@469 760 m_peaksCache = 0;
Chris@469 761 }
Chris@461 762 m_cacheValidStart = 0;
Chris@461 763 m_cacheValidEnd = 0;
Chris@197 764 }
Chris@197 765
Chris@461 766 if (m_cacheValidStart <= firstBin && m_cacheValidEnd >= lastBin) {
Chris@461 767 return;
Chris@461 768 }
Chris@461 769
Chris@461 770 size_t fillStart = firstBin;
Chris@461 771 size_t fillEnd = lastBin;
Chris@197 772
Chris@461 773 if (fillStart < modelStartBin) fillStart = modelStartBin;
Chris@461 774 if (fillStart > modelEndBin) fillStart = modelEndBin;
Chris@461 775 if (fillEnd < modelStartBin) fillEnd = modelStartBin;
Chris@461 776 if (fillEnd > modelEndBin) fillEnd = modelEndBin;
Chris@197 777
Chris@461 778 bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns);
Chris@197 779
Chris@461 780 if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) {
Chris@461 781
Chris@461 782 if (m_cacheValidEnd < fillStart) {
Chris@461 783 fillStart = m_cacheValidEnd + 1;
Chris@461 784 }
Chris@461 785 if (m_cacheValidStart > fillEnd) {
Chris@461 786 fillEnd = m_cacheValidStart - 1;
Chris@461 787 }
Chris@461 788
Chris@461 789 m_cacheValidStart = std::min(fillStart, m_cacheValidStart);
Chris@461 790 m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd);
Chris@461 791
Chris@461 792 } else {
Chris@461 793
Chris@461 794 // the only valid area, ever, is the currently visible one
Chris@461 795
Chris@461 796 m_cacheValidStart = fillStart;
Chris@461 797 m_cacheValidEnd = fillEnd;
Chris@461 798 }
Chris@461 799
Chris@461 800 // std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << std::endl;
Chris@461 801
Chris@197 802 DenseThreeDimensionalModel::Column values;
Chris@197 803
Chris@197 804 float min = m_model->getMinimumLevel();
Chris@197 805 float max = m_model->getMaximumLevel();
Chris@197 806
Chris@197 807 if (m_colourScale == LogScale) {
Chris@197 808 LogRange::mapRange(min, max);
Chris@197 809 } else if (m_colourScale == PlusMinusOneScale) {
Chris@197 810 min = -1.f;
Chris@197 811 max = 1.f;
Chris@197 812 }
Chris@197 813
Chris@197 814 if (max == min) max = min + 1.0;
Chris@197 815
Chris@197 816 ColourMapper mapper(m_colourMap, 0.f, 255.f);
Chris@197 817
Chris@197 818 for (int index = 0; index < 256; ++index) {
Chris@197 819 QColor colour = mapper.map(index);
Chris@469 820 m_cache->setColor
Chris@469 821 (index, qRgb(colour.red(), colour.green(), colour.blue()));
Chris@469 822 if (m_peaksCache) {
Chris@469 823 m_peaksCache->setColor
Chris@469 824 (index, qRgb(colour.red(), colour.green(), colour.blue()));
Chris@469 825 }
Chris@197 826 }
Chris@197 827
Chris@461 828 // m_cache->fill(0);
Chris@197 829
Chris@224 830 float visibleMax = 0.f, visibleMin = 0.f;
Chris@197 831
Chris@461 832 if (normalizeVisible) {
Chris@197 833
Chris@461 834 for (size_t c = fillStart; c <= fillEnd; ++c) {
Chris@197 835
Chris@467 836 values = getColumn(c);
Chris@197 837
Chris@224 838 float colMax = 0.f, colMin = 0.f;
Chris@197 839
Chris@461 840 for (size_t y = 0; y < cacheHeight; ++y) {
Chris@197 841 if (y >= values.size()) break;
Chris@197 842 if (y == 0 || values[y] > colMax) colMax = values[y];
Chris@224 843 if (y == 0 || values[y] < colMin) colMin = values[y];
Chris@197 844 }
Chris@197 845
Chris@461 846 if (c == fillStart || colMax > visibleMax) visibleMax = colMax;
Chris@461 847 if (c == fillStart || colMin < visibleMin) visibleMin = colMin;
Chris@461 848 }
Chris@461 849
Chris@461 850 if (m_colourScale == LogScale) {
Chris@461 851 visibleMin = LogRange::map(visibleMin);
Chris@461 852 visibleMax = LogRange::map(visibleMax);
Chris@461 853 if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax);
Chris@197 854 }
Chris@197 855 }
Chris@197 856
Chris@224 857 if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
Chris@224 858
Chris@469 859 int *peaks = 0;
Chris@469 860 if (m_peaksCache) {
Chris@469 861 peaks = new int[cacheHeight];
Chris@469 862 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 863 peaks[y] = 0;
Chris@469 864 }
Chris@469 865 }
Chris@469 866
Chris@461 867 for (size_t c = fillStart; c <= fillEnd; ++c) {
Chris@197 868
Chris@467 869 values = getColumn(c);
Chris@197 870
Chris@461 871 for (size_t y = 0; y < cacheHeight; ++y) {
Chris@197 872
Chris@197 873 float value = min;
Chris@197 874 if (y < values.size()) {
Chris@469 875 value = values.at(y);
Chris@197 876 }
Chris@224 877
Chris@224 878 if (m_colourScale == LogScale) {
Chris@224 879 value = LogRange::map(value);
Chris@197 880 }
Chris@461 881
Chris@461 882 if (normalizeVisible) {
Chris@461 883 float norm = (value - visibleMin) / (visibleMax - visibleMin);
Chris@461 884 value = min + (max - min) * norm;
Chris@461 885 }
Chris@197 886
Chris@197 887 int pixel = int(((value - min) * 256) / (max - min));
Chris@197 888 if (pixel < 0) pixel = 0;
Chris@197 889 if (pixel > 255) pixel = 255;
Chris@469 890 if (peaks && (pixel > peaks[y])) peaks[y] = pixel;
Chris@197 891
Chris@357 892 if (m_invertVertical) {
Chris@461 893 m_cache->setPixel(c, cacheHeight - y - 1, pixel);
Chris@357 894 } else {
Chris@461 895 m_cache->setPixel(c, y, pixel);
Chris@357 896 }
Chris@197 897 }
Chris@469 898
Chris@469 899 if (peaks) {
Chris@469 900 size_t notch = (c % m_peakResolution);
Chris@469 901 if (notch == m_peakResolution-1 || c == fillEnd) {
Chris@469 902 size_t pc = c / m_peakResolution;
Chris@469 903 for (size_t y = 0; y < cacheHeight; ++y) {
Chris@469 904 if (m_invertVertical) {
Chris@469 905 m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]);
Chris@469 906 } else {
Chris@469 907 m_peaksCache->setPixel(pc, y, peaks[y]);
Chris@469 908 }
Chris@469 909 }
Chris@469 910 for (int y = 0; y < cacheHeight; ++y) {
Chris@469 911 peaks[y] = 0;
Chris@469 912 }
Chris@469 913 }
Chris@469 914 }
Chris@197 915 }
Chris@469 916
Chris@469 917 delete[] peaks;
Chris@197 918 }
Chris@197 919
Chris@197 920 void
Chris@44 921 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const
Chris@0 922 {
Chris@443 923 /*!!!
Chris@443 924 if (m_model) {
Chris@443 925 std::cerr << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << std::endl;
Chris@443 926 }
Chris@443 927 */
Chris@466 928 Profiler profiler("Colour3DPlotLayer::paint");
Chris@125 929 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@125 930 std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl;
Chris@125 931 #endif
Chris@0 932
Chris@0 933 int completion = 0;
Chris@0 934 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
Chris@0 935 if (completion > 0) {
Chris@44 936 paint.fillRect(0, 10, v->width() * completion / 100,
Chris@0 937 10, QColor(120, 120, 120));
Chris@0 938 }
Chris@0 939 return;
Chris@0 940 }
Chris@0 941
Chris@197 942 if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect();
Chris@197 943
Chris@0 944 size_t modelStart = m_model->getStartFrame();
Chris@0 945 size_t modelEnd = m_model->getEndFrame();
Chris@130 946 size_t modelResolution = m_model->getResolution();
Chris@0 947
Chris@197 948 // The cache is from the model's start frame to the model's end
Chris@197 949 // frame at the model's window increment frames per pixel. We
Chris@197 950 // want to draw from our start frame + x0 * zoomLevel to our start
Chris@197 951 // frame + x1 * zoomLevel at zoomLevel frames per pixel.
Chris@12 952
Chris@197 953 // We have quite different paint mechanisms for rendering "large"
Chris@197 954 // bins (more than one bin per pixel in both directions) and
Chris@197 955 // "small". This is "large"; see paintDense below for "small".
Chris@12 956
Chris@197 957 int x0 = rect.left();
Chris@197 958 int x1 = rect.right() + 1;
Chris@12 959
Chris@197 960 int h = v->height();
Chris@0 961
Chris@197 962 float srRatio =
Chris@197 963 float(v->getViewManager()->getMainModelSampleRate()) /
Chris@197 964 float(m_model->getSampleRate());
Chris@0 965
Chris@197 966 int sx0 = int((v->getFrameForX(x0) / srRatio - long(modelStart))
Chris@197 967 / long(modelResolution));
Chris@197 968 int sx1 = int((v->getFrameForX(x1) / srRatio - long(modelStart))
Chris@197 969 / long(modelResolution));
Chris@197 970 int sh = m_model->getHeight();
Chris@159 971
Chris@444 972 int symin = m_miny;
Chris@444 973 int symax = m_maxy;
Chris@444 974 if (symax <= symin) {
Chris@444 975 symin = 0;
Chris@444 976 symax = sh;
Chris@444 977 }
Chris@444 978 if (symin < 0) symin = 0;
Chris@444 979 if (symax > sh) symax = sh;
Chris@444 980
Chris@197 981 if (sx0 > 0) --sx0;
Chris@197 982 fillCache(sx0 < 0 ? 0 : sx0,
Chris@197 983 sx1 < 0 ? 0 : sx1);
Chris@0 984
Chris@351 985 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@466 986 std::cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << std::endl;
Chris@351 987 #endif
Chris@351 988
Chris@465 989 if (m_opaque ||
Chris@465 990 int(m_model->getHeight()) >= v->height() ||
Chris@466 991 ((modelResolution * srRatio) / v->getZoomLevel()) < 2) {
Chris@347 992 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@351 993 std::cerr << "calling paintDense" << std::endl;
Chris@347 994 #endif
Chris@98 995 paintDense(v, paint, rect);
Chris@98 996 return;
Chris@98 997 }
Chris@98 998
Chris@125 999 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@347 1000 std::cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << std::endl;
Chris@130 1001 std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << std::endl;
Chris@125 1002 #endif
Chris@0 1003
Chris@25 1004 QPoint illuminatePos;
Chris@44 1005 bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
Chris@54 1006 char labelbuf[10];
Chris@25 1007
Chris@197 1008 for (int sx = sx0; sx <= sx1; ++sx) {
Chris@0 1009
Chris@130 1010 int fx = sx * int(modelResolution);
Chris@0 1011
Chris@351 1012 if (fx + int(modelResolution) <= int(modelStart) ||
Chris@0 1013 fx > int(modelEnd)) continue;
Chris@0 1014
Chris@248 1015 int rx0 = v->getXForFrame(int((fx + int(modelStart)) * srRatio));
Chris@248 1016 int rx1 = v->getXForFrame(int((fx + int(modelStart) + int(modelResolution) + 1) * srRatio));
Chris@54 1017
Chris@159 1018 int rw = rx1 - rx0;
Chris@159 1019 if (rw < 1) rw = 1;
Chris@54 1020
Chris@159 1021 bool showLabel = (rw > 10 &&
Chris@159 1022 paint.fontMetrics().width("0.000000") < rw - 3 &&
Chris@54 1023 paint.fontMetrics().height() < (h / sh));
Chris@98 1024
Chris@444 1025 for (int sy = symin; sy < symax; ++sy) {
Chris@0 1026
Chris@444 1027 int ry0 = h - ((sy - symin) * h) / (symax - symin) - 1;
Chris@0 1028 QRgb pixel = qRgb(255, 255, 255);
Chris@461 1029 if (sx >= 0 && sx < m_cache->width() &&
Chris@0 1030 sy >= 0 && sy < m_cache->height()) {
Chris@461 1031 pixel = m_cache->pixel(sx, sy);
Chris@0 1032 }
Chris@0 1033
Chris@444 1034 QRect r(rx0, ry0 - h / (symax - symin) - 1,
Chris@444 1035 rw, h / (symax - symin) + 1);
Chris@159 1036
Chris@159 1037 if (rw == 1) {
Chris@159 1038 paint.setPen(pixel);
Chris@159 1039 paint.setBrush(Qt::NoBrush);
Chris@159 1040 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
Chris@159 1041 continue;
Chris@159 1042 }
Chris@159 1043
Chris@0 1044 QColor pen(255, 255, 255, 80);
Chris@0 1045 QColor brush(pixel);
Chris@159 1046
Chris@159 1047 if (rw > 3 && r.height() > 3) {
Chris@159 1048 brush.setAlpha(160);
Chris@159 1049 }
Chris@159 1050
Chris@0 1051 paint.setPen(Qt::NoPen);
Chris@0 1052 paint.setBrush(brush);
Chris@0 1053
Chris@25 1054 if (illuminate) {
Chris@25 1055 if (r.contains(illuminatePos)) {
Chris@287 1056 paint.setPen(v->getForeground());
Chris@25 1057 }
Chris@25 1058 }
Chris@76 1059
Chris@125 1060 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@159 1061 std::cerr << "rect " << r.x() << "," << r.y() << " "
Chris@159 1062 << r.width() << "x" << r.height() << std::endl;
Chris@125 1063 #endif
Chris@25 1064
Chris@25 1065 paint.drawRect(r);
Chris@0 1066
Chris@54 1067 if (showLabel) {
Chris@461 1068 if (sx >= 0 && sx < m_cache->width() &&
Chris@54 1069 sy >= 0 && sy < m_cache->height()) {
Chris@461 1070 float value = m_model->getValueAt(sx, sy);
Chris@54 1071 sprintf(labelbuf, "%06f", value);
Chris@54 1072 QString text(labelbuf);
Chris@287 1073 paint.setPen(v->getBackground());
Chris@54 1074 paint.drawText(rx0 + 2,
Chris@54 1075 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
Chris@54 1076 text);
Chris@0 1077 }
Chris@0 1078 }
Chris@0 1079 }
Chris@0 1080 }
Chris@98 1081 }
Chris@0 1082
Chris@98 1083 void
Chris@98 1084 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const
Chris@98 1085 {
Chris@466 1086 Profiler profiler("Colour3DPlotLayer::paintDense");
Chris@463 1087 if (!m_cache) return;
Chris@463 1088
Chris@466 1089 float modelStart = m_model->getStartFrame();
Chris@466 1090 float modelResolution = m_model->getResolution();
Chris@0 1091
Chris@469 1092 int mmsr = v->getViewManager()->getMainModelSampleRate();
Chris@469 1093 int msr = m_model->getSampleRate();
Chris@469 1094 float srRatio = float(mmsr) / float(msr);
Chris@159 1095
Chris@98 1096 int x0 = rect.left();
Chris@98 1097 int x1 = rect.right() + 1;
Chris@0 1098
Chris@470 1099 const int w = x1 - x0; // const so it can be used as array size below
Chris@471 1100 int h = v->height(); // we always paint full height
Chris@160 1101 int sh = m_model->getHeight();
Chris@98 1102
Chris@444 1103 int symin = m_miny;
Chris@444 1104 int symax = m_maxy;
Chris@444 1105 if (symax <= symin) {
Chris@444 1106 symin = 0;
Chris@444 1107 symax = sh;
Chris@444 1108 }
Chris@444 1109 if (symin < 0) symin = 0;
Chris@444 1110 if (symax > sh) symax = sh;
Chris@444 1111
Chris@466 1112 QImage img(w, h, QImage::Format_Indexed8);
Chris@466 1113 img.setColorTable(m_cache->colorTable());
Chris@98 1114
Chris@466 1115 uchar *peaks = new uchar[w];
Chris@466 1116 memset(peaks, 0, w);
Chris@98 1117
Chris@469 1118 int zoomLevel = v->getZoomLevel();
Chris@469 1119
Chris@469 1120 QImage *source = m_cache;
Chris@469 1121 if (m_peaksCache &&
Chris@469 1122 ((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
Chris@469 1123 // std::cerr << "using peaks cache" << std::endl;
Chris@469 1124 source = m_peaksCache;
Chris@469 1125 modelResolution *= m_peakResolution;
Chris@469 1126 } else {
Chris@469 1127 // std::cerr << "not using peaks cache" << std::endl;
Chris@469 1128 }
Chris@469 1129
Chris@466 1130 int psy1i = -1;
Chris@469 1131 int sw = source->width();
Chris@470 1132
Chris@470 1133 long xf = -1;
Chris@470 1134 long nxf = v->getFrameForX(x0);
Chris@470 1135
Chris@470 1136 int sxa[w * 2];
Chris@470 1137 for (int x = 0; x < w; ++x) {
Chris@470 1138
Chris@470 1139 xf = nxf;
Chris@470 1140 nxf = xf + zoomLevel;
Chris@470 1141
Chris@470 1142 float sx0 = (float(xf) / srRatio - modelStart) / modelResolution;
Chris@470 1143 float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution;
Chris@470 1144
Chris@470 1145 int sx0i = int(sx0 + 0.001);
Chris@470 1146 int sx1i = int(sx1);
Chris@470 1147
Chris@470 1148 sxa[x*2] = sx0i;
Chris@470 1149 sxa[x*2 + 1] = sx1i;
Chris@470 1150 }
Chris@466 1151
Chris@466 1152 for (int y = 0; y < h; ++y) {
Chris@466 1153
Chris@466 1154 float sy0 = symin + (float(h - y - 1) * (symax - symin)) / h;
Chris@466 1155 float sy1 = symin + (float(h - y) * (symax - symin)) / h;
Chris@466 1156
Chris@466 1157 int sy0i = int(sy0 + 0.001);
Chris@466 1158 int sy1i = int(sy1);
Chris@466 1159
Chris@466 1160 uchar *targetLine = img.scanLine(y);
Chris@466 1161
Chris@466 1162 if (sy0i == sy1i && sy0i == psy1i) { // same scan line as just computed
Chris@466 1163 goto copy;
Chris@105 1164 }
Chris@105 1165
Chris@471 1166 for (int x = 0; x < w; ++x) {
Chris@471 1167 peaks[x] = 0;
Chris@471 1168 }
Chris@466 1169
Chris@466 1170 for (int sy = sy0i; sy <= sy1i; ++sy) {
Chris@347 1171
Chris@469 1172 if (sy < 0 || sy >= source->height()) continue;
Chris@466 1173
Chris@469 1174 uchar *sourceLine = source->scanLine(sy);
Chris@98 1175
Chris@466 1176 for (int x = 0; x < w; ++x) {
Chris@98 1177
Chris@470 1178 int sx0i = sxa[x*2];
Chris@470 1179 int sx1i = sxa[x*2 + 1];
Chris@98 1180
Chris@466 1181 uchar peak = 0;
Chris@466 1182 for (int sx = sx0i; sx <= sx1i; ++sx) {
Chris@469 1183 if (sx < 0 || sx >= sw) continue;
Chris@466 1184 if (sourceLine[sx] > peak) peak = sourceLine[sx];
Chris@98 1185 }
Chris@466 1186 peaks[x] = peak;
Chris@98 1187 }
Chris@466 1188 }
Chris@466 1189
Chris@466 1190 copy:
Chris@466 1191 for (int x = 0; x < w; ++x) {
Chris@466 1192 targetLine[x] = peaks[x];
Chris@98 1193 }
Chris@0 1194 }
Chris@0 1195
Chris@469 1196 delete[] peaks;
Chris@469 1197
Chris@98 1198 paint.drawImage(x0, 0, img);
Chris@0 1199 }
Chris@0 1200
Chris@472 1201 void
Chris@472 1202 Colour3DPlotLayer::paintSmooth(View *v, QPainter &paint, QRect rect) const
Chris@472 1203 {
Chris@472 1204 Profiler profiler("Colour3DPlotLayer:paintSmooth");
Chris@472 1205 if (!m_cache) return;
Chris@472 1206
Chris@472 1207 float modelStart = m_model->getStartFrame();
Chris@472 1208 float modelResolution = m_model->getResolution();
Chris@472 1209
Chris@472 1210 int mmsr = v->getViewManager()->getMainModelSampleRate();
Chris@472 1211 int msr = m_model->getSampleRate();
Chris@472 1212 float srRatio = float(mmsr) / float(msr);
Chris@472 1213
Chris@472 1214 int x0 = rect.left();
Chris@472 1215 int x1 = rect.right() + 1;
Chris@472 1216
Chris@472 1217 int h = v->height(); // we always paint full height
Chris@472 1218 int sh = m_model->getHeight();
Chris@472 1219
Chris@472 1220 int symin = m_miny;
Chris@472 1221 int symax = m_maxy;
Chris@472 1222 if (symax <= symin) {
Chris@472 1223 symin = 0;
Chris@472 1224 symax = sh;
Chris@472 1225 }
Chris@472 1226 if (symin < 0) symin = 0;
Chris@472 1227 if (symax > sh) symax = sh;
Chris@472 1228
Chris@472 1229 // QImage img(w, h, QImage::Format_Indexed8);
Chris@472 1230 // img.setColorTable(m_cache->colorTable());
Chris@472 1231
Chris@472 1232 int zoomLevel = v->getZoomLevel();
Chris@472 1233
Chris@472 1234 QImage *source = m_cache;
Chris@472 1235 if (m_peaksCache &&
Chris@472 1236 ((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
Chris@472 1237 std::cerr << "using peaks cache" << std::endl;
Chris@472 1238 source = m_peaksCache;
Chris@472 1239 modelResolution *= m_peakResolution;
Chris@472 1240 } else {
Chris@472 1241 std::cerr << "not using peaks cache" << std::endl;
Chris@472 1242 }
Chris@472 1243
Chris@472 1244 float sx0 = (float(v->getFrameForX(x0)) / srRatio - modelStart) / modelResolution;
Chris@472 1245 float sx1 = (float(v->getFrameForX(x1)) / srRatio - modelStart) / modelResolution;
Chris@472 1246 int sx0i = int(sx0 + 0.001);
Chris@472 1247 int sx1i = int(sx1);
Chris@472 1248
Chris@472 1249 if (sx0i < 0) sx0i = 0;
Chris@472 1250 if (sx0i > source->width()) sx0i = source->width();
Chris@472 1251
Chris@472 1252 int tx0 = v->getXForFrame(((sx0i * modelResolution) + modelStart) * srRatio + 0.001);
Chris@472 1253 int tx1 = v->getXForFrame(((sx1i * modelResolution) + modelStart) * srRatio);
Chris@472 1254
Chris@472 1255 std::cerr << "x0 " << x0 << ", x1 " << x1 << " -> sx0 " << sx0i << ", sx1 " << sx1i << " -> tx0 " << tx0 << ", tx1 " << tx1 << std::endl;
Chris@472 1256
Chris@472 1257 QImage img = source->copy(sx0i, 0, sx1i - sx0i, source->height())
Chris@472 1258 .scaled(QSize(tx1 - tx0, h),
Chris@472 1259 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
Chris@472 1260 paint.drawImage(x0, 0, img);
Chris@472 1261 }
Chris@472 1262
Chris@28 1263 bool
Chris@44 1264 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame,
Chris@28 1265 size_t &resolution,
Chris@28 1266 SnapType snap) const
Chris@24 1267 {
Chris@24 1268 if (!m_model) {
Chris@44 1269 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@24 1270 }
Chris@24 1271
Chris@130 1272 resolution = m_model->getResolution();
Chris@28 1273 int left = (frame / resolution) * resolution;
Chris@28 1274 int right = left + resolution;
Chris@28 1275
Chris@28 1276 switch (snap) {
Chris@28 1277 case SnapLeft: frame = left; break;
Chris@28 1278 case SnapRight: frame = right; break;
Chris@28 1279 case SnapNearest:
Chris@28 1280 case SnapNeighbouring:
Chris@28 1281 if (frame - left > right - frame) frame = right;
Chris@28 1282 else frame = left;
Chris@28 1283 break;
Chris@28 1284 }
Chris@24 1285
Chris@28 1286 return true;
Chris@24 1287 }
Chris@24 1288
Chris@316 1289 void
Chris@316 1290 Colour3DPlotLayer::toXml(QTextStream &stream,
Chris@316 1291 QString indent, QString extraAttributes) const
Chris@197 1292 {
Chris@316 1293 QString s = QString("scale=\"%1\" "
Chris@316 1294 "colourScheme=\"%2\" "
Chris@316 1295 "normalizeColumns=\"%3\" "
Chris@445 1296 "normalizeVisibleArea=\"%4\" "
Chris@445 1297 "minY=\"%5\" "
Chris@465 1298 "maxY=\"%6\" "
Chris@465 1299 "invertVertical=\"%7\" "
Chris@465 1300 "opaque=\"%8\"")
Chris@197 1301 .arg((int)m_colourScale)
Chris@197 1302 .arg(m_colourMap)
Chris@197 1303 .arg(m_normalizeColumns ? "true" : "false")
Chris@445 1304 .arg(m_normalizeVisibleArea ? "true" : "false")
Chris@445 1305 .arg(m_miny)
Chris@465 1306 .arg(m_maxy)
Chris@465 1307 .arg(m_invertVertical ? "true" : "false")
Chris@465 1308 .arg(m_opaque ? "true" : "false");
Chris@197 1309
Chris@316 1310 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@197 1311 }
Chris@197 1312
Chris@197 1313 void
Chris@197 1314 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
Chris@197 1315 {
Chris@445 1316 bool ok = false, alsoOk = false;
Chris@197 1317
Chris@197 1318 ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok);
Chris@197 1319 if (ok) setColourScale(scale);
Chris@197 1320
Chris@197 1321 int colourMap = attributes.value("colourScheme").toInt(&ok);
Chris@197 1322 if (ok) setColourMap(colourMap);
Chris@197 1323
Chris@197 1324 bool normalizeColumns =
Chris@197 1325 (attributes.value("normalizeColumns").trimmed() == "true");
Chris@197 1326 setNormalizeColumns(normalizeColumns);
Chris@197 1327
Chris@197 1328 bool normalizeVisibleArea =
Chris@197 1329 (attributes.value("normalizeVisibleArea").trimmed() == "true");
Chris@197 1330 setNormalizeVisibleArea(normalizeVisibleArea);
Chris@445 1331
Chris@465 1332 bool invertVertical =
Chris@465 1333 (attributes.value("invertVertical").trimmed() == "true");
Chris@465 1334 setInvertVertical(invertVertical);
Chris@465 1335
Chris@465 1336 bool opaque =
Chris@465 1337 (attributes.value("opaque").trimmed() == "true");
Chris@465 1338 setNormalizeVisibleArea(opaque);
Chris@465 1339
Chris@445 1340 float min = attributes.value("minY").toFloat(&ok);
Chris@445 1341 float max = attributes.value("maxY").toFloat(&alsoOk);
Chris@445 1342 if (ok && alsoOk) setDisplayExtents(min, max);
Chris@197 1343 }
Chris@197 1344