annotate layer/Colour3DPlotLayer.cpp @ 312:6de6f78b13a1

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