annotate layer/Colour3DPlotLayer.cpp @ 282:d9319859a4cf tip

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