annotate layer/Colour3DPlotLayer.cpp @ 333:e74b56f07c73

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