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