cgv
Loading...
Searching...
No Matches
color_scale.cxx
1#include "color_scale.h"
2#include <map>
3#include <algorithm>
4#include <cgv/utils/scan.h>
6
7namespace cgv {
8 namespace media {
9
11color<float,RGB> color_scale(double v, ColorScale cs, int polarity)
12{
13 switch (cs) {
14 case CS_RED: return color<float, RGB>((float)v, 0, 0);
15 case CS_GREEN: return color<float, RGB>(0, (float)v, 0);
16 case CS_BLUE: return color<float, RGB>(0, 0, (float)v);
17 case CS_GRAY: return color<float, RGB>((float)v, (float)v, (float)v);
18 case CS_TEMPERATURE:
19 if (v < 1.0 / 3)
20 return color<float, RGB>((float)(3 * v), 0, 0);
21 if (v < 2.0 / 3)
22 return color<float, RGB>(1, (float)(3 * v) - 1, 0);
23 return color<float, RGB>(1, 1, (float)(3 * v) - 2);
24 case CS_HUE:
25 return color<float, RGB>(color<float, HLS>((float)v, 0.5f, 1));
26 case CS_HUE_LUMINANCE:
27 return color<float, RGB>(color<float, HLS>((float)v, (float)(0.5 * v + 0.25), 1));
28 default:
29 if (int(cs - CS_NAMED) < query_color_scale_names(polarity).size())
30 return sample_sampled_color_scale((float)v, query_named_color_scale(query_color_scale_names(polarity)[cs - CS_NAMED]));
31 break;
32 }
33 return color<float,RGB>((float)v, (float)v, (float)v);
34}
35
36double color_scale_gamma_mapping(double v, double gamma, bool is_bipolar, double window_zero_position)
37{
38 if (is_bipolar) {
39 double amplitude = std::max(window_zero_position, 1.0 - window_zero_position);
40 if (v < window_zero_position)
41 return window_zero_position - std::pow((window_zero_position - v) / amplitude, gamma) * amplitude;
42 else
43 return std::pow((v - window_zero_position) / amplitude, gamma) * amplitude + window_zero_position;
44 }
45 else
46 return std::pow(v, gamma);
47}
48
49
50double adjust_zero_position(double v, double window_zero_position)
51{
52 if (window_zero_position <= 0.5)
53 return 1.0 - 0.5 * (1.0 - v) / (1.0 - window_zero_position);
54 else
55 return 0.5 * v / window_zero_position;
56}
57
58typedef std::pair<std::vector<color<float, RGB>>, bool> scs_entry_type;
59typedef std::map<std::string, scs_entry_type> scs_map_type;
60
61std::vector<color<float, RGB>> construct_sampled_color_scale(unsigned count, unsigned* data)
62{
63 ::std::vector<color<float, RGB>> samples;
64 for (unsigned i = 0; i < count; ++i)
65 samples.push_back(color<float, RGB>(((data[i] & 0xff0000) >> 16) / 255.0f, ((data[i] & 0xff00) >> 8) / 255.0f, (data[i] & 0xff) / 255.0f));
66 return samples;
67}
68
69scs_map_type& ref_sampled_color_scale_map()
70{
71 static scs_map_type scs_map;
72 static bool initialized = false;
73 if (!initialized) {
74 // register default color maps
75 // https://gka.github.io/palettes/#/11|s|000000,760000,ff0000,ffa500,f7f825,ffffff|ffffe0,ff005e,93003a|0|0
76 static unsigned temp[11] = { 0x000000,0x3b0000,0x760000,0xba0000,0xff0000,0xff5300,0xffa500,0xfbce12,0xf7f825,0xfbfc92,0xffffff };
77 // https://learnui.design/tools/data-color-picker.html
78 static unsigned anag[9] = { 0x000000,0x32172e,0x5d2851,0x873e6f,0xaf5c85,0xd37e93,0xefa79b,0xffd4a4,0xffffff };
79 // https://gka.github.io/palettes/#/49|d|43ffff,00cdcd,0073ff,203434|332420,ac0000,ff6100,ffe000|0|0
80 static unsigned bipo[8] = { 0x43ffff, 0x00cdcd, 0x0073ff, 0x203434, 0x332420, 0xac0000, 0xff6100, 0xffe000 };
81 //
82 static unsigned hue[7] = { 0xff0000,0xffff00,0x00ff00,0x00ffff,0x0000ff,0xff00ff,0xff0000 };
83 scs_map["temperature_11"] = scs_entry_type(construct_sampled_color_scale(11, temp),false);
84 scs_map["anaglyph_9"] = scs_entry_type(construct_sampled_color_scale(9, anag), false);
85 scs_map["bipolar_8"] = scs_entry_type(construct_sampled_color_scale(8, bipo), true);
86 scs_map["hue_7"] = scs_entry_type(construct_sampled_color_scale(7, hue),false);
87 initialized = true;
88 }
89 return scs_map;
90}
91
92size_t& ref_named_color_scale_timestamp()
93{
94 static size_t timestamp = 1;
95 return timestamp;
96}
97
98size_t get_named_color_scale_timestamp()
99{
100 return ref_named_color_scale_timestamp();
101}
102
103void register_named_color_scale(const std::string& name, const std::vector<color<float, RGB>>& samples, bool is_bipolar)
104{
105 ref_sampled_color_scale_map()[name] = scs_entry_type(samples, is_bipolar);
106 ++ref_named_color_scale_timestamp();
107}
108
109const std::vector<std::string>& query_color_scale_names(int polarity)
110{
111 static std::vector<std::string> names[3];
112 static size_t timestamp[3] = { 0, 0, 0 };
113 if (timestamp[polarity] < get_named_color_scale_timestamp()) {
114 for (const auto& p : ref_sampled_color_scale_map())
115 if (polarity == 0 || (polarity == (p.second.second ? 2 : 1)))
116 names[polarity].push_back(p.first);
117 timestamp[polarity] = get_named_color_scale_timestamp();
118 }
119 return names[polarity];
120}
121
122std::string get_color_scale_name(ColorScale cs)
123{
124 static const char* color_scale_names[] = { "red","green","blue","gray","temperature","hue","hue_luminance" };
125 if (cs < CS_NAMED)
126 return color_scale_names[cs];
127 int idx = cs - CS_NAMED;
128 if (idx < ref_sampled_color_scale_map().size())
129 for (const auto& p : ref_sampled_color_scale_map()) {
130 if (idx == 0)
131 return p.first;
132 --idx;
133 }
134 return std::string();
135}
136
137bool find_color_scale(const std::string& name, ColorScale& cs)
138{
139 const auto& csm = ref_sampled_color_scale_map();
140 if (csm.find(name) != csm.end()) {
141 ColorScale _cs = CS_NAMED;
142 for (const auto& p : csm) {
143 if (p.first == name) {
144 cs = _cs;
145 return true;
146 }
147 ++((int&)_cs);
148 }
149 return false;
150 }
151 std::string lname = cgv::utils::to_lower(name);
152 if (lname == "red")
153 cs = CS_RED;
154 else if (lname == "green")
155 cs = CS_GREEN;
156 else if (lname == "blue")
157 cs = CS_BLUE;
158 else if (lname == "gray")
159 cs = CS_GRAY;
160 else if (lname == "temperature")
161 cs = CS_TEMPERATURE;
162 else if (lname == "hue")
163 cs = CS_HUE;
164 else if (lname == "hue_luminance")
165 cs = CS_HUE_LUMINANCE;
166 else
167 return false;
168 return true;
169}
170
171const std::string& get_color_scale_enum_definition(bool include_fixed, bool include_named, int polarity)
172{
173 static std::string empty = "enums=''";
174 if (!include_fixed && !include_named)
175 return empty;
176 unsigned i = (include_fixed ? 1 : 0) + (include_named ? 2 : 0) - 1 + 3*polarity;
177 static std::string enum_definitions[9];
178 static size_t timestamps[9] = { 0,0,0, 0,0,0, 0,0,0 };
179 if (timestamps[i] < get_named_color_scale_timestamp()) {
180 std::string def = "enums='";
181 if (include_fixed)
182 def += "red,green,blue,gray,temperature,hue,hue_luminance";
183 if (include_named) {
184 bool no_comma = !include_fixed;
185 unsigned i = 7;
186 for (const auto& p : ref_sampled_color_scale_map()) {
187 if (polarity == 0 || (polarity == (p.second.second ? 2 : 1))) {
188 if (no_comma)
189 no_comma = false;
190 else
191 def += ",";
192 def += p.first;
193 def += "=";
194 def += cgv::utils::to_string(i);
195 }
196 ++i;
197 }
198 }
199 def += "'";
200 enum_definitions[i] = def;
201 timestamps[i] = get_named_color_scale_timestamp();
202 }
203 return enum_definitions[i];
204}
205
206
207const std::vector<color<float, RGB>>& query_named_color_scale(const std::string& name, bool* is_bipolar_ptr)
208{
209 const auto& scs = ref_sampled_color_scale_map()[name];
210 if (is_bipolar_ptr)
211 *is_bipolar_ptr = scs.second;
212 return scs.first;
213}
214
215::std::vector<color<float, RGB>> sample_named_color_scale(const std::string& name, size_t nr_samples, bool exact)
216{
217 const auto& scs_map = ref_sampled_color_scale_map();
218 auto it = scs_map.find(name);
219 if (it == scs_map.end())
220 return ::std::vector<color<float, RGB>>();
221 if (nr_samples == 0)
222 return it->second.first;
223 // determine size of to be returned sampling
224 size_t size = it->second.first.size();
225 size_t target_size = nr_samples;
226 // in case of not exactly given size
227 if (!exact) {
228 // if queried size is larger than size of color scale sampling
229 if (nr_samples > size)
230 // find smallest multiple of size at least as big as queried size
231 target_size = size * size_t(ceil(double(nr_samples) / size));
232 else {
233 // otherwise find smallest divisor of size that is at least as large as fraction of size to queried size
234 size_t divisor = size_t(ceil(double(size) / nr_samples));
235 while (divisor > 1) {
236 if (size == divisor * (size / divisor))
237 break;
238 --divisor;
239 }
240 target_size = divisor * (size / divisor);
241 }
242 }
243 // resampled color scale
244 ::std::vector<color<float, RGB>> result(target_size);
245 for (size_t i = 0; i < target_size; ++i) {
246 float value = float(i) / (target_size - 1);
247 result.push_back(sample_sampled_color_scale(value, it->second.first, it->second.second));
248 }
249 return result;
250}
251
252color<float, RGB> sample_sampled_color_scale(float value, const ::std::vector<color<float, RGB>>& samples, bool is_bipolar)
253{
254 // first check if values needs to be clamped to 0
255 if (value <= 0.0f)
256 return samples.front();
257 // than check if values needs to be clamped to 1 and make sure that values is really smaller than 1
258 if (value > 0.99999f)
259 return samples.back();
260 float v, f;
261 size_t i;
262 // in case of bipolar color map central to samples correspond to -0 and +0
263 if (is_bipolar && ((samples.size() & 1) == 0)) {
264 // scale value up to [0,n-2]
265 v = value * (samples.size() - 2);
266 // compute index of smaller sampled necessary for linear interpolation
267 i = size_t(v);
268 // correct indices in second half
269 if (i+1 >= samples.size()/2)
270 ++i;
271 // compute fractional part
272 f = v - i;
273 }
274 else {
275 // scale value up to [0,n-1]
276 v = value * (samples.size() - 1);
277 // compute index of smaller sampled necessary for linear interpolation
278 i = size_t(v);
279 // compute fractional part
280 f = v - i;
281 }
282 // return affine combination of two adjacent samples
283 return (1.0f - f) * samples[i] + f * samples[i + 1];
284}
285
286
287 }
288}
Helper functions to convert numeric types into strings using std streams.
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
char to_lower(char c)
convert char to lower case
Definition scan.cxx:39
the cgv namespace
Definition print.h:11
Helper functions to process strings.