comparison layer/Colour3DPlotLayer.cpp @ 1216:dc2af6616c83

Merge from branch 3.0-integration
author Chris Cannam
date Fri, 13 Jan 2017 10:29:50 +0000
parents a1ee3108d1d3
children 2954e9952b78
comparison
equal deleted inserted replaced
1048:e8102ff5573b 1216:dc2af6616c83
13 COPYING included with this distribution for more information. 13 COPYING included with this distribution for more information.
14 */ 14 */
15 15
16 #include "Colour3DPlotLayer.h" 16 #include "Colour3DPlotLayer.h"
17 17
18 #include "view/View.h"
19 #include "base/Profiler.h" 18 #include "base/Profiler.h"
20 #include "base/LogRange.h" 19 #include "base/LogRange.h"
21 #include "base/RangeMapper.h" 20 #include "base/RangeMapper.h"
21
22 #include "ColourMapper.h" 22 #include "ColourMapper.h"
23 #include "LayerGeometryProvider.h"
24 #include "PaintAssistant.h"
25
26 #include "data/model/Dense3DModelPeakCache.h"
27
28 #include "view/ViewManager.h"
23 29
24 #include <QPainter> 30 #include <QPainter>
25 #include <QImage> 31 #include <QImage>
26 #include <QRect> 32 #include <QRect>
27 #include <QTextStream> 33 #include <QTextStream>
34 #include <QSettings>
28 35
29 #include <iostream> 36 #include <iostream>
30 37
31 #include <cassert> 38 #include <cassert>
32
33 #ifndef __GNUC__
34 #include <alloca.h>
35 #endif
36 39
37 using std::vector; 40 using std::vector;
38 41
39 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1 42 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
40 43
41 44
42 Colour3DPlotLayer::Colour3DPlotLayer() : 45 Colour3DPlotLayer::Colour3DPlotLayer() :
43 m_model(0), 46 m_model(0),
44 m_cache(0), 47 m_colourScale(ColourScaleType::Linear),
45 m_peaksCache(0),
46 m_cacheValidStart(0),
47 m_cacheValidEnd(0),
48 m_colourScale(LinearScale),
49 m_colourScaleSet(false), 48 m_colourScaleSet(false),
50 m_colourMap(0), 49 m_colourMap(0),
51 m_gain(1.0), 50 m_gain(1.0),
52 m_binScale(LinearBinScale), 51 m_binScale(BinScale::Linear),
53 m_normalizeColumns(false), 52 m_normalization(ColumnNormalization::None),
54 m_normalizeVisibleArea(false), 53 m_normalizeVisibleArea(false),
55 m_normalizeHybrid(false),
56 m_invertVertical(false), 54 m_invertVertical(false),
57 m_opaque(false), 55 m_opaque(false),
58 m_smooth(false), 56 m_smooth(false),
59 m_peakResolution(256), 57 m_peakResolution(256),
60 m_miny(0), 58 m_miny(0),
61 m_maxy(0) 59 m_maxy(0),
62 { 60 m_synchronous(false),
63 61 m_peakCache(0),
62 m_peakCacheDivisor(8)
63 {
64 QSettings settings;
65 settings.beginGroup("Preferences");
66 setColourMap(settings.value("colour-3d-plot-colour", ColourMapper::Green).toInt());
67 settings.endGroup();
64 } 68 }
65 69
66 Colour3DPlotLayer::~Colour3DPlotLayer() 70 Colour3DPlotLayer::~Colour3DPlotLayer()
67 { 71 {
68 delete m_cache; 72 invalidateRenderers();
69 delete m_peaksCache; 73 delete m_peakCache;
74 }
75
76 ColourScaleType
77 Colour3DPlotLayer::convertToColourScale(int value)
78 {
79 switch (value) {
80 default:
81 case 0: return ColourScaleType::Linear;
82 case 1: return ColourScaleType::Log;
83 case 2: return ColourScaleType::PlusMinusOne;
84 case 3: return ColourScaleType::Absolute;
85 }
86 }
87
88 int
89 Colour3DPlotLayer::convertFromColourScale(ColourScaleType scale)
90 {
91 switch (scale) {
92 case ColourScaleType::Linear: return 0;
93 case ColourScaleType::Log: return 1;
94 case ColourScaleType::PlusMinusOne: return 2;
95 case ColourScaleType::Absolute: return 3;
96
97 case ColourScaleType::Meter:
98 case ColourScaleType::Phase:
99 default: return 0;
100 }
101 }
102
103 std::pair<ColumnNormalization, bool>
104 Colour3DPlotLayer::convertToColumnNorm(int value)
105 {
106 switch (value) {
107 default:
108 case 0: return { ColumnNormalization::None, false };
109 case 1: return { ColumnNormalization::Max1, false };
110 case 2: return { ColumnNormalization::None, true }; // visible area
111 case 3: return { ColumnNormalization::Hybrid, false };
112 }
113 }
114
115 int
116 Colour3DPlotLayer::convertFromColumnNorm(ColumnNormalization norm, bool visible)
117 {
118 if (visible) return 2;
119 switch (norm) {
120 case ColumnNormalization::None: return 0;
121 case ColumnNormalization::Max1: return 1;
122 case ColumnNormalization::Hybrid: return 3;
123
124 case ColumnNormalization::Sum1:
125 default: return 0;
126 }
127 }
128
129 void
130 Colour3DPlotLayer::setSynchronousPainting(bool synchronous)
131 {
132 m_synchronous = synchronous;
70 } 133 }
71 134
72 void 135 void
73 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model) 136 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
74 { 137 {
89 } else if (model->getResolution() > 128) { 152 } else if (model->getResolution() > 128) {
90 m_peakResolution = 64; 153 m_peakResolution = 64;
91 } else if (model->getResolution() > 2) { 154 } else if (model->getResolution() > 2) {
92 m_peakResolution = 128; 155 m_peakResolution = 128;
93 } 156 }
94 cacheInvalid(); 157
158 delete m_peakCache;
159 m_peakCache = 0;
160
161 invalidateRenderers();
95 162
96 emit modelReplaced(); 163 emit modelReplaced();
97 emit sliceableModelReplaced(oldModel, model); 164 emit sliceableModelReplaced(oldModel, model);
98 } 165 }
99 166
100 void 167 void
101 Colour3DPlotLayer::cacheInvalid() 168 Colour3DPlotLayer::cacheInvalid()
102 { 169 {
103 delete m_cache; 170 invalidateRenderers();
104 delete m_peaksCache; 171 }
105 m_cache = 0; 172
106 m_peaksCache = 0; 173 void
107 m_cacheValidStart = 0; 174 Colour3DPlotLayer::cacheInvalid(sv_frame_t /* startFrame */,
108 m_cacheValidEnd = 0; 175 sv_frame_t /* endFrame */)
109 } 176 {
110 177 //!!! should do this only if the range is visible
111 void 178 delete m_peakCache;
112 Colour3DPlotLayer::cacheInvalid(sv_frame_t startFrame, sv_frame_t endFrame) 179 m_peakCache = 0;
113 { 180
114 if (!m_cache || !m_model) return; 181 invalidateRenderers();
115 182 }
116 int modelResolution = m_model->getResolution(); 183
117 int start = int(startFrame / modelResolution); 184 void
118 int end = int(endFrame / modelResolution + 1); 185 Colour3DPlotLayer::invalidateRenderers()
119 if (m_cacheValidStart < end) m_cacheValidStart = end; 186 {
120 if (m_cacheValidEnd > start) m_cacheValidEnd = start; 187 for (ViewRendererMap::iterator i = m_renderers.begin();
121 if (m_cacheValidStart > m_cacheValidEnd) m_cacheValidEnd = m_cacheValidStart; 188 i != m_renderers.end(); ++i) {
189 delete i->second;
190 }
191 m_renderers.clear();
192 }
193
194 Dense3DModelPeakCache *
195 Colour3DPlotLayer::getPeakCache() const
196 {
197 if (!m_peakCache) {
198 m_peakCache = new Dense3DModelPeakCache(m_model, m_peakCacheDivisor);
199 }
200 return m_peakCache;
122 } 201 }
123 202
124 void 203 void
125 Colour3DPlotLayer::modelChanged() 204 Colour3DPlotLayer::modelChanged()
126 { 205 {
127 if (!m_colourScaleSet && m_colourScale == LinearScale) { 206 if (!m_colourScaleSet && m_colourScale == ColourScaleType::Linear) {
128 if (m_model) { 207 if (m_model) {
129 if (m_model->shouldUseLogValueScale()) { 208 if (m_model->shouldUseLogValueScale()) {
130 setColourScale(LogScale); 209 setColourScale(ColourScaleType::Log);
131 } else { 210 } else {
132 m_colourScaleSet = true; 211 m_colourScaleSet = true;
133 } 212 }
134 } 213 }
135 } 214 }
137 } 216 }
138 217
139 void 218 void
140 Colour3DPlotLayer::modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame) 219 Colour3DPlotLayer::modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame)
141 { 220 {
142 if (!m_colourScaleSet && m_colourScale == LinearScale) { 221 if (!m_colourScaleSet && m_colourScale == ColourScaleType::Linear) {
143 if (m_model && m_model->getWidth() > 50) { 222 if (m_model && m_model->getWidth() > 50) {
144 if (m_model->shouldUseLogValueScale()) { 223 if (m_model->shouldUseLogValueScale()) {
145 setColourScale(LogScale); 224 setColourScale(ColourScaleType::Log);
146 } else { 225 } else {
147 m_colourScaleSet = true; 226 m_colourScaleSet = true;
148 } 227 }
149 } 228 }
150 } 229 }
155 Colour3DPlotLayer::getProperties() const 234 Colour3DPlotLayer::getProperties() const
156 { 235 {
157 PropertyList list; 236 PropertyList list;
158 list.push_back("Colour"); 237 list.push_back("Colour");
159 list.push_back("Colour Scale"); 238 list.push_back("Colour Scale");
160 list.push_back("Normalize Columns"); 239 list.push_back("Normalization");
161 list.push_back("Normalize Visible Area");
162 list.push_back("Gain"); 240 list.push_back("Gain");
163 list.push_back("Bin Scale"); 241 list.push_back("Bin Scale");
164 list.push_back("Invert Vertical Scale"); 242 list.push_back("Invert Vertical Scale");
165 list.push_back("Opaque"); 243 list.push_back("Opaque");
166 list.push_back("Smooth"); 244 list.push_back("Smooth");
170 QString 248 QString
171 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const 249 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
172 { 250 {
173 if (name == "Colour") return tr("Colour"); 251 if (name == "Colour") return tr("Colour");
174 if (name == "Colour Scale") return tr("Scale"); 252 if (name == "Colour Scale") return tr("Scale");
175 if (name == "Normalize Columns") return tr("Normalize Columns"); 253 if (name == "Normalization") return tr("Normalization");
176 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
177 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); 254 if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
178 if (name == "Gain") return tr("Gain"); 255 if (name == "Gain") return tr("Gain");
179 if (name == "Opaque") return tr("Always Opaque"); 256 if (name == "Opaque") return tr("Always Opaque");
180 if (name == "Smooth") return tr("Smooth"); 257 if (name == "Smooth") return tr("Smooth");
181 if (name == "Bin Scale") return tr("Bin Scale"); 258 if (name == "Bin Scale") return tr("Bin Scale");
183 } 260 }
184 261
185 QString 262 QString
186 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const 263 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
187 { 264 {
188 if (name == "Normalize Columns") return "normalise-columns";
189 if (name == "Normalize Visible Area") return "normalise";
190 if (name == "Invert Vertical Scale") return "invert-vertical"; 265 if (name == "Invert Vertical Scale") return "invert-vertical";
191 if (name == "Opaque") return "opaque"; 266 if (name == "Opaque") return "opaque";
192 if (name == "Smooth") return "smooth"; 267 if (name == "Smooth") return "smooth";
193 return ""; 268 return "";
194 } 269 }
195 270
196 Layer::PropertyType 271 Layer::PropertyType
197 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const 272 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
198 { 273 {
199 if (name == "Gain") return RangeProperty; 274 if (name == "Gain") return RangeProperty;
200 if (name == "Normalize Columns") return ToggleProperty;
201 if (name == "Normalize Visible Area") return ToggleProperty;
202 if (name == "Invert Vertical Scale") return ToggleProperty; 275 if (name == "Invert Vertical Scale") return ToggleProperty;
203 if (name == "Opaque") return ToggleProperty; 276 if (name == "Opaque") return ToggleProperty;
204 if (name == "Smooth") return ToggleProperty; 277 if (name == "Smooth") return ToggleProperty;
278 if (name == "Colour") return ColourMapProperty;
205 return ValueProperty; 279 return ValueProperty;
206 } 280 }
207 281
208 QString 282 QString
209 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const 283 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
210 { 284 {
211 if (name == "Normalize Columns" || 285 if (name == "Normalization" ||
212 name == "Normalize Visible Area" || 286 name == "Colour Scale" ||
213 name == "Colour Scale" ||
214 name == "Gain") return tr("Scale"); 287 name == "Gain") return tr("Scale");
215 if (name == "Bin Scale" || 288 if (name == "Bin Scale" ||
216 name == "Invert Vertical Scale") return tr("Bins"); 289 name == "Invert Vertical Scale") return tr("Bins");
217 if (name == "Opaque" || 290 if (name == "Opaque" ||
218 name == "Smooth" || 291 name == "Smooth" ||
244 if (val < *min) val = *min; 317 if (val < *min) val = *min;
245 if (val > *max) val = *max; 318 if (val > *max) val = *max;
246 319
247 } else if (name == "Colour Scale") { 320 } else if (name == "Colour Scale") {
248 321
322 // linear, log, +/-1, abs
249 *min = 0; 323 *min = 0;
250 *max = 3; 324 *max = 3;
251 *deflt = (int)LinearScale; 325 *deflt = 0;
252 326
253 val = (int)m_colourScale; 327 val = convertFromColourScale(m_colourScale);
254 328
255 } else if (name == "Colour") { 329 } else if (name == "Colour") {
256 330
257 *min = 0; 331 *min = 0;
258 *max = ColourMapper::getColourMapCount() - 1; 332 *max = ColourMapper::getColourMapCount() - 1;
259 *deflt = 0; 333 *deflt = 0;
260 334
261 val = m_colourMap; 335 val = m_colourMap;
262 336
263 } else if (name == "Normalize Columns") { 337 } else if (name == "Normalization") {
264 338
339 *min = 0;
340 *max = 3;
265 *deflt = 0; 341 *deflt = 0;
266 val = (m_normalizeColumns ? 1 : 0); 342
267 343 val = convertFromColumnNorm(m_normalization, m_normalizeVisibleArea);
268 } else if (name == "Normalize Visible Area") {
269
270 *deflt = 0;
271 val = (m_normalizeVisibleArea ? 1 : 0);
272 344
273 } else if (name == "Invert Vertical Scale") { 345 } else if (name == "Invert Vertical Scale") {
274 346
275 *deflt = 0; 347 *deflt = 0;
276 val = (m_invertVertical ? 1 : 0); 348 val = (m_invertVertical ? 1 : 0);
277 349
278 } else if (name == "Bin Scale") { 350 } else if (name == "Bin Scale") {
279 351
280 *min = 0; 352 *min = 0;
281 *max = 1; 353 *max = 1;
282 *deflt = int(LinearBinScale); 354 *deflt = int(BinScale::Linear);
283 val = (int)m_binScale; 355 val = (int)m_binScale;
284 356
285 } else if (name == "Opaque") { 357 } else if (name == "Opaque") {
286 358
287 *deflt = 0; 359 *deflt = 0;
313 case 1: return tr("Log"); 385 case 1: return tr("Log");
314 case 2: return tr("+/-1"); 386 case 2: return tr("+/-1");
315 case 3: return tr("Absolute"); 387 case 3: return tr("Absolute");
316 } 388 }
317 } 389 }
390 if (name == "Normalization") {
391 switch(value) {
392 default:
393 case 0: return tr("None");
394 case 1: return tr("Col");
395 case 2: return tr("View");
396 case 3: return tr("Hybrid");
397 }
398 // return ""; // icon only
399 }
318 if (name == "Bin Scale") { 400 if (name == "Bin Scale") {
319 switch (value) { 401 switch (value) {
320 default: 402 default:
321 case 0: return tr("Linear"); 403 case 0: return tr("Linear");
322 case 1: return tr("Log"); 404 case 1: return tr("Log");
323 } 405 }
324 } 406 }
325 return tr("<unknown>"); 407 return tr("<unknown>");
326 } 408 }
327 409
410 QString
411 Colour3DPlotLayer::getPropertyValueIconName(const PropertyName &name,
412 int value) const
413 {
414 if (name == "Normalization") {
415 switch(value) {
416 default:
417 case 0: return "normalise-none";
418 case 1: return "normalise-columns";
419 case 2: return "normalise";
420 case 3: return "normalise-hybrid";
421 }
422 }
423 return "";
424 }
425
328 RangeMapper * 426 RangeMapper *
329 Colour3DPlotLayer::getNewPropertyRangeMapper(const PropertyName &name) const 427 Colour3DPlotLayer::getNewPropertyRangeMapper(const PropertyName &name) const
330 { 428 {
331 if (name == "Gain") { 429 if (name == "Gain") {
332 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB")); 430 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
338 Colour3DPlotLayer::setProperty(const PropertyName &name, int value) 436 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
339 { 437 {
340 if (name == "Gain") { 438 if (name == "Gain") {
341 setGain(float(pow(10, value/20.0))); 439 setGain(float(pow(10, value/20.0)));
342 } else if (name == "Colour Scale") { 440 } else if (name == "Colour Scale") {
343 switch (value) { 441 setColourScale(convertToColourScale(value));
344 default:
345 case 0: setColourScale(LinearScale); break;
346 case 1: setColourScale(LogScale); break;
347 case 2: setColourScale(PlusMinusOneScale); break;
348 case 3: setColourScale(AbsoluteScale); break;
349 }
350 } else if (name == "Colour") { 442 } else if (name == "Colour") {
351 setColourMap(value); 443 setColourMap(value);
352 } else if (name == "Normalize Columns") {
353 setNormalizeColumns(value ? true : false);
354 } else if (name == "Normalize Visible Area") {
355 setNormalizeVisibleArea(value ? true : false);
356 } else if (name == "Invert Vertical Scale") { 444 } else if (name == "Invert Vertical Scale") {
357 setInvertVertical(value ? true : false); 445 setInvertVertical(value ? true : false);
358 } else if (name == "Opaque") { 446 } else if (name == "Opaque") {
359 setOpaque(value ? true : false); 447 setOpaque(value ? true : false);
360 } else if (name == "Smooth") { 448 } else if (name == "Smooth") {
361 setSmooth(value ? true : false); 449 setSmooth(value ? true : false);
362 } else if (name == "Bin Scale") { 450 } else if (name == "Bin Scale") {
363 switch (value) { 451 switch (value) {
364 default: 452 default:
365 case 0: setBinScale(LinearBinScale); break; 453 case 0: setBinScale(BinScale::Linear); break;
366 case 1: setBinScale(LogBinScale); break; 454 case 1: setBinScale(BinScale::Log); break;
367 } 455 }
368 } 456 } else if (name == "Normalization") {
369 } 457 auto n = convertToColumnNorm(value);
370 458 setNormalization(n.first);
371 void 459 setNormalizeVisibleArea(n.second);
372 Colour3DPlotLayer::setColourScale(ColourScale scale) 460 }
461 }
462
463 void
464 Colour3DPlotLayer::setColourScale(ColourScaleType scale)
373 { 465 {
374 if (m_colourScale == scale) return; 466 if (m_colourScale == scale) return;
375 m_colourScale = scale; 467 m_colourScale = scale;
376 m_colourScaleSet = true; 468 m_colourScaleSet = true;
377 cacheInvalid(); 469 invalidateRenderers();
378 emit layerParametersChanged(); 470 emit layerParametersChanged();
379 } 471 }
380 472
381 void 473 void
382 Colour3DPlotLayer::setColourMap(int map) 474 Colour3DPlotLayer::setColourMap(int map)
383 { 475 {
384 if (m_colourMap == map) return; 476 if (m_colourMap == map) return;
385 m_colourMap = map; 477 m_colourMap = map;
386 cacheInvalid(); 478 invalidateRenderers();
387 emit layerParametersChanged(); 479 emit layerParametersChanged();
388 } 480 }
389 481
390 void 482 void
391 Colour3DPlotLayer::setGain(float gain) 483 Colour3DPlotLayer::setGain(float gain)
392 { 484 {
393 if (m_gain == gain) return; 485 if (m_gain == gain) return;
394 m_gain = gain; 486 m_gain = gain;
395 cacheInvalid(); 487 invalidateRenderers();
396 emit layerParametersChanged(); 488 emit layerParametersChanged();
397 } 489 }
398 490
399 float 491 float
400 Colour3DPlotLayer::getGain() const 492 Colour3DPlotLayer::getGain() const
405 void 497 void
406 Colour3DPlotLayer::setBinScale(BinScale binScale) 498 Colour3DPlotLayer::setBinScale(BinScale binScale)
407 { 499 {
408 if (m_binScale == binScale) return; 500 if (m_binScale == binScale) return;
409 m_binScale = binScale; 501 m_binScale = binScale;
410 cacheInvalid(); 502 invalidateRenderers();
411 emit layerParametersChanged(); 503 emit layerParametersChanged();
412 } 504 }
413 505
414 Colour3DPlotLayer::BinScale 506 BinScale
415 Colour3DPlotLayer::getBinScale() const 507 Colour3DPlotLayer::getBinScale() const
416 { 508 {
417 return m_binScale; 509 return m_binScale;
418 } 510 }
419 511
420 void 512 void
421 Colour3DPlotLayer::setNormalizeColumns(bool n) 513 Colour3DPlotLayer::setNormalization(ColumnNormalization n)
422 { 514 {
423 if (m_normalizeColumns == n) return; 515 if (m_normalization == n) return;
424 m_normalizeColumns = n; 516
425 cacheInvalid(); 517 m_normalization = n;
518 invalidateRenderers();
519
426 emit layerParametersChanged(); 520 emit layerParametersChanged();
427 } 521 }
428 522
429 bool 523 ColumnNormalization
430 Colour3DPlotLayer::getNormalizeColumns() const 524 Colour3DPlotLayer::getNormalization() const
431 { 525 {
432 return m_normalizeColumns; 526 return m_normalization;
433 }
434
435 void
436 Colour3DPlotLayer::setNormalizeHybrid(bool n)
437 {
438 if (m_normalizeHybrid == n) return;
439 m_normalizeHybrid = n;
440 cacheInvalid();
441 emit layerParametersChanged();
442 }
443
444 bool
445 Colour3DPlotLayer::getNormalizeHybrid() const
446 {
447 return m_normalizeHybrid;
448 } 527 }
449 528
450 void 529 void
451 Colour3DPlotLayer::setNormalizeVisibleArea(bool n) 530 Colour3DPlotLayer::setNormalizeVisibleArea(bool n)
452 { 531 {
453 if (m_normalizeVisibleArea == n) return; 532 if (m_normalizeVisibleArea == n) return;
533
454 m_normalizeVisibleArea = n; 534 m_normalizeVisibleArea = n;
455 cacheInvalid(); 535 invalidateRenderers();
536
456 emit layerParametersChanged(); 537 emit layerParametersChanged();
457 } 538 }
458 539
459 bool 540 bool
460 Colour3DPlotLayer::getNormalizeVisibleArea() const 541 Colour3DPlotLayer::getNormalizeVisibleArea() const
465 void 546 void
466 Colour3DPlotLayer::setInvertVertical(bool n) 547 Colour3DPlotLayer::setInvertVertical(bool n)
467 { 548 {
468 if (m_invertVertical == n) return; 549 if (m_invertVertical == n) return;
469 m_invertVertical = n; 550 m_invertVertical = n;
470 cacheInvalid(); 551 invalidateRenderers();
471 emit layerParametersChanged(); 552 emit layerParametersChanged();
472 } 553 }
473 554
474 void 555 void
475 Colour3DPlotLayer::setOpaque(bool n) 556 Colour3DPlotLayer::setOpaque(bool n)
476 { 557 {
477 if (m_opaque == n) return; 558 if (m_opaque == n) return;
478 m_opaque = n; 559 m_opaque = n;
560 invalidateRenderers();
479 emit layerParametersChanged(); 561 emit layerParametersChanged();
480 } 562 }
481 563
482 void 564 void
483 Colour3DPlotLayer::setSmooth(bool n) 565 Colour3DPlotLayer::setSmooth(bool n)
484 { 566 {
485 if (m_smooth == n) return; 567 if (m_smooth == n) return;
486 m_smooth = n; 568 m_smooth = n;
569 invalidateRenderers();
487 emit layerParametersChanged(); 570 emit layerParametersChanged();
488 } 571 }
489 572
490 bool 573 bool
491 Colour3DPlotLayer::getInvertVertical() const 574 Colour3DPlotLayer::getInvertVertical() const
504 { 587 {
505 return m_smooth; 588 return m_smooth;
506 } 589 }
507 590
508 void 591 void
509 Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant) 592 Colour3DPlotLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant)
510 { 593 {
511 if (dormant) { 594 if (dormant) {
512 595
513 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 596 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
514 cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")" 597 cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")"
528 Layer::setLayerDormant(v, false); 611 Layer::setLayerDormant(v, false);
529 } 612 }
530 } 613 }
531 614
532 bool 615 bool
533 Colour3DPlotLayer::isLayerScrollable(const View *v) const 616 Colour3DPlotLayer::isLayerScrollable(const LayerGeometryProvider * /* v */) const
534 { 617 {
535 if (m_normalizeVisibleArea) { 618 if (m_normalizeVisibleArea) {
536 return false; 619 return false;
537 } 620 }
538 if (shouldPaintDenseIn(v)) { 621 //!!! ah hang on, if we're potentially rendering incrementally
539 return true; 622 //!!! they we can't be scrollable
540 } 623 return false;
541 QPoint discard; 624 // if (getRenderer(v)->willRenderOpaque(v)) {
542 return !v->shouldIlluminateLocalFeatures(this, discard); 625 // return true;
626 // }
627 // QPoint discard;
628 // return !v->shouldIlluminateLocalFeatures(this, discard);
543 } 629 }
544 630
545 bool 631 bool
546 Colour3DPlotLayer::getValueExtents(double &min, double &max, 632 Colour3DPlotLayer::getValueExtents(double &min, double &max,
547 bool &logarithmic, QString &unit) const 633 bool &logarithmic, QString &unit) const
582 if (!m_model) return false; 668 if (!m_model) return false;
583 669
584 m_miny = int(lrint(min)); 670 m_miny = int(lrint(min));
585 m_maxy = int(lrint(max)); 671 m_maxy = int(lrint(max));
586 672
673 invalidateRenderers();
674
587 emit layerParametersChanged(); 675 emit layerParametersChanged();
588 return true; 676 return true;
589 } 677 }
590 678
591 bool 679 bool
592 Colour3DPlotLayer::getYScaleValue(const View *, int, 680 Colour3DPlotLayer::getYScaleValue(const LayerGeometryProvider *, int,
593 double &, QString &) const 681 double &, QString &) const
594 { 682 {
595 return false;//!!! 683 return false;//!!!
596 } 684 }
597 685
628 m_miny = int(lrint(centre - dist/2.0)); 716 m_miny = int(lrint(centre - dist/2.0));
629 if (m_miny < 0) m_miny = 0; 717 if (m_miny < 0) m_miny = 0;
630 m_maxy = m_miny + dist; 718 m_maxy = m_miny + dist;
631 if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight(); 719 if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight();
632 720
721 invalidateRenderers();
722
633 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): after: miny = " << m_miny << ", maxy = " << m_maxy << endl; 723 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): after: miny = " << m_miny << ", maxy = " << m_maxy << endl;
634 724
635 emit layerParametersChanged(); 725 emit layerParametersChanged();
636 } 726 }
637 727
643 return new LinearRangeMapper(0, m_model->getHeight(), 733 return new LinearRangeMapper(0, m_model->getHeight(),
644 0, m_model->getHeight(), ""); 734 0, m_model->getHeight(), "");
645 } 735 }
646 736
647 double 737 double
648 Colour3DPlotLayer::getYForBin(View *v, double bin) const 738 Colour3DPlotLayer::getYForBin(const LayerGeometryProvider *v, double bin) const
649 { 739 {
650 double y = bin; 740 double y = bin;
651 if (!m_model) return y; 741 if (!m_model) return y;
652 double mn = 0, mx = m_model->getHeight(); 742 double mn = 0, mx = m_model->getHeight();
653 getDisplayExtents(mn, mx); 743 getDisplayExtents(mn, mx);
654 double h = v->height(); 744 double h = v->getPaintHeight();
655 if (m_binScale == LinearBinScale) { 745 if (m_binScale == BinScale::Linear) {
656 y = h - (((bin - mn) * h) / (mx - mn)); 746 y = h - (((bin - mn) * h) / (mx - mn));
657 } else { 747 } else {
658 double logmin = mn + 1, logmax = mx + 1; 748 double logmin = mn + 1, logmax = mx + 1;
659 LogRange::mapRange(logmin, logmax); 749 LogRange::mapRange(logmin, logmax);
660 y = h - (((LogRange::map(bin + 1) - logmin) * h) / (logmax - logmin)); 750 y = h - (((LogRange::map(bin + 1) - logmin) * h) / (logmax - logmin));
661 } 751 }
662 return y; 752 return y;
663 } 753 }
664 754
665 int
666 Colour3DPlotLayer::getIYForBin(View *v, int bin) const
667 {
668 return int(round(getYForBin(v, bin)));
669 }
670
671 double 755 double
672 Colour3DPlotLayer::getBinForY(View *v, double y) const 756 Colour3DPlotLayer::getBinForY(const LayerGeometryProvider *v, double y) const
673 { 757 {
674 double bin = y; 758 double bin = y;
675 if (!m_model) return bin; 759 if (!m_model) return bin;
676 double mn = 0, mx = m_model->getHeight(); 760 double mn = 0, mx = m_model->getHeight();
677 getDisplayExtents(mn, mx); 761 getDisplayExtents(mn, mx);
678 double h = v->height(); 762 double h = v->getPaintHeight();
679 if (m_binScale == LinearBinScale) { 763 if (m_binScale == BinScale::Linear) {
680 bin = mn + ((h - y) * (mx - mn)) / h; 764 bin = mn + ((h - y) * (mx - mn)) / h;
681 } else { 765 } else {
682 double logmin = mn + 1, logmax = mx + 1; 766 double logmin = mn + 1, logmax = mx + 1;
683 LogRange::mapRange(logmin, logmax); 767 LogRange::mapRange(logmin, logmax);
684 bin = LogRange::unmap(logmin + ((h - y) * (logmax - logmin)) / h) - 1; 768 bin = LogRange::unmap(logmin + ((h - y) * (logmax - logmin)) / h) - 1;
685 } 769 }
686 return bin; 770 return bin;
687 } 771 }
688 772
689 int
690 Colour3DPlotLayer::getIBinForY(View *v, int y) const
691 {
692 return int(floor(getBinForY(v, y)));
693 }
694
695 QString 773 QString
696 Colour3DPlotLayer::getFeatureDescription(View *v, QPoint &pos) const 774 Colour3DPlotLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
697 { 775 {
698 if (!m_model) return ""; 776 if (!m_model) return "";
699 777
700 int x = pos.x(); 778 int x = pos.x();
701 int y = pos.y(); 779 int y = pos.y();
722 symax = sh; 800 symax = sh;
723 } 801 }
724 if (symin < 0) symin = 0; 802 if (symin < 0) symin = 0;
725 if (symax > sh) symax = sh; 803 if (symax > sh) symax = sh;
726 804
727 // double binHeight = double(v->height()) / (symax - symin); 805 // double binHeight = double(v->getPaintHeight()) / (symax - symin);
728 // int sy = int((v->height() - y) / binHeight) + symin; 806 // int sy = int((v->getPaintHeight() - y) / binHeight) + symin;
729 807
730 int sy = getIBinForY(v, y); 808 int sy = getIBinForY(v, y);
731 809
732 if (sy < 0 || sy >= m_model->getHeight()) { 810 if (sy < 0 || sy >= m_model->getHeight()) {
733 return ""; 811 return "";
753 831
754 return text; 832 return text;
755 } 833 }
756 834
757 int 835 int
758 Colour3DPlotLayer::getColourScaleWidth(QPainter &) const 836 Colour3DPlotLayer::getColourScaleWidth(QPainter &p) const
759 { 837 {
760 int cw = 20; 838 // Font is rotated
839 int cw = p.fontMetrics().height();
761 return cw; 840 return cw;
762 } 841 }
763 842
764 int 843 int
765 Colour3DPlotLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const 844 Colour3DPlotLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const
766 { 845 {
767 if (!m_model) return 0; 846 if (!m_model) return 0;
768 847
769 QString sampleText = QString("[%1]").arg(m_model->getHeight()); 848 QString sampleText = QString("[%1]").arg(m_model->getHeight());
770 int tw = paint.fontMetrics().width(sampleText); 849 int tw = paint.fontMetrics().width(sampleText);
782 861
783 return tw + 13 + getColourScaleWidth(paint); 862 return tw + 13 + getColourScaleWidth(paint);
784 } 863 }
785 864
786 void 865 void
787 Colour3DPlotLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const 866 Colour3DPlotLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const
788 { 867 {
789 if (!m_model) return; 868 if (!m_model) return;
790 869
791 int h = rect.height(), w = rect.width(); 870 int h = rect.height(), w = rect.width();
792 871
793 int cw = getColourScaleWidth(paint); 872 int cw = getColourScaleWidth(paint);
794 873
795 int ch = h - 20; 874 int ch = h - 20;
796 if (ch > 20 && m_cache) { 875 if (ch > 20) {
797 876
798 double min = m_model->getMinimumLevel(); 877 double min = m_viewMags[v->getId()].getMin();
799 double max = m_model->getMaximumLevel(); 878 double max = m_viewMags[v->getId()].getMax();
800 879
801 double mmin = min; 880 if (max <= min) max = min + 0.1;
802 double mmax = max; 881
803
804 if (m_colourScale == LogScale) {
805 LogRange::mapRange(mmin, mmax);
806 } else if (m_colourScale == PlusMinusOneScale) {
807 mmin = -1.f;
808 mmax = 1.f;
809 } else if (m_colourScale == AbsoluteScale) {
810 if (mmin < 0) {
811 if (fabs(mmin) > fabs(mmax)) mmax = fabs(mmin);
812 else mmax = fabs(mmax);
813 mmin = 0;
814 } else {
815 mmin = fabs(mmin);
816 mmax = fabs(mmax);
817 }
818 }
819
820 if (max == min) max = min + 1.f;
821 if (mmax == mmin) mmax = mmin + 1.f;
822
823 paint.setPen(v->getForeground()); 882 paint.setPen(v->getForeground());
824 paint.drawRect(4, 10, cw - 8, ch+1); 883 paint.drawRect(4, 10, cw - 8, ch+1);
825 884
826 for (int y = 0; y < ch; ++y) { 885 for (int y = 0; y < ch; ++y) {
827 double value = ((max - min) * (double(ch-y) - 1.0)) / double(ch) + min; 886 double value = ((max - min) * (double(ch-y) - 1.0)) / double(ch) + min;
828 if (m_colourScale == LogScale) { 887 paint.setPen(getRenderer(v)->getColour(value));
829 value = LogRange::map(value); 888 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
830 }
831 int pixel = int(((value - mmin) * 256) / (mmax - mmin));
832 if (pixel >= 0 && pixel < 256) {
833 QRgb c = m_cache->color(pixel);
834 paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c)));
835 paint.drawLine(5, 11 + y, cw - 5, 11 + y);
836 } else {
837 cerr << "WARNING: Colour3DPlotLayer::paintVerticalScale: value " << value << ", mmin " << mmin << ", mmax " << mmax << " leads to invalid pixel " << pixel << endl;
838 }
839 } 889 }
840 890
841 QString minstr = QString("%1").arg(min); 891 QString minstr = QString("%1").arg(min);
842 QString maxstr = QString("%1").arg(max); 892 QString maxstr = QString("%1").arg(max);
843 893
844 paint.save(); 894 paint.save();
845 895
846 QFont font = paint.font(); 896 QFont font = paint.font();
847 font.setPixelSize(10); 897 if (font.pixelSize() > 0) {
848 paint.setFont(font); 898 int newSize = int(font.pixelSize() * 0.65);
899 if (newSize < 6) newSize = 6;
900 font.setPixelSize(newSize);
901 paint.setFont(font);
902 }
849 903
850 int msw = paint.fontMetrics().width(maxstr); 904 int msw = paint.fontMetrics().width(maxstr);
851 905
852 QMatrix m; 906 QMatrix m;
853 m.translate(cw - 6, ch + 10); 907 m.translate(cw - 6, ch + 10);
854 m.rotate(-90); 908 m.rotate(-90);
855 909
856 paint.setWorldMatrix(m); 910 paint.setWorldMatrix(m);
857 911
858 v->drawVisibleText(paint, 2, 0, minstr, View::OutlinedText); 912 PaintAssistant::drawVisibleText(v, paint, 2, 0, minstr, PaintAssistant::OutlinedText);
859 913
860 m.translate(ch - msw - 2, 0); 914 m.translate(ch - msw - 2, 0);
861 paint.setWorldMatrix(m); 915 paint.setWorldMatrix(m);
862 916
863 v->drawVisibleText(paint, 0, 0, maxstr, View::OutlinedText); 917 PaintAssistant::drawVisibleText(v, paint, 0, 0, maxstr, PaintAssistant::OutlinedText);
864 918
865 paint.restore(); 919 paint.restore();
866 } 920 }
867 921
868 paint.setPen(v->getForeground()); 922 paint.setPen(v->getForeground());
880 934
881 paint.save(); 935 paint.save();
882 936
883 int py = h; 937 int py = h;
884 938
939 int defaultFontHeight = paint.fontMetrics().height();
940
885 for (int i = symin; i <= symax; ++i) { 941 for (int i = symin; i <= symax; ++i) {
886 942
887 int y0; 943 int y0;
888 944
889 y0 = getIYForBin(v, i); 945 y0 = getIYForBin(v, i);
890 int h = py - y0; 946 int h = py - y0;
891 947
892 if (i > symin) { 948 if (i > symin) {
893 if (paint.fontMetrics().height() >= h) { 949 if (paint.fontMetrics().height() >= h) {
894 if (h >= 8) { 950 if (h >= defaultFontHeight * 0.8) {
895 QFont tf = paint.font(); 951 QFont tf = paint.font();
896 tf.setPixelSize(h-2); 952 tf.setPixelSize(int(h * 0.8));
897 paint.setFont(tf); 953 paint.setFont(tf);
898 } else { 954 } else {
899 continue; 955 continue;
900 } 956 }
901 } 957 }
929 Colour3DPlotLayer::getColumn(int col) const 985 Colour3DPlotLayer::getColumn(int col) const
930 { 986 {
931 Profiler profiler("Colour3DPlotLayer::getColumn"); 987 Profiler profiler("Colour3DPlotLayer::getColumn");
932 988
933 DenseThreeDimensionalModel::Column values = m_model->getColumn(col); 989 DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
934 while (values.size() < m_model->getHeight()) values.push_back(0.f); 990 values.resize(m_model->getHeight(), 0.f);
935 if (!m_normalizeColumns && !m_normalizeHybrid) return values; 991 if (m_normalization != ColumnNormalization::Max1 &&
992 m_normalization != ColumnNormalization::Hybrid) {
993 return values;
994 }
936 995
937 double colMax = 0.f, colMin = 0.f; 996 double colMax = 0.f, colMin = 0.f;
938 double min = 0.f, max = 0.f; 997 double min = 0.f, max = 0.f;
939 998
999 int nv = int(values.size());
1000
940 min = m_model->getMinimumLevel(); 1001 min = m_model->getMinimumLevel();
941 max = m_model->getMaximumLevel(); 1002 max = m_model->getMaximumLevel();
942 1003
943 for (int y = 0; y < values.size(); ++y) { 1004 for (int y = 0; y < nv; ++y) {
944 if (y == 0 || values.at(y) > colMax) colMax = values.at(y); 1005 if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
945 if (y == 0 || values.at(y) < colMin) colMin = values.at(y); 1006 if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
946 } 1007 }
947 if (colMin == colMax) colMax = colMin + 1; 1008 if (colMin == colMax) colMax = colMin + 1;
948 1009
949 for (int y = 0; y < values.size(); ++y) { 1010 for (int y = 0; y < nv; ++y) {
950 1011
951 double value = values.at(y); 1012 double value = values.at(y);
952 double norm = (value - colMin) / (colMax - colMin); 1013 double norm = (value - colMin) / (colMax - colMin);
953 double newvalue = min + (max - min) * norm; 1014 double newvalue = min + (max - min) * norm;
954 1015
955 if (value != newvalue) values[y] = float(newvalue); 1016 if (value != newvalue) values[y] = float(newvalue);
956 } 1017 }
957 1018
958 if (m_normalizeHybrid && (colMax > 0.0)) { 1019 if (m_normalization == ColumnNormalization::Hybrid
1020 && (colMax > 0.0)) {
959 double logmax = log10(colMax); 1021 double logmax = log10(colMax);
960 for (int y = 0; y < values.size(); ++y) { 1022 for (int y = 0; y < nv; ++y) {
961 values[y] = float(values[y] * logmax); 1023 values[y] = float(values[y] * logmax);
962 } 1024 }
963 } 1025 }
964 1026
965 return values; 1027 return values;
966 } 1028 }
967 1029
968 void 1030 Colour3DPlotRenderer *
969 Colour3DPlotLayer::fillCache(int firstColumn, int lastColumn) const 1031 Colour3DPlotLayer::getRenderer(const LayerGeometryProvider *v) const
970 { 1032 {
971 // This call requests a (perhaps partial) fill of the cache 1033 if (m_renderers.find(v->getId()) == m_renderers.end()) {
972 // between model columns firstColumn and lastColumn inclusive. 1034
973 // The cache itself always has size sufficient to contain the 1035 Colour3DPlotRenderer::Sources sources;
974 // whole model, but its validity may be less, depending on which 1036 sources.verticalBinLayer = this;
975 // regions have been requested via calls to this function. Note 1037 sources.fft = 0;
976 // that firstColumn and lastColumn are *model* column numbers. If 1038 sources.source = m_model;
977 // the model starts at a frame > 0, a firstColumn of zero still 1039 sources.peakCaches.push_back(getPeakCache());
978 // corresponds to the first column in the model, not the first 1040
979 // column on the resulting rendered layer. 1041 ColourScale::Parameters cparams;
980 1042 cparams.colourMap = m_colourMap;
981 Profiler profiler("Colour3DPlotLayer::fillCache", true); 1043 cparams.scaleType = m_colourScale;
982 1044 cparams.gain = m_gain;
983 int cacheWidth = m_model->getWidth(); 1045
984 int cacheHeight = m_model->getHeight(); 1046 if (m_normalization == ColumnNormalization::None) {
985 1047 cparams.minValue = m_model->getMinimumLevel();
986 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1048 cparams.maxValue = m_model->getMaximumLevel();
987 cerr << "Colour3DPlotLayer::fillCache: range " << firstColumn << " -> " << lastColumn << " (cache size will be " << cacheWidth << " x " << cacheHeight << ")" << endl; 1049 } else if (m_normalization == ColumnNormalization::Hybrid) {
988 #endif 1050 cparams.minValue = 0;
989 1051 cparams.maxValue = log10(m_model->getMaximumLevel() + 1.0);
990 if (m_cache && m_cache->height() != cacheHeight) { 1052 }
991 // height has changed: delete everything rather than resizing 1053
992 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1054 if (cparams.maxValue <= cparams.minValue) {
993 cerr << "Colour3DPlotLayer::fillCache: Cache height has changed, recreating" << endl; 1055 cparams.maxValue = cparams.minValue + 0.1;
994 #endif 1056 }
995 delete m_cache;
996 delete m_peaksCache;
997 m_cache = 0;
998 m_peaksCache = 0;
999 }
1000
1001 if (m_cache && m_cache->width() != cacheWidth) {
1002 // width has changed and we have an existing cache: resize it
1003 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1004 cerr << "Colour3DPlotLayer::fillCache: Cache width has changed, resizing existing cache" << endl;
1005 #endif
1006 QImage *newCache =
1007 new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight));
1008 delete m_cache;
1009 m_cache = newCache;
1010 if (m_peaksCache) {
1011 QImage *newPeaksCache =
1012 new QImage(m_peaksCache->copy
1013 (0, 0, cacheWidth / m_peakResolution + 1, cacheHeight));
1014 delete m_peaksCache;
1015 m_peaksCache = newPeaksCache;
1016 }
1017 }
1018
1019 if (!m_cache) {
1020 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1021 cerr << "Colour3DPlotLayer::fillCache: Have no cache, making one" << endl;
1022 #endif
1023 m_cache = new QImage(cacheWidth, cacheHeight, QImage::Format_Indexed8);
1024 m_cache->setColorCount(256);
1025 m_cache->fill(0);
1026 if (!m_normalizeVisibleArea) {
1027 m_peaksCache = new QImage
1028 (cacheWidth / m_peakResolution + 1, cacheHeight,
1029 QImage::Format_Indexed8);
1030 m_peaksCache->setColorCount(256);
1031 m_peaksCache->fill(0);
1032 } else if (m_peaksCache) {
1033 delete m_peaksCache;
1034 m_peaksCache = 0;
1035 }
1036 m_cacheValidStart = 0;
1037 m_cacheValidEnd = 0;
1038 }
1039
1040 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1041 cerr << "cache size = " << m_cache->width() << "x" << m_cache->height()
1042 << " peaks cache size = " << m_peaksCache->width() << "x" << m_peaksCache->height() << endl;
1043 #endif
1044
1045 if (m_cacheValidStart <= firstColumn && m_cacheValidEnd >= lastColumn) {
1046 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1047 cerr << "Cache is valid in this region already" << endl;
1048 #endif
1049 return;
1050 }
1051
1052 int fillStart = firstColumn;
1053 int fillEnd = lastColumn;
1054
1055 if (fillStart >= cacheWidth) fillStart = cacheWidth-1;
1056 if (fillStart < 0) fillStart = 0;
1057 if (fillEnd >= cacheWidth) fillEnd = cacheWidth-1;
1058 if (fillEnd < 0) fillEnd = 0;
1059 if (fillEnd < fillStart) fillEnd = fillStart;
1060
1061 bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns);
1062
1063 if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) {
1064 1057
1065 if (m_cacheValidEnd < fillStart) { 1058 Colour3DPlotRenderer::Parameters params;
1066 fillStart = m_cacheValidEnd + 1; 1059 params.colourScale = ColourScale(cparams);
1067 } 1060 params.normalization = m_normalization;
1068 if (m_cacheValidStart > fillEnd) { 1061 params.binScale = m_binScale;
1069 fillEnd = m_cacheValidStart - 1; 1062 params.alwaysOpaque = m_opaque;
1070 } 1063 params.invertVertical = m_invertVertical;
1064 params.interpolate = m_smooth;
1065
1066 m_renderers[v->getId()] = new Colour3DPlotRenderer(sources, params);
1067 }
1068
1069 return m_renderers[v->getId()];
1070 }
1071
1072 void
1073 Colour3DPlotLayer::paintWithRenderer(LayerGeometryProvider *v,
1074 QPainter &paint, QRect rect) const
1075 {
1076 Colour3DPlotRenderer *renderer = getRenderer(v);
1077
1078 Colour3DPlotRenderer::RenderResult result;
1079 MagnitudeRange magRange;
1080 int viewId = v->getId();
1081
1082 if (!renderer->geometryChanged(v)) {
1083 magRange = m_viewMags[viewId];
1084 }
1085
1086 if (m_synchronous) {
1087
1088 result = renderer->render(v, paint, rect);
1089
1090 } else {
1091
1092 result = renderer->renderTimeConstrained(v, paint, rect);
1093
1094 QRect uncached = renderer->getLargestUncachedRect(v);
1095 if (uncached.width() > 0) {
1096 v->updatePaintRect(uncached);
1097 }
1098 }
1099
1100 magRange.sample(result.range);
1101
1102 if (magRange.isSet()) {
1103 if (!(m_viewMags[viewId] == magRange)) {
1104 m_viewMags[viewId] = magRange;
1105 //!!! now need to do the normalise-visible thing
1106 }
1107 }
1108
1109 cerr << "mag range in this view: "
1110 << m_viewMags[v->getId()].getMin()
1111 << " -> "
1112 << m_viewMags[v->getId()].getMax()
1113 << endl;
1071 1114
1072 m_cacheValidStart = std::min(fillStart, m_cacheValidStart); 1115 }
1073 m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd); 1116
1074 1117 void
1075 } else { 1118 Colour3DPlotLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
1076
1077 // when normalising the visible area, the only valid area,
1078 // ever, is the currently visible one
1079
1080 m_cacheValidStart = fillStart;
1081 m_cacheValidEnd = fillEnd;
1082 }
1083
1084 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1085 cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << " (fillStart = " << fillStart << ", fillEnd = " << fillEnd << ")" << endl;
1086 #endif
1087
1088 DenseThreeDimensionalModel::Column values;
1089
1090 double min = m_model->getMinimumLevel();
1091 double max = m_model->getMaximumLevel();
1092
1093 if (m_colourScale == LogScale) {
1094 LogRange::mapRange(min, max);
1095 } else if (m_colourScale == PlusMinusOneScale) {
1096 min = -1.f;
1097 max = 1.f;
1098 } else if (m_colourScale == AbsoluteScale) {
1099 if (min < 0) {
1100 if (fabs(min) > fabs(max)) max = fabs(min);
1101 else max = fabs(max);
1102 min = 0;
1103 } else {
1104 min = fabs(min);
1105 max = fabs(max);
1106 }
1107 }
1108
1109 if (max == min) max = min + 1.f;
1110
1111 ColourMapper mapper(m_colourMap, 0.f, 255.f);
1112
1113 for (int index = 0; index < 256; ++index) {
1114 QColor colour = mapper.map(index);
1115 m_cache->setColor
1116 (index, qRgb(colour.red(), colour.green(), colour.blue()));
1117 if (m_peaksCache) {
1118 m_peaksCache->setColor
1119 (index, qRgb(colour.red(), colour.green(), colour.blue()));
1120 }
1121 }
1122
1123 double visibleMax = 0.f, visibleMin = 0.f;
1124
1125 if (normalizeVisible) {
1126
1127 for (int c = fillStart; c <= fillEnd; ++c) {
1128
1129 values = getColumn(c);
1130
1131 double colMax = 0.f, colMin = 0.f;
1132
1133 for (int y = 0; y < cacheHeight; ++y) {
1134 if (y >= values.size()) break;
1135 if (y == 0 || values[y] > colMax) colMax = values[y];
1136 if (y == 0 || values[y] < colMin) colMin = values[y];
1137 }
1138
1139 if (c == fillStart || colMax > visibleMax) visibleMax = colMax;
1140 if (c == fillStart || colMin < visibleMin) visibleMin = colMin;
1141 }
1142
1143 if (m_colourScale == LogScale) {
1144 visibleMin = LogRange::map(visibleMin);
1145 visibleMax = LogRange::map(visibleMax);
1146 if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax);
1147 } else if (m_colourScale == AbsoluteScale) {
1148 if (visibleMin < 0) {
1149 if (fabs(visibleMin) > fabs(visibleMax)) visibleMax = fabs(visibleMin);
1150 else visibleMax = fabs(visibleMax);
1151 visibleMin = 0;
1152 } else {
1153 visibleMin = fabs(visibleMin);
1154 visibleMax = fabs(visibleMax);
1155 }
1156 }
1157 }
1158
1159 if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
1160
1161 int *peaks = 0;
1162 if (m_peaksCache) {
1163 peaks = new int[cacheHeight];
1164 for (int y = 0; y < cacheHeight; ++y) {
1165 peaks[y] = 0;
1166 }
1167 }
1168
1169 Profiler profiler2("Colour3DPlotLayer::fillCache: filling", true);
1170
1171 for (int c = fillStart; c <= fillEnd; ++c) {
1172
1173 values = getColumn(c);
1174
1175 if (c >= m_cache->width()) {
1176 cerr << "ERROR: column " << c << " >= cache width "
1177 << m_cache->width() << endl;
1178 continue;
1179 }
1180
1181 for (int y = 0; y < cacheHeight; ++y) {
1182
1183 double value = min;
1184 if (y < values.size()) {
1185 value = values.at(y);
1186 }
1187
1188 value = value * m_gain;
1189
1190 if (m_colourScale == LogScale) {
1191 value = LogRange::map(value);
1192 } else if (m_colourScale == AbsoluteScale) {
1193 value = fabs(value);
1194 }
1195
1196 if (normalizeVisible) {
1197 double norm = (value - visibleMin) / (visibleMax - visibleMin);
1198 value = min + (max - min) * norm;
1199 }
1200
1201 int pixel = int(((value - min) * 256) / (max - min));
1202 if (pixel < 0) pixel = 0;
1203 if (pixel > 255) pixel = 255;
1204 if (peaks && (pixel > peaks[y])) peaks[y] = pixel;
1205
1206 if (m_invertVertical) {
1207 m_cache->setPixel(c, cacheHeight - y - 1, pixel);
1208 } else {
1209 if (y >= m_cache->height()) {
1210 cerr << "ERROR: row " << y << " >= cache height " << m_cache->height() << endl;
1211 } else {
1212 m_cache->setPixel(c, y, pixel);
1213 }
1214 }
1215 }
1216
1217 if (peaks) {
1218 int notch = (c % m_peakResolution);
1219 if (notch == m_peakResolution-1 || c == fillEnd) {
1220 int pc = c / m_peakResolution;
1221 if (pc >= m_peaksCache->width()) {
1222 cerr << "ERROR: peak column " << pc
1223 << " (from col " << c << ") >= peaks cache width "
1224 << m_peaksCache->width() << endl;
1225 continue;
1226 }
1227 for (int y = 0; y < cacheHeight; ++y) {
1228 if (m_invertVertical) {
1229 m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]);
1230 } else {
1231 if (y >= m_peaksCache->height()) {
1232 cerr << "ERROR: row " << y
1233 << " >= peaks cache height "
1234 << m_peaksCache->height() << endl;
1235 } else {
1236 m_peaksCache->setPixel(pc, y, peaks[y]);
1237 }
1238 }
1239 }
1240 for (int y = 0; y < cacheHeight; ++y) {
1241 peaks[y] = 0;
1242 }
1243 }
1244 }
1245 }
1246
1247 delete[] peaks;
1248 }
1249
1250 bool
1251 Colour3DPlotLayer::shouldPaintDenseIn(const View *v) const
1252 {
1253 if (!m_model || !v || !(v->getViewManager())) {
1254 return false;
1255 }
1256 double srRatio =
1257 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
1258 if (m_opaque ||
1259 m_smooth ||
1260 m_model->getHeight() >= v->height() ||
1261 ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) {
1262 return true;
1263 }
1264 return false;
1265 }
1266
1267 void
1268 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const
1269 { 1119 {
1270 /* 1120 /*
1271 if (m_model) { 1121 if (m_model) {
1272 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl; 1122 SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
1273 } 1123 }
1278 #endif 1128 #endif
1279 1129
1280 int completion = 0; 1130 int completion = 0;
1281 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) { 1131 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
1282 if (completion > 0) { 1132 if (completion > 0) {
1283 paint.fillRect(0, 10, v->width() * completion / 100, 1133 paint.fillRect(0, 10, v->getPaintWidth() * completion / 100,
1284 10, QColor(120, 120, 120)); 1134 10, QColor(120, 120, 120));
1285 } 1135 }
1286 return; 1136 return;
1287 } 1137 }
1288 1138
1289 if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect(); 1139 if (m_model->getWidth() == 0) {
1290
1291 sv_frame_t modelStart = m_model->getStartFrame();
1292 sv_frame_t modelEnd = m_model->getEndFrame();
1293 int modelResolution = m_model->getResolution();
1294
1295 // The cache is from the model's start frame to the model's end
1296 // frame at the model's window increment frames per pixel. We
1297 // want to draw from our start frame + x0 * zoomLevel to our start
1298 // frame + x1 * zoomLevel at zoomLevel frames per pixel.
1299
1300 // We have quite different paint mechanisms for rendering "large"
1301 // bins (more than one bin per pixel in both directions) and
1302 // "small". This is "large"; see paintDense below for "small".
1303
1304 int x0 = rect.left();
1305 int x1 = rect.right() + 1;
1306
1307 int h = v->height();
1308
1309 double srRatio =
1310 v->getViewManager()->getMainModelSampleRate() / m_model->getSampleRate();
1311
1312 // the s-prefix values are source, i.e. model, column and bin numbers
1313 int sx0 = int((double(v->getFrameForX(x0)) / srRatio - double(modelStart))
1314 / modelResolution);
1315 int sx1 = int((double(v->getFrameForX(x1)) / srRatio - double(modelStart))
1316 / modelResolution);
1317 int sh = m_model->getHeight();
1318
1319 int symin = m_miny;
1320 int symax = m_maxy;
1321 if (symax <= symin) {
1322 symin = 0;
1323 symax = sh;
1324 }
1325 if (symin < 0) symin = 0;
1326 if (symax > sh) symax = sh;
1327
1328 if (sx0 > 0) --sx0;
1329 fillCache(sx0 < 0 ? 0 : sx0,
1330 sx1 < 0 ? 0 : sx1);
1331
1332 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1140 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1333 cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << endl; 1141 cerr << "Colour3DPlotLayer::paint(): model width == 0, "
1142 << "nothing to paint (yet)" << endl;
1334 #endif 1143 #endif
1335
1336 if (shouldPaintDenseIn(v)) {
1337 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1338 cerr << "calling paintDense" << endl;
1339 #endif
1340 paintDense(v, paint, rect);
1341 return; 1144 return;
1342 } 1145 }
1343 1146
1344 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1147 //!!!???
1345 cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << endl; 1148
1346 cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << endl; 1149 if (m_normalizeVisibleArea) {
1347 #endif 1150 rect = v->getPaintRect();
1348 1151 }
1349 QPoint illuminatePos; 1152
1350 bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos); 1153 //!!! why is the setLayerDormant(false) found here in
1351 1154 //!!! SpectrogramLayer not present in Colour3DPlotLayer?
1352 const int buflen = 40; 1155 //!!! unnecessary? vestigial? forgotten?
1353 char labelbuf[buflen]; 1156
1354 1157 paintWithRenderer(v, paint, rect);
1355 for (int sx = sx0; sx <= sx1; ++sx) {
1356
1357 sv_frame_t fx = sx * modelResolution + modelStart;
1358
1359 if (fx + modelResolution <= modelStart || fx > modelEnd) continue;
1360
1361 int rx0 = v->getXForFrame(int(double(fx) * srRatio));
1362 int rx1 = v->getXForFrame(int(double(fx + modelResolution + 1) * srRatio));
1363
1364 int rw = rx1 - rx0;
1365 if (rw < 1) rw = 1;
1366
1367 bool showLabel = (rw > 10 &&
1368 paint.fontMetrics().width("0.000000") < rw - 3 &&
1369 paint.fontMetrics().height() < (h / sh));
1370
1371 for (int sy = symin; sy < symax; ++sy) {
1372
1373 int ry0 = getIYForBin(v, sy);
1374 int ry1 = getIYForBin(v, sy + 1);
1375 QRect r(rx0, ry1, rw, ry0 - ry1);
1376
1377 QRgb pixel = qRgb(255, 255, 255);
1378 if (sx >= 0 && sx < m_cache->width() &&
1379 sy >= 0 && sy < m_cache->height()) {
1380 pixel = m_cache->pixel(sx, sy);
1381 }
1382
1383 if (rw == 1) {
1384 paint.setPen(pixel);
1385 paint.setBrush(Qt::NoBrush);
1386 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
1387 continue;
1388 }
1389
1390 QColor pen(255, 255, 255, 80);
1391 QColor brush(pixel);
1392
1393 if (rw > 3 && r.height() > 3) {
1394 brush.setAlpha(160);
1395 }
1396
1397 paint.setPen(Qt::NoPen);
1398 paint.setBrush(brush);
1399
1400 if (illuminate) {
1401 if (r.contains(illuminatePos)) {
1402 paint.setPen(v->getForeground());
1403 }
1404 }
1405
1406 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1407 // cerr << "rect " << r.x() << "," << r.y() << " "
1408 // << r.width() << "x" << r.height() << endl;
1409 #endif
1410
1411 paint.drawRect(r);
1412
1413 if (showLabel) {
1414 if (sx >= 0 && sx < m_cache->width() &&
1415 sy >= 0 && sy < m_cache->height()) {
1416 double value = m_model->getValueAt(sx, sy);
1417 snprintf(labelbuf, buflen, "%06f", value);
1418 QString text(labelbuf);
1419 v->drawVisibleText
1420 (paint,
1421 rx0 + 2,
1422 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
1423 text,
1424 View::OutlinedText);
1425 }
1426 }
1427 }
1428 }
1429 }
1430
1431 void
1432 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const
1433 {
1434 Profiler profiler("Colour3DPlotLayer::paintDense", true);
1435 if (!m_cache) return;
1436
1437 double modelStart = double(m_model->getStartFrame());
1438 double modelResolution = double(m_model->getResolution());
1439
1440 sv_samplerate_t mmsr = v->getViewManager()->getMainModelSampleRate();
1441 sv_samplerate_t msr = m_model->getSampleRate();
1442 double srRatio = mmsr / msr;
1443
1444 int x0 = rect.left();
1445 int x1 = rect.right() + 1;
1446
1447 const int w = x1 - x0; // const so it can be used as array size below
1448 int h = v->height(); // we always paint full height
1449 int sh = m_model->getHeight();
1450
1451 int symin = m_miny;
1452 int symax = m_maxy;
1453 if (symax <= symin) {
1454 symin = 0;
1455 symax = sh;
1456 }
1457 if (symin < 0) symin = 0;
1458 if (symax > sh) symax = sh;
1459
1460 QImage img(w, h, QImage::Format_Indexed8);
1461 img.setColorTable(m_cache->colorTable());
1462
1463 uchar *peaks = new uchar[w];
1464 memset(peaks, 0, w);
1465
1466 int zoomLevel = v->getZoomLevel();
1467
1468 QImage *source = m_cache;
1469
1470 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1471 cerr << "modelResolution " << modelResolution << ", srRatio "
1472 << srRatio << ", m_peakResolution " << m_peakResolution
1473 << ", zoomLevel " << zoomLevel << ", result "
1474 << ((modelResolution * srRatio * m_peakResolution) / zoomLevel)
1475 << endl;
1476 #endif
1477
1478 if (m_peaksCache) {
1479 if (((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
1480 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1481 cerr << "using peaks cache" << endl;
1482 #endif
1483 source = m_peaksCache;
1484 modelResolution *= m_peakResolution;
1485 } else {
1486 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1487 cerr << "not using peaks cache" << endl;
1488 #endif
1489 }
1490 } else {
1491 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1492 cerr << "have no peaks cache" << endl;
1493 #endif
1494 }
1495
1496 int sw = source->width();
1497
1498 sv_frame_t xf = -1;
1499 sv_frame_t nxf = v->getFrameForX(x0);
1500
1501 double epsilon = 0.000001;
1502
1503 vector<double> sxa(w*2);
1504
1505 for (int x = 0; x < w; ++x) {
1506
1507 xf = nxf;
1508 nxf = xf + zoomLevel;
1509
1510 double sx0 = (double(xf) / srRatio - modelStart) / modelResolution;
1511 double sx1 = (double(nxf) / srRatio - modelStart) / modelResolution;
1512
1513 sxa[x*2] = sx0;
1514 sxa[x*2 + 1] = sx1;
1515 }
1516
1517 double logmin = symin+1, logmax = symax+1;
1518 LogRange::mapRange(logmin, logmax);
1519
1520 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1521 cerr << "m_smooth = " << m_smooth << ", w = " << w << ", h = " << h << endl;
1522 #endif
1523
1524 if (m_smooth) {
1525
1526 for (int y = 0; y < h; ++y) {
1527
1528 double sy = getBinForY(v, y) - 0.5;
1529 int syi = int(sy + epsilon);
1530 if (syi < 0 || syi >= source->height()) continue;
1531
1532 uchar *targetLine = img.scanLine(y);
1533 uchar *sourceLine = source->scanLine(syi);
1534 uchar *nextSource;
1535 if (syi + 1 < source->height()) {
1536 nextSource = source->scanLine(syi + 1);
1537 } else {
1538 nextSource = sourceLine;
1539 }
1540
1541 for (int x = 0; x < w; ++x) {
1542
1543 targetLine[x] = 0;
1544
1545 double sx0 = sxa[x*2];
1546 if (sx0 < 0) continue;
1547 int sx0i = int(sx0 + epsilon);
1548 if (sx0i >= sw) break;
1549
1550 double a = sourceLine[sx0i];
1551 double b = a;
1552 double value;
1553
1554 double sx1 = sxa[x*2+1];
1555 if (sx1 > sx0 + 1.f) {
1556 int sx1i = int(sx1);
1557 bool have = false;
1558 for (int sx = sx0i; sx <= sx1i; ++sx) {
1559 if (sx < 0 || sx >= sw) continue;
1560 if (!have) {
1561 a = sourceLine[sx];
1562 b = nextSource[sx];
1563 have = true;
1564 } else {
1565 a = std::max(a, double(sourceLine[sx]));
1566 b = std::max(b, double(nextSource[sx]));
1567 }
1568 }
1569 double yprop = sy - syi;
1570 value = (a * (1.f - yprop) + b * yprop);
1571 } else {
1572 a = sourceLine[sx0i];
1573 b = nextSource[sx0i];
1574 double yprop = sy - syi;
1575 value = (a * (1.f - yprop) + b * yprop);
1576 int oi = sx0i + 1;
1577 double xprop = sx0 - sx0i;
1578 xprop -= 0.5;
1579 if (xprop < 0) {
1580 oi = sx0i - 1;
1581 xprop = -xprop;
1582 }
1583 if (oi < 0 || oi >= sw) oi = sx0i;
1584 a = sourceLine[oi];
1585 b = nextSource[oi];
1586 value = (value * (1.f - xprop) +
1587 (a * (1.f - yprop) + b * yprop) * xprop);
1588 }
1589
1590 int vi = int(lrint(value));
1591 if (vi > 255) vi = 255;
1592 if (vi < 0) vi = 0;
1593 targetLine[x] = uchar(vi);
1594 }
1595 }
1596 } else {
1597
1598 double sy0 = getBinForY(v, 0);
1599
1600 int psy0i = -1, psy1i = -1;
1601
1602 for (int y = 0; y < h; ++y) {
1603
1604 double sy1 = sy0;
1605 sy0 = getBinForY(v, double(y + 1));
1606
1607 int sy0i = int(sy0 + epsilon);
1608 int sy1i = int(sy1);
1609
1610 uchar *targetLine = img.scanLine(y);
1611
1612 if (sy0i == psy0i && sy1i == psy1i) {
1613 // same source scan line as just computed
1614 goto copy;
1615 }
1616
1617 psy0i = sy0i;
1618 psy1i = sy1i;
1619
1620 for (int x = 0; x < w; ++x) {
1621 peaks[x] = 0;
1622 }
1623
1624 for (int sy = sy0i; sy <= sy1i; ++sy) {
1625
1626 if (sy < 0 || sy >= source->height()) continue;
1627
1628 uchar *sourceLine = source->scanLine(sy);
1629
1630 for (int x = 0; x < w; ++x) {
1631
1632 double sx1 = sxa[x*2 + 1];
1633 if (sx1 < 0) continue;
1634 int sx1i = int(sx1);
1635
1636 double sx0 = sxa[x*2];
1637 if (sx0 < 0) continue;
1638 int sx0i = int(sx0 + epsilon);
1639 if (sx0i >= sw) break;
1640
1641 uchar peak = 0;
1642 for (int sx = sx0i; sx <= sx1i; ++sx) {
1643 if (sx < 0 || sx >= sw) continue;
1644 if (sourceLine[sx] > peak) peak = sourceLine[sx];
1645 }
1646 peaks[x] = peak;
1647 }
1648 }
1649
1650 copy:
1651 for (int x = 0; x < w; ++x) {
1652 targetLine[x] = peaks[x];
1653 }
1654 }
1655 }
1656
1657 delete[] peaks;
1658
1659 paint.drawImage(x0, 0, img);
1660 } 1158 }
1661 1159
1662 bool 1160 bool
1663 Colour3DPlotLayer::snapToFeatureFrame(View *v, sv_frame_t &frame, 1161 Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
1664 int &resolution, 1162 int &resolution,
1665 SnapType snap) const 1163 SnapType snap) const
1666 { 1164 {
1667 if (!m_model) { 1165 if (!m_model) {
1668 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 1166 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
1689 Colour3DPlotLayer::toXml(QTextStream &stream, 1187 Colour3DPlotLayer::toXml(QTextStream &stream,
1690 QString indent, QString extraAttributes) const 1188 QString indent, QString extraAttributes) const
1691 { 1189 {
1692 QString s = QString("scale=\"%1\" " 1190 QString s = QString("scale=\"%1\" "
1693 "colourScheme=\"%2\" " 1191 "colourScheme=\"%2\" "
1694 "normalizeColumns=\"%3\" " 1192 "minY=\"%3\" "
1695 "normalizeVisibleArea=\"%4\" " 1193 "maxY=\"%4\" "
1696 "minY=\"%5\" " 1194 "invertVertical=\"%5\" "
1697 "maxY=\"%6\" " 1195 "opaque=\"%6\" %7")
1698 "invertVertical=\"%7\" " 1196 .arg(convertFromColourScale(m_colourScale))
1699 "opaque=\"%8\" %9")
1700 .arg((int)m_colourScale)
1701 .arg(m_colourMap) 1197 .arg(m_colourMap)
1702 .arg(m_normalizeColumns ? "true" : "false")
1703 .arg(m_normalizeVisibleArea ? "true" : "false")
1704 .arg(m_miny) 1198 .arg(m_miny)
1705 .arg(m_maxy) 1199 .arg(m_maxy)
1706 .arg(m_invertVertical ? "true" : "false") 1200 .arg(m_invertVertical ? "true" : "false")
1707 .arg(m_opaque ? "true" : "false") 1201 .arg(m_opaque ? "true" : "false")
1708 .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ") 1202 .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
1709 .arg((int)m_binScale) 1203 .arg(int(m_binScale))
1710 .arg(m_smooth ? "true" : "false") 1204 .arg(m_smooth ? "true" : "false")
1711 .arg(m_gain)); 1205 .arg(m_gain));
1712 1206
1207 // New-style normalization attributes, allowing for more types of
1208 // normalization in future: write out the column normalization
1209 // type separately, and then whether we are normalizing visible
1210 // area as well afterwards
1211
1212 s += QString("columnNormalization=\"%1\" ")
1213 .arg(m_normalization == ColumnNormalization::Max1 ? "peak" :
1214 m_normalization == ColumnNormalization::Hybrid ? "hybrid" : "none");
1215
1216 // Old-style normalization attribute, for backward compatibility
1217
1218 s += QString("normalizeColumns=\"%1\" ")
1219 .arg(m_normalization == ColumnNormalization::Max1 ? "true" : "false");
1220
1221 // And this applies to both old- and new-style attributes
1222
1223 s += QString("normalizeVisibleArea=\"%1\" ")
1224 .arg(m_normalizeVisibleArea ? "true" : "false");
1225
1713 Layer::toXml(stream, indent, extraAttributes + " " + s); 1226 Layer::toXml(stream, indent, extraAttributes + " " + s);
1714 } 1227 }
1715 1228
1716 void 1229 void
1717 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes) 1230 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
1718 { 1231 {
1719 bool ok = false, alsoOk = false; 1232 bool ok = false, alsoOk = false;
1720 1233
1721 ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok); 1234 ColourScaleType colourScale = convertToColourScale
1722 if (ok) setColourScale(scale); 1235 (attributes.value("colourScale").toInt(&ok));
1236 if (ok) setColourScale(colourScale);
1723 1237
1724 int colourMap = attributes.value("colourScheme").toInt(&ok); 1238 int colourMap = attributes.value("colourScheme").toInt(&ok);
1725 if (ok) setColourMap(colourMap); 1239 if (ok) setColourMap(colourMap);
1726 1240
1727 BinScale binscale = (BinScale)attributes.value("binScale").toInt(&ok); 1241 BinScale binScale = (BinScale)
1728 if (ok) setBinScale(binscale); 1242 attributes.value("binScale").toInt(&ok);
1729 1243 if (ok) setBinScale(binScale);
1730 bool normalizeColumns = 1244
1731 (attributes.value("normalizeColumns").trimmed() == "true"); 1245 bool invertVertical =
1732 setNormalizeColumns(normalizeColumns); 1246 (attributes.value("invertVertical").trimmed() == "true");
1733 1247 setInvertVertical(invertVertical);
1248
1249 bool opaque =
1250 (attributes.value("opaque").trimmed() == "true");
1251 setOpaque(opaque);
1252
1253 bool smooth =
1254 (attributes.value("smooth").trimmed() == "true");
1255 setSmooth(smooth);
1256
1257 float gain = attributes.value("gain").toFloat(&ok);
1258 if (ok) setGain(gain);
1259
1260 float min = attributes.value("minY").toFloat(&ok);
1261 float max = attributes.value("maxY").toFloat(&alsoOk);
1262 if (ok && alsoOk) setDisplayExtents(min, max);
1263
1264 bool haveNewStyleNormalization = false;
1265
1266 QString columnNormalization = attributes.value("columnNormalization");
1267
1268 if (columnNormalization != "") {
1269
1270 haveNewStyleNormalization = true;
1271
1272 if (columnNormalization == "peak") {
1273 setNormalization(ColumnNormalization::Max1);
1274 } else if (columnNormalization == "hybrid") {
1275 setNormalization(ColumnNormalization::Hybrid);
1276 } else if (columnNormalization == "none") {
1277 setNormalization(ColumnNormalization::None);
1278 } else {
1279 cerr << "NOTE: Unknown or unsupported columnNormalization attribute \""
1280 << columnNormalization << "\"" << endl;
1281 }
1282 }
1283
1284 if (!haveNewStyleNormalization) {
1285
1286 setNormalization(ColumnNormalization::None);
1287
1288 bool normalizeColumns =
1289 (attributes.value("normalizeColumns").trimmed() == "true");
1290 if (normalizeColumns) {
1291 setNormalization(ColumnNormalization::Max1);
1292 }
1293
1294 bool normalizeHybrid =
1295 (attributes.value("normalizeHybrid").trimmed() == "true");
1296 if (normalizeHybrid) {
1297 setNormalization(ColumnNormalization::Hybrid);
1298 }
1299 }
1300
1734 bool normalizeVisibleArea = 1301 bool normalizeVisibleArea =
1735 (attributes.value("normalizeVisibleArea").trimmed() == "true"); 1302 (attributes.value("normalizeVisibleArea").trimmed() == "true");
1736 setNormalizeVisibleArea(normalizeVisibleArea); 1303 setNormalizeVisibleArea(normalizeVisibleArea);
1737 1304
1738 bool invertVertical = 1305 //!!! todo: check save/reload scaling, compare with
1739 (attributes.value("invertVertical").trimmed() == "true"); 1306 //!!! SpectrogramLayer, compare with prior SV versions, compare
1740 setInvertVertical(invertVertical); 1307 //!!! with Tony v1 and v2 and their save files
1741 1308 }
1742 bool opaque = 1309
1743 (attributes.value("opaque").trimmed() == "true");
1744 setOpaque(opaque);
1745
1746 bool smooth =
1747 (attributes.value("smooth").trimmed() == "true");
1748 setSmooth(smooth);
1749
1750 float gain = attributes.value("gain").toFloat(&ok);
1751 if (ok) setGain(gain);
1752
1753 float min = attributes.value("minY").toFloat(&ok);
1754 float max = attributes.value("maxY").toFloat(&alsoOk);
1755 if (ok && alsoOk) setDisplayExtents(min, max);
1756 }
1757