annotate layer/Colour3DPlotLayer.cpp @ 349:369a197737c7

* Various fixes to object lifetime management, particularly in the spectrum layer and for notification of main model deletion. The main purpose of this is to improve the behaviour of the spectrum, but I think it may also help with #1840922 Various crashes in Layer Summary window.
author Chris Cannam
date Wed, 23 Jan 2008 15:43:27 +0000
parents 0093f351641c
children b548a36f7633
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@285 21 #include "base/ColourMapper.h"
Chris@0 22
Chris@0 23 #include <QPainter>
Chris@0 24 #include <QImage>
Chris@0 25 #include <QRect>
Chris@316 26 #include <QTextStream>
Chris@0 27
Chris@0 28 #include <iostream>
Chris@0 29
Chris@0 30 #include <cassert>
Chris@0 31
Chris@125 32 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
Chris@125 33
Chris@0 34
Chris@44 35 Colour3DPlotLayer::Colour3DPlotLayer() :
Chris@0 36 m_model(0),
Chris@159 37 m_cache(0),
Chris@197 38 m_cacheStart(0),
Chris@197 39 m_colourScale(LinearScale),
Chris@197 40 m_colourMap(0),
Chris@197 41 m_normalizeColumns(false),
Chris@197 42 m_normalizeVisibleArea(false)
Chris@0 43 {
Chris@44 44
Chris@0 45 }
Chris@0 46
Chris@0 47 Colour3DPlotLayer::~Colour3DPlotLayer()
Chris@0 48 {
Chris@0 49 }
Chris@0 50
Chris@0 51 void
Chris@0 52 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
Chris@0 53 {
Chris@193 54 if (m_model == model) return;
Chris@193 55 const DenseThreeDimensionalModel *oldModel = m_model;
Chris@0 56 m_model = model;
Chris@0 57 if (!m_model || !m_model->isOK()) return;
Chris@0 58
Chris@320 59 connectSignals(m_model);
Chris@0 60
Chris@0 61 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid()));
Chris@0 62 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@0 63 this, SLOT(cacheInvalid(size_t, size_t)));
Chris@0 64
Chris@0 65 emit modelReplaced();
Chris@193 66 emit sliceableModelReplaced(oldModel, model);
Chris@0 67 }
Chris@0 68
Chris@0 69 void
Chris@0 70 Colour3DPlotLayer::cacheInvalid()
Chris@0 71 {
Chris@0 72 delete m_cache;
Chris@0 73 m_cache = 0;
Chris@0 74 }
Chris@0 75
Chris@0 76 void
Chris@0 77 Colour3DPlotLayer::cacheInvalid(size_t, size_t)
Chris@0 78 {
Chris@0 79 cacheInvalid();
Chris@0 80 }
Chris@0 81
Chris@159 82 Layer::PropertyList
Chris@159 83 Colour3DPlotLayer::getProperties() const
Chris@159 84 {
Chris@159 85 PropertyList list;
Chris@197 86 list.push_back("Colour");
Chris@159 87 list.push_back("Colour Scale");
Chris@197 88 list.push_back("Normalize Columns");
Chris@197 89 list.push_back("Normalize Visible Area");
Chris@159 90 return list;
Chris@159 91 }
Chris@159 92
Chris@159 93 QString
Chris@159 94 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
Chris@159 95 {
Chris@197 96 if (name == "Colour") return tr("Colour");
Chris@197 97 if (name == "Colour Scale") return tr("Scale");
Chris@197 98 if (name == "Normalize Columns") return tr("Normalize Columns");
Chris@197 99 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
Chris@159 100 return "";
Chris@159 101 }
Chris@159 102
Chris@346 103 QString
Chris@346 104 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
Chris@346 105 {
Chris@346 106 if (name == "Normalize Columns") return "normalise-columns";
Chris@346 107 if (name == "Normalize Visible Area") return "normalise";
Chris@346 108 return "";
Chris@346 109 }
Chris@346 110
Chris@159 111 Layer::PropertyType
Chris@159 112 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
Chris@159 113 {
Chris@197 114 if (name == "Normalize Columns") return ToggleProperty;
Chris@197 115 if (name == "Normalize Visible Area") return ToggleProperty;
Chris@159 116 return ValueProperty;
Chris@159 117 }
Chris@159 118
Chris@159 119 QString
Chris@159 120 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
Chris@159 121 {
Chris@197 122 if (name == "Normalize Columns" ||
Chris@197 123 name == "Normalize Visible Area" ||
Chris@197 124 name == "Colour Scale") return tr("Scale");
Chris@159 125 return QString();
Chris@159 126 }
Chris@159 127
Chris@159 128 int
Chris@159 129 Colour3DPlotLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@216 130 int *min, int *max, int *deflt) const
Chris@159 131 {
Chris@216 132 int val = 0;
Chris@159 133
Chris@216 134 int garbage0, garbage1, garbage2;
Chris@159 135 if (!min) min = &garbage0;
Chris@159 136 if (!max) max = &garbage1;
Chris@216 137 if (!deflt) deflt = &garbage2;
Chris@159 138
Chris@159 139 if (name == "Colour Scale") {
Chris@159 140
Chris@159 141 *min = 0;
Chris@197 142 *max = 2;
Chris@216 143 *deflt = (int)LinearScale;
Chris@159 144
Chris@216 145 val = (int)m_colourScale;
Chris@159 146
Chris@197 147 } else if (name == "Colour") {
Chris@197 148
Chris@197 149 *min = 0;
Chris@197 150 *max = ColourMapper::getColourMapCount() - 1;
Chris@216 151 *deflt = 0;
Chris@197 152
Chris@216 153 val = m_colourMap;
Chris@197 154
Chris@197 155 } else if (name == "Normalize Columns") {
Chris@197 156
Chris@216 157 *deflt = 0;
Chris@216 158 val = (m_normalizeColumns ? 1 : 0);
Chris@197 159
Chris@197 160 } else if (name == "Normalize Visible Area") {
Chris@197 161
Chris@216 162 *deflt = 0;
Chris@216 163 val = (m_normalizeVisibleArea ? 1 : 0);
Chris@197 164
Chris@159 165 } else {
Chris@216 166 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@159 167 }
Chris@159 168
Chris@216 169 return val;
Chris@159 170 }
Chris@159 171
Chris@159 172 QString
Chris@159 173 Colour3DPlotLayer::getPropertyValueLabel(const PropertyName &name,
Chris@159 174 int value) const
Chris@159 175 {
Chris@197 176 if (name == "Colour") {
Chris@197 177 return ColourMapper::getColourMapName(value);
Chris@197 178 }
Chris@159 179 if (name == "Colour Scale") {
Chris@159 180 switch (value) {
Chris@159 181 default:
Chris@198 182 case 0: return tr("Linear");
Chris@198 183 case 1: return tr("Log");
Chris@198 184 case 2: return tr("+/-1");
Chris@159 185 }
Chris@159 186 }
Chris@159 187 return tr("<unknown>");
Chris@159 188 }
Chris@159 189
Chris@159 190 void
Chris@159 191 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
Chris@159 192 {
Chris@159 193 if (name == "Colour Scale") {
Chris@159 194 switch (value) {
Chris@159 195 default:
Chris@159 196 case 0: setColourScale(LinearScale); break;
Chris@197 197 case 1: setColourScale(LogScale); break;
Chris@197 198 case 2: setColourScale(PlusMinusOneScale); break;
Chris@159 199 }
Chris@197 200 } else if (name == "Colour") {
Chris@197 201 setColourMap(value);
Chris@197 202 } else if (name == "Normalize Columns") {
Chris@197 203 setNormalizeColumns(value ? true : false);
Chris@197 204 } else if (name == "Normalize Visible Area") {
Chris@197 205 setNormalizeVisibleArea(value ? true : false);
Chris@159 206 }
Chris@159 207 }
Chris@159 208
Chris@159 209 void
Chris@159 210 Colour3DPlotLayer::setColourScale(ColourScale scale)
Chris@159 211 {
Chris@159 212 if (m_colourScale == scale) return;
Chris@159 213 m_colourScale = scale;
Chris@159 214 cacheInvalid();
Chris@159 215 emit layerParametersChanged();
Chris@159 216 }
Chris@159 217
Chris@197 218 void
Chris@197 219 Colour3DPlotLayer::setColourMap(int map)
Chris@197 220 {
Chris@197 221 if (m_colourMap == map) return;
Chris@197 222 m_colourMap = map;
Chris@197 223 cacheInvalid();
Chris@197 224 emit layerParametersChanged();
Chris@197 225 }
Chris@197 226
Chris@197 227 void
Chris@197 228 Colour3DPlotLayer::setNormalizeColumns(bool n)
Chris@197 229 {
Chris@197 230 if (m_normalizeColumns == n) return;
Chris@197 231 m_normalizeColumns = n;
Chris@197 232 cacheInvalid();
Chris@197 233 emit layerParametersChanged();
Chris@197 234 }
Chris@197 235
Chris@197 236 bool
Chris@197 237 Colour3DPlotLayer::getNormalizeColumns() const
Chris@197 238 {
Chris@197 239 return m_normalizeColumns;
Chris@197 240 }
Chris@197 241
Chris@197 242 void
Chris@197 243 Colour3DPlotLayer::setNormalizeVisibleArea(bool n)
Chris@197 244 {
Chris@197 245 if (m_normalizeVisibleArea == n) return;
Chris@197 246 m_normalizeVisibleArea = n;
Chris@197 247 cacheInvalid();
Chris@197 248 emit layerParametersChanged();
Chris@197 249 }
Chris@197 250
Chris@197 251 bool
Chris@197 252 Colour3DPlotLayer::getNormalizeVisibleArea() const
Chris@197 253 {
Chris@197 254 return m_normalizeVisibleArea;
Chris@197 255 }
Chris@197 256
Chris@25 257 bool
Chris@44 258 Colour3DPlotLayer::isLayerScrollable(const View *v) const
Chris@25 259 {
Chris@197 260 if (m_normalizeVisibleArea) return false;
Chris@25 261 QPoint discard;
Chris@44 262 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@25 263 }
Chris@25 264
Chris@25 265 QString
Chris@44 266 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const
Chris@25 267 {
Chris@25 268 if (!m_model) return "";
Chris@25 269
Chris@25 270 int x = pos.x();
Chris@25 271 int y = pos.y();
Chris@25 272
Chris@25 273 size_t modelStart = m_model->getStartFrame();
Chris@130 274 size_t modelResolution = m_model->getResolution();
Chris@25 275
Chris@159 276 float srRatio =
Chris@159 277 float(v->getViewManager()->getMainModelSampleRate()) /
Chris@159 278 float(m_model->getSampleRate());
Chris@159 279
Chris@160 280 int sx0 = int((v->getFrameForX(x) / srRatio - long(modelStart)) /
Chris@160 281 long(modelResolution));
Chris@25 282
Chris@160 283 int f0 = sx0 * modelResolution;
Chris@160 284 int f1 = f0 + modelResolution;
Chris@160 285
Chris@160 286 float binHeight = float(v->height()) / m_model->getHeight();
Chris@248 287 int sy = int((v->height() - y) / binHeight);
Chris@25 288
Chris@160 289 float value = m_model->getValueAt(sx0, sy);
Chris@159 290
Chris@159 291 // std::cerr << "bin value (" << sx0 << "," << sy << ") is " << value << std::endl;
Chris@25 292
Chris@25 293 QString binName = m_model->getBinName(sy);
Chris@25 294 if (binName == "") binName = QString("[%1]").arg(sy + 1);
Chris@25 295 else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
Chris@25 296
Chris@25 297 QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
Chris@160 298 .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
Chris@25 299 .toText(true).c_str())
Chris@160 300 .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
Chris@25 301 .toText(true).c_str())
Chris@25 302 .arg(binName)
Chris@25 303 .arg(value);
Chris@25 304
Chris@25 305 return text;
Chris@25 306 }
Chris@25 307
Chris@25 308 int
Chris@248 309 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const
Chris@159 310 {
Chris@159 311 int cw = 20;
Chris@159 312 return cw;
Chris@159 313 }
Chris@159 314
Chris@159 315 int
Chris@248 316 Colour3DPlotLayer::getVerticalScaleWidth(View *, QPainter &paint) const
Chris@25 317 {
Chris@25 318 if (!m_model) return 0;
Chris@25 319
Chris@160 320 QString sampleText = QString("[%1]").arg(m_model->getHeight());
Chris@25 321 int tw = paint.fontMetrics().width(sampleText);
Chris@98 322 bool another = false;
Chris@25 323
Chris@160 324 for (size_t i = 0; i < m_model->getHeight(); ++i) {
Chris@25 325 if (m_model->getBinName(i).length() > sampleText.length()) {
Chris@25 326 sampleText = m_model->getBinName(i);
Chris@98 327 another = true;
Chris@25 328 }
Chris@25 329 }
Chris@98 330 if (another) {
Chris@25 331 tw = std::max(tw, paint.fontMetrics().width(sampleText));
Chris@25 332 }
Chris@25 333
Chris@159 334 return tw + 13 + getColourScaleWidth(paint);
Chris@25 335 }
Chris@25 336
Chris@25 337 void
Chris@44 338 Colour3DPlotLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
Chris@25 339 {
Chris@25 340 if (!m_model) return;
Chris@25 341
Chris@25 342 int h = rect.height(), w = rect.width();
Chris@160 343 float binHeight = float(v->height()) / m_model->getHeight();
Chris@25 344
Chris@159 345 int cw = getColourScaleWidth(paint);
Chris@159 346
Chris@159 347 int ch = h - 20;
Chris@159 348 if (ch > 20 && m_cache) {
Chris@159 349
Chris@287 350 paint.setPen(v->getForeground());
Chris@159 351 paint.drawRect(4, 10, cw - 8, ch - 19);
Chris@159 352
Chris@159 353 for (int y = 0; y < ch - 20; ++y) {
Chris@159 354 QRgb c = m_cache->color(((ch - 20 - y) * 255) / (ch - 20));
Chris@159 355 // std::cerr << "y = " << y << ": rgb " << qRed(c) << "," << qGreen(c) << "," << qBlue(c) << std::endl;
Chris@159 356 paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c)));
Chris@159 357 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
Chris@159 358 }
Chris@159 359 }
Chris@159 360
Chris@287 361 paint.setPen(v->getForeground());
Chris@159 362
Chris@98 363 int count = v->height() / paint.fontMetrics().height();
Chris@160 364 int step = m_model->getHeight() / count;
Chris@98 365 if (step == 0) step = 1;
Chris@25 366
Chris@160 367 for (size_t i = 0; i < m_model->getHeight(); ++i) {
Chris@25 368
Chris@98 369 if ((i % step) != 0) continue;
Chris@98 370
Chris@248 371 int y0 = int(v->height() - (i * binHeight) - 1);
Chris@25 372
Chris@25 373 QString text = m_model->getBinName(i);
Chris@25 374 if (text == "") text = QString("[%1]").arg(i + 1);
Chris@25 375
Chris@159 376 paint.drawLine(cw, y0, w, y0);
Chris@25 377
Chris@248 378 int cy = int(y0 - (step * binHeight)/2);
Chris@25 379 int ty = cy + paint.fontMetrics().ascent()/2;
Chris@25 380
Chris@159 381 paint.drawText(cw + 5, ty, text);
Chris@25 382 }
Chris@25 383 }
Chris@25 384
Chris@0 385 void
Chris@197 386 Colour3DPlotLayer::getColumn(size_t col,
Chris@197 387 DenseThreeDimensionalModel::Column &values) const
Chris@197 388 {
Chris@197 389 m_model->getColumn(col, values);
Chris@197 390
Chris@224 391 float colMax = 0.f, colMin = 0.f;
Chris@197 392
Chris@197 393 float min = 0.f, max = 0.f;
Chris@197 394 if (m_normalizeColumns) {
Chris@197 395 min = m_model->getMinimumLevel();
Chris@197 396 max = m_model->getMaximumLevel();
Chris@197 397 }
Chris@197 398
Chris@197 399 if (m_normalizeColumns) {
Chris@197 400 for (size_t y = 0; y < values.size(); ++y) {
Chris@224 401 if (y == 0 || values[y] > colMax) colMax = values[y];
Chris@224 402 if (y == 0 || values[y] < colMin) colMin = values[y];
Chris@197 403 }
Chris@224 404 if (colMin == colMax) colMax = colMin + 1;
Chris@197 405 }
Chris@197 406
Chris@197 407 for (size_t y = 0; y < values.size(); ++y) {
Chris@197 408
Chris@197 409 float value = min;
Chris@197 410
Chris@197 411 value = values[y];
Chris@197 412
Chris@197 413 if (m_normalizeColumns) {
Chris@224 414 float norm = (value - colMin) / (colMax - colMin);
Chris@224 415 value = min + (max - min) * norm;
Chris@197 416 }
Chris@197 417
Chris@197 418 values[y] = value;
Chris@197 419 }
Chris@197 420 }
Chris@197 421
Chris@197 422 void
Chris@197 423 Colour3DPlotLayer::fillCache(size_t firstBin, size_t lastBin) const
Chris@197 424 {
Chris@197 425 size_t modelStart = m_model->getStartFrame();
Chris@197 426 size_t modelEnd = m_model->getEndFrame();
Chris@197 427 size_t modelResolution = m_model->getResolution();
Chris@197 428
Chris@224 429 // std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl;
Chris@197 430
Chris@197 431 if (!m_normalizeVisibleArea || m_normalizeColumns) {
Chris@197 432 firstBin = modelStart / modelResolution;
Chris@197 433 lastBin = modelEnd / modelResolution;
Chris@197 434 }
Chris@197 435
Chris@197 436 size_t cacheWidth = lastBin - firstBin + 1;
Chris@197 437 size_t cacheHeight = m_model->getHeight();
Chris@197 438
Chris@197 439 if (m_cache &&
Chris@197 440 (m_cacheStart != firstBin ||
Chris@248 441 m_cache->width() != int(cacheWidth) ||
Chris@248 442 m_cache->height() != int(cacheHeight))) {
Chris@197 443
Chris@197 444 delete m_cache;
Chris@197 445 m_cache = 0;
Chris@197 446 }
Chris@197 447
Chris@197 448 if (m_cache) return;
Chris@197 449
Chris@197 450 m_cache = new QImage(cacheWidth, cacheHeight, QImage::Format_Indexed8);
Chris@197 451 m_cacheStart = firstBin;
Chris@197 452
Chris@224 453 // std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " starting " << m_cacheStart << std::endl;
Chris@197 454
Chris@197 455 m_cache->setNumColors(256);
Chris@197 456 DenseThreeDimensionalModel::Column values;
Chris@197 457
Chris@197 458 float min = m_model->getMinimumLevel();
Chris@197 459 float max = m_model->getMaximumLevel();
Chris@197 460
Chris@197 461 if (m_colourScale == LogScale) {
Chris@197 462 LogRange::mapRange(min, max);
Chris@197 463 } else if (m_colourScale == PlusMinusOneScale) {
Chris@197 464 min = -1.f;
Chris@197 465 max = 1.f;
Chris@197 466 }
Chris@197 467
Chris@197 468 if (max == min) max = min + 1.0;
Chris@197 469
Chris@197 470 ColourMapper mapper(m_colourMap, 0.f, 255.f);
Chris@197 471
Chris@197 472 for (int index = 0; index < 256; ++index) {
Chris@197 473
Chris@197 474 QColor colour = mapper.map(index);
Chris@197 475 m_cache->setColor(index, qRgb(colour.red(), colour.green(), colour.blue()));
Chris@197 476 }
Chris@197 477
Chris@197 478 m_cache->fill(0);
Chris@197 479
Chris@224 480 float visibleMax = 0.f, visibleMin = 0.f;
Chris@197 481
Chris@197 482 if (m_normalizeVisibleArea && !m_normalizeColumns) {
Chris@197 483
Chris@197 484 for (size_t c = firstBin; c <= lastBin; ++c) {
Chris@197 485
Chris@197 486 values.clear();
Chris@197 487 getColumn(c, values);
Chris@197 488
Chris@224 489 float colMax = 0.f, colMin = 0.f;
Chris@197 490
Chris@197 491 for (size_t y = 0; y < m_model->getHeight(); ++y) {
Chris@197 492 if (y >= values.size()) break;
Chris@197 493 if (y == 0 || values[y] > colMax) colMax = values[y];
Chris@224 494 if (y == 0 || values[y] < colMin) colMin = values[y];
Chris@197 495 }
Chris@197 496
Chris@197 497 if (c == firstBin || colMax > visibleMax) visibleMax = colMax;
Chris@224 498 if (c == firstBin || colMin < visibleMin) visibleMin = colMin;
Chris@197 499 }
Chris@197 500 }
Chris@197 501
Chris@224 502 if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
Chris@224 503
Chris@197 504 for (size_t c = firstBin; c <= lastBin; ++c) {
Chris@197 505
Chris@197 506 values.clear();
Chris@197 507 getColumn(c, values);
Chris@197 508
Chris@197 509 for (size_t y = 0; y < m_model->getHeight(); ++y) {
Chris@197 510
Chris@197 511 float value = min;
Chris@197 512 if (y < values.size()) {
Chris@197 513 value = values[y];
Chris@197 514 }
Chris@197 515
Chris@197 516 if (m_normalizeVisibleArea && !m_normalizeColumns) {
Chris@224 517 float norm = (value - visibleMin) / (visibleMax - visibleMin);
Chris@224 518 value = min + (max - min) * norm;
Chris@224 519 }
Chris@224 520
Chris@224 521 if (m_colourScale == LogScale) {
Chris@224 522 value = LogRange::map(value);
Chris@197 523 }
Chris@197 524
Chris@197 525 int pixel = int(((value - min) * 256) / (max - min));
Chris@197 526 if (pixel < 0) pixel = 0;
Chris@197 527 if (pixel > 255) pixel = 255;
Chris@197 528
Chris@197 529 m_cache->setPixel(c - firstBin, y, pixel);
Chris@197 530 }
Chris@197 531 }
Chris@197 532 }
Chris@197 533
Chris@197 534 void
Chris@44 535 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const
Chris@0 536 {
Chris@0 537 // Profiler profiler("Colour3DPlotLayer::paint");
Chris@125 538 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@125 539 std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl;
Chris@125 540 #endif
Chris@0 541
Chris@0 542 int completion = 0;
Chris@0 543 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
Chris@0 544 if (completion > 0) {
Chris@44 545 paint.fillRect(0, 10, v->width() * completion / 100,
Chris@0 546 10, QColor(120, 120, 120));
Chris@0 547 }
Chris@0 548 return;
Chris@0 549 }
Chris@0 550
Chris@197 551 if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect();
Chris@197 552
Chris@0 553 size_t modelStart = m_model->getStartFrame();
Chris@0 554 size_t modelEnd = m_model->getEndFrame();
Chris@130 555 size_t modelResolution = m_model->getResolution();
Chris@0 556
Chris@197 557 // The cache is from the model's start frame to the model's end
Chris@197 558 // frame at the model's window increment frames per pixel. We
Chris@197 559 // want to draw from our start frame + x0 * zoomLevel to our start
Chris@197 560 // frame + x1 * zoomLevel at zoomLevel frames per pixel.
Chris@12 561
Chris@197 562 // We have quite different paint mechanisms for rendering "large"
Chris@197 563 // bins (more than one bin per pixel in both directions) and
Chris@197 564 // "small". This is "large"; see paintDense below for "small".
Chris@12 565
Chris@197 566 int x0 = rect.left();
Chris@197 567 int x1 = rect.right() + 1;
Chris@12 568
Chris@197 569 int h = v->height();
Chris@0 570
Chris@197 571 float srRatio =
Chris@197 572 float(v->getViewManager()->getMainModelSampleRate()) /
Chris@197 573 float(m_model->getSampleRate());
Chris@0 574
Chris@197 575 int sx0 = int((v->getFrameForX(x0) / srRatio - long(modelStart))
Chris@197 576 / long(modelResolution));
Chris@197 577 int sx1 = int((v->getFrameForX(x1) / srRatio - long(modelStart))
Chris@197 578 / long(modelResolution));
Chris@197 579 int sh = m_model->getHeight();
Chris@159 580
Chris@197 581 if (sx0 > 0) --sx0;
Chris@197 582 fillCache(sx0 < 0 ? 0 : sx0,
Chris@197 583 sx1 < 0 ? 0 : sx1);
Chris@0 584
Chris@248 585 if (int(m_model->getHeight()) >= v->height() ||
Chris@348 586 int(modelResolution * m_model->getSampleRate()) < v->getZoomLevel() / 2) {
Chris@347 587 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@347 588 std::cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << ", calling paintDense" << std::endl;
Chris@347 589 #endif
Chris@98 590 paintDense(v, paint, rect);
Chris@98 591 return;
Chris@98 592 }
Chris@98 593
Chris@125 594 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@347 595 std::cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << std::endl;
Chris@130 596 std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << std::endl;
Chris@125 597 #endif
Chris@0 598
Chris@25 599 QPoint illuminatePos;
Chris@44 600 bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
Chris@54 601 char labelbuf[10];
Chris@25 602
Chris@197 603 for (int sx = sx0; sx <= sx1; ++sx) {
Chris@0 604
Chris@197 605 int scx = 0;
Chris@248 606 if (sx > int(m_cacheStart)) scx = sx - m_cacheStart;
Chris@197 607
Chris@130 608 int fx = sx * int(modelResolution);
Chris@0 609
Chris@248 610 if (fx + int(modelResolution) < int(modelStart) ||
Chris@0 611 fx > int(modelEnd)) continue;
Chris@0 612
Chris@248 613 int rx0 = v->getXForFrame(int((fx + int(modelStart)) * srRatio));
Chris@248 614 int rx1 = v->getXForFrame(int((fx + int(modelStart) + int(modelResolution) + 1) * srRatio));
Chris@54 615
Chris@159 616 int rw = rx1 - rx0;
Chris@159 617 if (rw < 1) rw = 1;
Chris@54 618
Chris@159 619 bool showLabel = (rw > 10 &&
Chris@159 620 paint.fontMetrics().width("0.000000") < rw - 3 &&
Chris@54 621 paint.fontMetrics().height() < (h / sh));
Chris@98 622
Chris@0 623 for (int sy = 0; sy < sh; ++sy) {
Chris@0 624
Chris@0 625 int ry0 = h - (sy * h) / sh - 1;
Chris@0 626 QRgb pixel = qRgb(255, 255, 255);
Chris@197 627 if (scx >= 0 && scx < m_cache->width() &&
Chris@0 628 sy >= 0 && sy < m_cache->height()) {
Chris@197 629 pixel = m_cache->pixel(scx, sy);
Chris@0 630 }
Chris@0 631
Chris@159 632 QRect r(rx0, ry0 - h / sh - 1, rw, h / sh + 1);
Chris@159 633
Chris@159 634 if (rw == 1) {
Chris@159 635 paint.setPen(pixel);
Chris@159 636 paint.setBrush(Qt::NoBrush);
Chris@159 637 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
Chris@159 638 continue;
Chris@159 639 }
Chris@159 640
Chris@0 641 QColor pen(255, 255, 255, 80);
Chris@0 642 QColor brush(pixel);
Chris@159 643
Chris@159 644 if (rw > 3 && r.height() > 3) {
Chris@159 645 brush.setAlpha(160);
Chris@159 646 }
Chris@159 647
Chris@0 648 paint.setPen(Qt::NoPen);
Chris@0 649 paint.setBrush(brush);
Chris@0 650
Chris@25 651 if (illuminate) {
Chris@25 652 if (r.contains(illuminatePos)) {
Chris@287 653 paint.setPen(v->getForeground());
Chris@25 654 }
Chris@25 655 }
Chris@76 656
Chris@125 657 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
Chris@159 658 std::cerr << "rect " << r.x() << "," << r.y() << " "
Chris@159 659 << r.width() << "x" << r.height() << std::endl;
Chris@125 660 #endif
Chris@25 661
Chris@25 662 paint.drawRect(r);
Chris@0 663
Chris@54 664 if (showLabel) {
Chris@197 665 if (scx >= 0 && scx < m_cache->width() &&
Chris@54 666 sy >= 0 && sy < m_cache->height()) {
Chris@197 667 float value = m_model->getValueAt(scx, sy);
Chris@54 668 sprintf(labelbuf, "%06f", value);
Chris@54 669 QString text(labelbuf);
Chris@287 670 paint.setPen(v->getBackground());
Chris@54 671 paint.drawText(rx0 + 2,
Chris@54 672 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
Chris@54 673 text);
Chris@0 674 }
Chris@0 675 }
Chris@0 676 }
Chris@0 677 }
Chris@98 678 }
Chris@0 679
Chris@98 680 void
Chris@98 681 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const
Chris@98 682 {
Chris@98 683 size_t modelStart = m_model->getStartFrame();
Chris@130 684 size_t modelResolution = m_model->getResolution();
Chris@0 685
Chris@159 686 float srRatio =
Chris@159 687 float(v->getViewManager()->getMainModelSampleRate()) /
Chris@159 688 float(m_model->getSampleRate());
Chris@159 689
Chris@98 690 int x0 = rect.left();
Chris@98 691 int x1 = rect.right() + 1;
Chris@0 692
Chris@98 693 int w = x1 - x0;
Chris@98 694 int h = v->height();
Chris@160 695 int sh = m_model->getHeight();
Chris@98 696
Chris@98 697 QImage img(w, h, QImage::Format_RGB32);
Chris@98 698
Chris@98 699 for (int x = x0; x < x1; ++x) {
Chris@98 700
Chris@347 701 long xf = long(v->getFrameForX(x));
Chris@105 702 if (xf < 0) {
Chris@105 703 for (int y = 0; y < h; ++y) {
Chris@105 704 img.setPixel(x - x0, y, m_cache->color(0));
Chris@105 705 }
Chris@105 706 continue;
Chris@105 707 }
Chris@105 708
Chris@347 709 xf /= srRatio;
Chris@347 710
Chris@130 711 float sx0 = (float(xf) - modelStart) / modelResolution;
Chris@159 712 float sx1 = (float(v->getFrameForX(x+1) / srRatio) - modelStart) / modelResolution;
Chris@98 713
Chris@98 714 int sx0i = int(sx0 + 0.001);
Chris@98 715 int sx1i = int(sx1);
Chris@98 716
Chris@98 717 for (int y = 0; y < h; ++y) {
Chris@98 718
Chris@98 719 float sy0 = (float(h - y - 1) * sh) / h;
Chris@98 720 float sy1 = (float(h - y) * sh) / h;
Chris@98 721
Chris@98 722 int sy0i = int(sy0 + 0.001);
Chris@98 723 int sy1i = int(sy1);
Chris@98 724
Chris@98 725 float mag = 0.0, div = 0.0;
Chris@159 726 int max = 0;
Chris@98 727
Chris@98 728 for (int sx = sx0i; sx <= sx1i; ++sx) {
Chris@98 729
Chris@197 730 int scx = 0;
Chris@248 731 if (sx > int(m_cacheStart)) scx = sx - int(m_cacheStart);
Chris@197 732
Chris@197 733 if (scx < 0 || scx >= m_cache->width()) continue;
Chris@98 734
Chris@98 735 for (int sy = sy0i; sy <= sy1i; ++sy) {
Chris@98 736
Chris@98 737 if (sy < 0 || sy >= m_cache->height()) continue;
Chris@98 738
Chris@98 739 float prop = 1.0;
Chris@98 740 if (sx == sx0i) prop *= (sx + 1) - sx0;
Chris@98 741 if (sx == sx1i) prop *= sx1 - sx;
Chris@98 742 if (sy == sy0i) prop *= (sy + 1) - sy0;
Chris@98 743 if (sy == sy1i) prop *= sy1 - sy;
Chris@98 744
Chris@197 745 mag += prop * m_cache->pixelIndex(scx, sy);
Chris@197 746 max = std::max(max, m_cache->pixelIndex(scx, sy));
Chris@98 747 div += prop;
Chris@98 748 }
Chris@98 749 }
Chris@98 750
Chris@98 751 if (div != 0) mag /= div;
Chris@98 752 if (mag < 0) mag = 0;
Chris@98 753 if (mag > 255) mag = 255;
Chris@159 754 if (max < 0) max = 0;
Chris@159 755 if (max > 255) max = 255;
Chris@98 756
Chris@98 757 img.setPixel(x - x0, y, m_cache->color(int(mag + 0.001)));
Chris@159 758 // img.setPixel(x - x0, y, m_cache->color(max));
Chris@98 759 }
Chris@0 760 }
Chris@0 761
Chris@98 762 paint.drawImage(x0, 0, img);
Chris@0 763 }
Chris@0 764
Chris@28 765 bool
Chris@44 766 Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame,
Chris@28 767 size_t &resolution,
Chris@28 768 SnapType snap) const
Chris@24 769 {
Chris@24 770 if (!m_model) {
Chris@44 771 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@24 772 }
Chris@24 773
Chris@130 774 resolution = m_model->getResolution();
Chris@28 775 int left = (frame / resolution) * resolution;
Chris@28 776 int right = left + resolution;
Chris@28 777
Chris@28 778 switch (snap) {
Chris@28 779 case SnapLeft: frame = left; break;
Chris@28 780 case SnapRight: frame = right; break;
Chris@28 781 case SnapNearest:
Chris@28 782 case SnapNeighbouring:
Chris@28 783 if (frame - left > right - frame) frame = right;
Chris@28 784 else frame = left;
Chris@28 785 break;
Chris@28 786 }
Chris@24 787
Chris@28 788 return true;
Chris@24 789 }
Chris@24 790
Chris@316 791 void
Chris@316 792 Colour3DPlotLayer::toXml(QTextStream &stream,
Chris@316 793 QString indent, QString extraAttributes) const
Chris@197 794 {
Chris@316 795 QString s = QString("scale=\"%1\" "
Chris@316 796 "colourScheme=\"%2\" "
Chris@316 797 "normalizeColumns=\"%3\" "
Chris@316 798 "normalizeVisibleArea=\"%4\"")
Chris@197 799 .arg((int)m_colourScale)
Chris@197 800 .arg(m_colourMap)
Chris@197 801 .arg(m_normalizeColumns ? "true" : "false")
Chris@197 802 .arg(m_normalizeVisibleArea ? "true" : "false");
Chris@197 803
Chris@316 804 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@197 805 }
Chris@197 806
Chris@197 807 void
Chris@197 808 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
Chris@197 809 {
Chris@197 810 bool ok = false;
Chris@197 811
Chris@197 812 ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok);
Chris@197 813 if (ok) setColourScale(scale);
Chris@197 814
Chris@197 815 int colourMap = attributes.value("colourScheme").toInt(&ok);
Chris@197 816 if (ok) setColourMap(colourMap);
Chris@197 817
Chris@197 818 bool normalizeColumns =
Chris@197 819 (attributes.value("normalizeColumns").trimmed() == "true");
Chris@197 820 setNormalizeColumns(normalizeColumns);
Chris@197 821
Chris@197 822 bool normalizeVisibleArea =
Chris@197 823 (attributes.value("normalizeVisibleArea").trimmed() == "true");
Chris@197 824 setNormalizeVisibleArea(normalizeVisibleArea);
Chris@197 825 }
Chris@197 826