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