Mercurial > hg > svgui
comparison layer/ColourMapper.cpp @ 1374:631897ba9fca zoom
Merge from default branch
author | Chris Cannam |
---|---|
date | Tue, 06 Nov 2018 08:59:03 +0000 |
parents | d79e21855aef |
children | c8a6fd3f9dff |
comparison
equal
deleted
inserted
replaced
1360:e848ea0850fe | 1374:631897ba9fca |
---|---|
25 | 25 |
26 #include <QPainter> | 26 #include <QPainter> |
27 | 27 |
28 using namespace std; | 28 using namespace std; |
29 | 29 |
30 static vector<QColor> convertStrings(const vector<QString> &strs) | 30 static vector<QColor> convertStrings(const vector<QString> &strs, |
31 bool reversed) | |
31 { | 32 { |
32 vector<QColor> converted; | 33 vector<QColor> converted; |
33 for (const auto &s: strs) converted.push_back(QColor(s)); | 34 for (const auto &s: strs) converted.push_back(QColor(s)); |
34 reverse(converted.begin(), converted.end()); | 35 if (reversed) { |
36 reverse(converted.begin(), converted.end()); | |
37 } | |
35 return converted; | 38 return converted; |
36 } | 39 } |
37 | 40 |
38 static vector<QColor> ice = convertStrings({ | 41 static vector<QColor> ice = convertStrings({ |
39 // Based on ColorBrewer ylGnBu | 42 // Based on ColorBrewer ylGnBu |
40 "#ffffff", "#ffff00", "#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", | 43 "#ffffff", "#ffff00", "#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", |
41 "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081", "#042040" | 44 "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081", "#042040" |
42 }); | 45 }, |
46 true); | |
43 | 47 |
44 static vector<QColor> cherry = convertStrings({ | 48 static vector<QColor> cherry = convertStrings({ |
45 "#f7f7f7", "#fddbc7", "#f4a582", "#d6604d", "#b2182b", "#dd3497", | 49 "#f7f7f7", "#fddbc7", "#f4a582", "#d6604d", "#b2182b", "#dd3497", |
46 "#ae017e", "#7a0177", "#49006a" | 50 "#ae017e", "#7a0177", "#49006a" |
47 }); | 51 }, |
48 | 52 true); |
53 | |
54 static vector<QColor> magma = convertStrings({ | |
55 "#FCFFB2", "#FCDF96", "#FBC17D", "#FBA368", "#FA8657", "#F66B4D", | |
56 "#ED504A", "#E03B50", "#C92D59", "#B02363", "#981D69", "#81176D", | |
57 "#6B116F", "#57096E", "#43006A", "#300060", "#1E0848", "#110B2D", | |
58 "#080616", "#000005" | |
59 }, | |
60 true); | |
61 | |
62 static vector<QColor> cividis = convertStrings({ | |
63 "#00204c", "#00204e", "#002150", "#002251", "#002353", "#002355", | |
64 "#002456", "#002558", "#00265a", "#00265b", "#00275d", "#00285f", | |
65 "#002861", "#002963", "#002a64", "#002a66", "#002b68", "#002c6a", | |
66 "#002d6c", "#002d6d", "#002e6e", "#002e6f", "#002f6f", "#002f6f", | |
67 "#00306f", "#00316f", "#00316f", "#00326e", "#00336e", "#00346e", | |
68 "#00346e", "#01356e", "#06366e", "#0a376d", "#0e376d", "#12386d", | |
69 "#15396d", "#17396d", "#1a3a6c", "#1c3b6c", "#1e3c6c", "#203c6c", | |
70 "#223d6c", "#243e6c", "#263e6c", "#273f6c", "#29406b", "#2b416b", | |
71 "#2c416b", "#2e426b", "#2f436b", "#31446b", "#32446b", "#33456b", | |
72 "#35466b", "#36466b", "#37476b", "#38486b", "#3a496b", "#3b496b", | |
73 "#3c4a6b", "#3d4b6b", "#3e4b6b", "#404c6b", "#414d6b", "#424e6b", | |
74 "#434e6b", "#444f6b", "#45506b", "#46506b", "#47516b", "#48526b", | |
75 "#49536b", "#4a536b", "#4b546b", "#4c556b", "#4d556b", "#4e566b", | |
76 "#4f576c", "#50586c", "#51586c", "#52596c", "#535a6c", "#545a6c", | |
77 "#555b6c", "#565c6c", "#575d6d", "#585d6d", "#595e6d", "#5a5f6d", | |
78 "#5b5f6d", "#5c606d", "#5d616e", "#5e626e", "#5f626e", "#5f636e", | |
79 "#60646e", "#61656f", "#62656f", "#63666f", "#64676f", "#65676f", | |
80 "#666870", "#676970", "#686a70", "#686a70", "#696b71", "#6a6c71", | |
81 "#6b6d71", "#6c6d72", "#6d6e72", "#6e6f72", "#6f6f72", "#6f7073", | |
82 "#707173", "#717273", "#727274", "#737374", "#747475", "#757575", | |
83 "#757575", "#767676", "#777776", "#787876", "#797877", "#7a7977", | |
84 "#7b7a77", "#7b7b78", "#7c7b78", "#7d7c78", "#7e7d78", "#7f7e78", | |
85 "#807e78", "#817f78", "#828078", "#838178", "#848178", "#858278", | |
86 "#868378", "#878478", "#888578", "#898578", "#8a8678", "#8b8778", | |
87 "#8c8878", "#8d8878", "#8e8978", "#8f8a78", "#908b78", "#918c78", | |
88 "#928c78", "#938d78", "#948e78", "#958f78", "#968f77", "#979077", | |
89 "#989177", "#999277", "#9a9377", "#9b9377", "#9c9477", "#9d9577", | |
90 "#9e9676", "#9f9776", "#a09876", "#a19876", "#a29976", "#a39a75", | |
91 "#a49b75", "#a59c75", "#a69c75", "#a79d75", "#a89e74", "#a99f74", | |
92 "#aaa074", "#aba174", "#aca173", "#ada273", "#aea373", "#afa473", | |
93 "#b0a572", "#b1a672", "#b2a672", "#b4a771", "#b5a871", "#b6a971", | |
94 "#b7aa70", "#b8ab70", "#b9ab70", "#baac6f", "#bbad6f", "#bcae6e", | |
95 "#bdaf6e", "#beb06e", "#bfb16d", "#c0b16d", "#c1b26c", "#c2b36c", | |
96 "#c3b46c", "#c5b56b", "#c6b66b", "#c7b76a", "#c8b86a", "#c9b869", | |
97 "#cab969", "#cbba68", "#ccbb68", "#cdbc67", "#cebd67", "#d0be66", | |
98 "#d1bf66", "#d2c065", "#d3c065", "#d4c164", "#d5c263", "#d6c363", | |
99 "#d7c462", "#d8c561", "#d9c661", "#dbc760", "#dcc860", "#ddc95f", | |
100 "#deca5e", "#dfcb5d", "#e0cb5d", "#e1cc5c", "#e3cd5b", "#e4ce5b", | |
101 "#e5cf5a", "#e6d059", "#e7d158", "#e8d257", "#e9d356", "#ebd456", | |
102 "#ecd555", "#edd654", "#eed753", "#efd852", "#f0d951", "#f1da50", | |
103 "#f3db4f", "#f4dc4e", "#f5dd4d", "#f6de4c", "#f7df4b", "#f9e049", | |
104 "#fae048", "#fbe147", "#fce246", "#fde345", "#ffe443", "#ffe542", | |
105 "#ffe642", "#ffe743", "#ffe844", "#ffe945" | |
106 }, | |
107 false); | |
108 | |
49 static void | 109 static void |
50 mapDiscrete(double norm, vector<QColor> &colours, double &r, double &g, double &b) | 110 mapDiscrete(double norm, vector<QColor> &colours, double &r, double &g, double &b) |
51 { | 111 { |
52 int n = int(colours.size()); | 112 int n = int(colours.size()); |
53 double m = norm * (n-1); | 113 double m = norm * (n-1); |
59 r = c0.redF() * prop0 + c1.redF() * prop1; | 119 r = c0.redF() * prop0 + c1.redF() * prop1; |
60 g = c0.greenF() * prop0 + c1.greenF() * prop1; | 120 g = c0.greenF() * prop0 + c1.greenF() * prop1; |
61 b = c0.blueF() * prop0 + c1.blueF() * prop1; | 121 b = c0.blueF() * prop0 + c1.blueF() * prop1; |
62 } | 122 } |
63 | 123 |
64 ColourMapper::ColourMapper(int map, double min, double max) : | 124 ColourMapper::ColourMapper(int map, bool inverted, double min, double max) : |
65 m_map(map), | 125 m_map(map), |
126 m_inverted(inverted), | |
66 m_min(min), | 127 m_min(min), |
67 m_max(max) | 128 m_max(max) |
68 { | 129 { |
69 if (m_min == m_max) { | 130 if (m_min == m_max) { |
70 SVCERR << "WARNING: ColourMapper: min == max (== " << m_min | 131 SVCERR << "WARNING: ColourMapper: min == max (== " << m_min |
78 } | 139 } |
79 | 140 |
80 int | 141 int |
81 ColourMapper::getColourMapCount() | 142 ColourMapper::getColourMapCount() |
82 { | 143 { |
83 return 12; | 144 return 15; |
84 } | 145 } |
85 | 146 |
86 QString | 147 QString |
87 ColourMapper::getColourMapName(int n) | 148 ColourMapper::getColourMapLabel(int n) |
88 { | 149 { |
150 // When adding a map, be sure to also update getColourMapCount() | |
151 | |
89 if (n >= getColourMapCount()) return QObject::tr("<unknown>"); | 152 if (n >= getColourMapCount()) return QObject::tr("<unknown>"); |
90 StandardMap map = (StandardMap)n; | 153 ColourMap map = (ColourMap)n; |
91 | 154 |
92 switch (map) { | 155 switch (map) { |
93 case Green: return QObject::tr("Green"); | 156 case Green: return QObject::tr("Green"); |
94 case WhiteOnBlack: return QObject::tr("White on Black"); | 157 case WhiteOnBlack: return QObject::tr("White on Black"); |
95 case BlackOnWhite: return QObject::tr("Black on White"); | 158 case BlackOnWhite: return QObject::tr("Black on White"); |
100 case FruitSalad: return QObject::tr("Fruit Salad"); | 163 case FruitSalad: return QObject::tr("Fruit Salad"); |
101 case Banded: return QObject::tr("Banded"); | 164 case Banded: return QObject::tr("Banded"); |
102 case Highlight: return QObject::tr("Highlight"); | 165 case Highlight: return QObject::tr("Highlight"); |
103 case Printer: return QObject::tr("Printer"); | 166 case Printer: return QObject::tr("Printer"); |
104 case HighGain: return QObject::tr("High Gain"); | 167 case HighGain: return QObject::tr("High Gain"); |
168 case BlueOnBlack: return QObject::tr("Blue on Black"); | |
169 case Cividis: return QObject::tr("Cividis"); | |
170 case Magma: return QObject::tr("Magma"); | |
105 } | 171 } |
106 | 172 |
107 return QObject::tr("<unknown>"); | 173 return QObject::tr("<unknown>"); |
174 } | |
175 | |
176 QString | |
177 ColourMapper::getColourMapId(int n) | |
178 { | |
179 if (n >= getColourMapCount()) return "<unknown>"; | |
180 ColourMap map = (ColourMap)n; | |
181 | |
182 switch (map) { | |
183 case Green: return "Green"; | |
184 case WhiteOnBlack: return "White on Black"; | |
185 case BlackOnWhite: return "Black on White"; | |
186 case Cherry: return "Cherry"; | |
187 case Wasp: return "Wasp"; | |
188 case Ice: return "Ice"; | |
189 case Sunset: return "Sunset"; | |
190 case FruitSalad: return "Fruit Salad"; | |
191 case Banded: return "Banded"; | |
192 case Highlight: return "Highlight"; | |
193 case Printer: return "Printer"; | |
194 case HighGain: return "High Gain"; | |
195 case BlueOnBlack: return "Blue on Black"; | |
196 case Cividis: return "Cividis"; | |
197 case Magma: return "Magma"; | |
198 } | |
199 | |
200 return "<unknown>"; | |
201 } | |
202 | |
203 int | |
204 ColourMapper::getColourMapById(QString id) | |
205 { | |
206 ColourMap map = (ColourMap)getColourMapCount(); | |
207 | |
208 if (id == "Green") { map = Green; } | |
209 else if (id == "White on Black") { map = WhiteOnBlack; } | |
210 else if (id == "Black on White") { map = BlackOnWhite; } | |
211 else if (id == "Cherry") { map = Cherry; } | |
212 else if (id == "Wasp") { map = Wasp; } | |
213 else if (id == "Ice") { map = Ice; } | |
214 else if (id == "Sunset") { map = Sunset; } | |
215 else if (id == "Fruit Salad") { map = FruitSalad; } | |
216 else if (id == "Banded") { map = Banded; } | |
217 else if (id == "Highlight") { map = Highlight; } | |
218 else if (id == "Printer") { map = Printer; } | |
219 else if (id == "High Gain") { map = HighGain; } | |
220 else if (id == "Blue on Black") { map = BlueOnBlack; } | |
221 else if (id == "Cividis") { map = Cividis; } | |
222 else if (id == "Magma") { map = Magma; } | |
223 | |
224 if (map == (ColourMap)getColourMapCount()) { | |
225 return -1; | |
226 } else { | |
227 return int(map); | |
228 } | |
229 } | |
230 | |
231 int | |
232 ColourMapper::getBackwardCompatibilityColourMap(int n) | |
233 { | |
234 /* Returned value should be an index into the series | |
235 * (Default/Green, Sunset, WhiteOnBlack, BlackOnWhite, RedOnBlue, | |
236 * YellowOnBlack, BlueOnBlack, FruitSalad, Banded, Highlight, | |
237 * Printer, HighGain). Minimum 0, maximum 11. | |
238 */ | |
239 | |
240 if (n >= getColourMapCount()) return 0; | |
241 ColourMap map = (ColourMap)n; | |
242 | |
243 switch (map) { | |
244 case Green: return 0; | |
245 case WhiteOnBlack: return 2; | |
246 case BlackOnWhite: return 3; | |
247 case Cherry: return 4; | |
248 case Wasp: return 5; | |
249 case Ice: return 6; | |
250 case Sunset: return 1; | |
251 case FruitSalad: return 7; | |
252 case Banded: return 8; | |
253 case Highlight: return 9; | |
254 case Printer: return 10; | |
255 case HighGain: return 11; | |
256 case BlueOnBlack: return 6; | |
257 case Cividis: return 6; | |
258 case Magma: return 1; | |
259 } | |
260 | |
261 return 0; | |
108 } | 262 } |
109 | 263 |
110 QColor | 264 QColor |
111 ColourMapper::map(double value) const | 265 ColourMapper::map(double value) const |
112 { | 266 { |
113 double norm = (value - m_min) / (m_max - m_min); | 267 double norm = (value - m_min) / (m_max - m_min); |
114 if (norm < 0.0) norm = 0.0; | 268 if (norm < 0.0) norm = 0.0; |
115 if (norm > 1.0) norm = 1.0; | 269 if (norm > 1.0) norm = 1.0; |
270 | |
271 if (m_inverted) { | |
272 norm = 1.0 - norm; | |
273 } | |
116 | 274 |
117 double h = 0.0, s = 0.0, v = 0.0, r = 0.0, g = 0.0, b = 0.0; | 275 double h = 0.0, s = 0.0, v = 0.0, r = 0.0, g = 0.0, b = 0.0; |
118 bool hsv = true; | 276 bool hsv = true; |
119 | 277 |
120 double blue = 0.6666, pieslice = 0.3333; | 278 double blue = 0.6666, pieslice = 0.3333; |
121 | 279 |
122 if (m_map >= getColourMapCount()) return Qt::black; | 280 if (m_map >= getColourMapCount()) return Qt::black; |
123 StandardMap map = (StandardMap)m_map; | 281 ColourMap map = (ColourMap)m_map; |
124 | 282 |
125 switch (map) { | 283 switch (map) { |
126 | 284 |
127 case Green: | 285 case Green: |
128 h = blue - norm * 2.0 * pieslice; | 286 h = blue - norm * 2.0 * pieslice; |
147 | 305 |
148 case Wasp: | 306 case Wasp: |
149 h = 0.15; | 307 h = 0.15; |
150 s = 1.0; | 308 s = 1.0; |
151 v = norm; | 309 v = norm; |
310 break; | |
311 | |
312 case BlueOnBlack: | |
313 h = blue; | |
314 s = 1.0; | |
315 v = norm * 2.0; | |
316 if (v > 1.0) { | |
317 v = 1.0; | |
318 s = 1.0 - (sqrt(norm) - 0.707) * 3.413; | |
319 if (s < 0.0) s = 0.0; | |
320 if (s > 1.0) s = 1.0; | |
321 } | |
152 break; | 322 break; |
153 | 323 |
154 case Sunset: | 324 case Sunset: |
155 r = (norm - 0.24) * 2.38; | 325 r = (norm - 0.24) * 2.38; |
156 if (r > 1.0) r = 1.0; | 326 if (r > 1.0) r = 1.0; |
235 break; | 405 break; |
236 | 406 |
237 case Ice: | 407 case Ice: |
238 hsv = false; | 408 hsv = false; |
239 mapDiscrete(norm, ice, r, g, b); | 409 mapDiscrete(norm, ice, r, g, b); |
410 break; | |
411 | |
412 case Cividis: | |
413 hsv = false; | |
414 mapDiscrete(norm, cividis, r, g, b); | |
415 break; | |
416 | |
417 case Magma: | |
418 hsv = false; | |
419 mapDiscrete(norm, magma, r, g, b); | |
420 break; | |
240 } | 421 } |
241 | 422 |
242 if (hsv) { | 423 if (hsv) { |
243 return QColor::fromHsvF(h, s, v); | 424 return QColor::fromHsvF(h, s, v); |
244 } else { | 425 } else { |
248 | 429 |
249 QColor | 430 QColor |
250 ColourMapper::getContrastingColour() const | 431 ColourMapper::getContrastingColour() const |
251 { | 432 { |
252 if (m_map >= getColourMapCount()) return Qt::white; | 433 if (m_map >= getColourMapCount()) return Qt::white; |
253 StandardMap map = (StandardMap)m_map; | 434 ColourMap map = (ColourMap)m_map; |
254 | 435 |
255 switch (map) { | 436 switch (map) { |
256 | 437 |
257 case Green: | 438 case Green: |
258 return QColor(255, 150, 50); | 439 return QColor(255, 150, 50); |
287 case Printer: | 468 case Printer: |
288 return Qt::red; | 469 return Qt::red; |
289 | 470 |
290 case HighGain: | 471 case HighGain: |
291 return Qt::red; | 472 return Qt::red; |
473 | |
474 case BlueOnBlack: | |
475 return Qt::red; | |
476 | |
477 case Cividis: | |
478 return Qt::white; | |
479 | |
480 case Magma: | |
481 return Qt::white; | |
292 } | 482 } |
293 | 483 |
294 return Qt::white; | 484 return Qt::white; |
295 } | 485 } |
296 | 486 |
297 bool | 487 bool |
298 ColourMapper::hasLightBackground() const | 488 ColourMapper::hasLightBackground() const |
299 { | 489 { |
300 if (m_map >= getColourMapCount()) return false; | 490 if (m_map >= getColourMapCount()) return false; |
301 StandardMap map = (StandardMap)m_map; | 491 ColourMap map = (ColourMap)m_map; |
302 | 492 |
303 switch (map) { | 493 switch (map) { |
304 | 494 |
305 case BlackOnWhite: | 495 case BlackOnWhite: |
306 case Printer: | 496 case Printer: |
314 case Wasp: | 504 case Wasp: |
315 case Ice: | 505 case Ice: |
316 case FruitSalad: | 506 case FruitSalad: |
317 case Banded: | 507 case Banded: |
318 case Highlight: | 508 case Highlight: |
509 case BlueOnBlack: | |
510 case Cividis: | |
511 case Magma: | |
319 | 512 |
320 default: | 513 default: |
321 return false; | 514 return false; |
322 } | 515 } |
323 } | 516 } |