Mercurial > hg > svgui
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 |