Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_sg_colormap 5 #define tools_sg_colormap 6 7 #include "../colorf" 8 #include "../mathf" 9 #include "../scast" 10 #include "style_parser" 11 12 #include <string> 13 #include <cfloat> //FLT_MAX 14 15 namespace tools { 16 namespace sg { 17 18 class base_colormap { 19 #ifdef TOOLS_MEM 20 static const std::string& s_class() { 21 static const std::string s_v("tools::sg::base_colormap"); 22 return s_v; 23 } 24 #endif 25 public: 26 virtual void get_color(float,colorf&) const = 0; 27 virtual void* cast(const std::string&) const = 0; 28 public: 29 base_colormap(){ 30 #ifdef TOOLS_MEM 31 mem::increment(s_class().c_str()); 32 #endif 33 } 34 base_colormap(const base_colormap& aFrom) 35 :m_values(aFrom.m_values),m_colors(aFrom.m_colors){ 36 #ifdef TOOLS_MEM 37 mem::increment(s_class().c_str()); 38 #endif 39 } 40 base_colormap& operator=(const base_colormap& aFrom){ 41 m_values = aFrom.m_values; 42 m_colors = aFrom.m_colors; 43 return *this; 44 } 45 virtual ~base_colormap(){ 46 #ifdef TOOLS_MEM 47 mem::decrement(s_class().c_str()); 48 #endif 49 } 50 public: 51 size_t colorn() const {return m_colors.size();} 52 size_t valn() const {return m_values.size();} 53 colorf color(size_t a_index) const { 54 size_t n = m_colors.size(); 55 if(a_index>=n) return colorf(0.5F,0.5F,0.5F); 56 return m_colors[a_index]; 57 } 58 float value(size_t a_index) const { 59 size_t n = m_values.size(); 60 if(a_index>=n) return 0; 61 return m_values[a_index]; 62 } 63 public: 64 // helper : 65 void set_colors(void(*aGet)(float,colorf&),size_t a_ncell) { 66 m_colors.clear(); 67 m_colors.resize(a_ncell); 68 if(!a_ncell) return; 69 float d = 1.0F/(a_ncell-1); 70 for(size_t index=0;index<a_ncell;index++) { 71 aGet(d*index,m_colors[index]); 72 } 73 } 74 75 void set_PAW_coloring() { 76 size_t _valn = m_values.size(); 77 if(_valn==1) { 78 m_values[0] = take_log(m_values[0]); 79 } else if(_valn>=2) { 80 //CERN/PAW coloring : 81 if(m_values[0]==0) m_values[0] = 10e-5F; 82 float vmin = take_log(m_values[0]); 83 float vmax = take_log(m_values[_valn-1]); 84 float dv = (vmax-vmin)/(_valn-1); 85 for(size_t count=0;count<_valn;count++) { 86 m_values[count] = vmin + dv * count; 87 } 88 } 89 } 90 91 protected: 92 static float take_log(float aVal){ 93 if(aVal<=0) { 94 return -FLT_MAX; 95 } else { 96 return flog10(aVal); 97 } 98 } 99 100 protected: 101 std::vector<float> m_values; 102 std::vector<colorf> m_colors; 103 }; 104 105 class by_value_colormap : public base_colormap { 106 public: 107 TOOLS_SCLASS(tools::sg::by_value_colormap) 108 public: 109 virtual void get_color(float a_value,colorf& a_col) const{ 110 get_by_value(a_value,m_values,m_colors,a_col); 111 } 112 virtual void* cast(const std::string& a_class) const { 113 if(void* p = cmp_cast<by_value_colormap>(this,a_class)) {return p;} 114 else return 0; 115 } 116 public: 117 by_value_colormap(std::ostream& a_out, 118 const sg::cmaps_t& a_cmaps, 119 const std::string& aString){ 120 set_by_value(a_out,a_cmaps,aString,m_values,m_colors); 121 } 122 by_value_colormap(const by_value_colormap& aFrom):base_colormap(aFrom){} 123 by_value_colormap& operator=(const by_value_colormap& aFrom){ 124 base_colormap::operator=(aFrom); 125 return *this; 126 } 127 virtual ~by_value_colormap(){} 128 protected: 129 static void set_by_value(std::ostream& a_out, 130 const sg::cmaps_t& a_cmaps, 131 const std::string& aString, 132 std::vector<float>& aValues, 133 std::vector<colorf>& aColors) { 134 // The given string is of the format : 135 // [<color name> <value>] <color name> 136 // or : 137 // [<value> <color name>] <value> 138 // For example : 139 // black 10 cyan 50 green 100 orange 200 blue 300 pink 400 red 140 std::vector<std::string> ws; 141 words(aString," ",false,ws); 142 size_t wordn = ws.size(); 143 size_t number = wordn/2; 144 if(number<=0) { 145 aValues.clear(); 146 aColors.clear(); 147 } else if((2*number+1)!=wordn) { 148 a_out << "by_value_colormap::set_by_value :" 149 << " An odd number (" << wordn 150 << " given) of words is expected in " << sout(aString) << "." 151 << std::endl; 152 aValues.clear(); 153 aColors.clear(); 154 } else { 155 // look if : 156 // <col> <num> <col> ... <num> <col> 157 // or : 158 // <num> <col> <num> ... <col> <num> 159 // FIXME : case of <col> being three floats ? 160 colorf c; 161 if(sg::find_color(a_cmaps,ws[0],c)) { 162 // <col> <num> <col> ... <num> <col> 163 aValues.resize(number); 164 aColors.resize(number+1); 165 for(size_t count=0;count<number;count++) { 166 {const std::string& word = ws[2*count]; 167 if(!sg::find_color(a_cmaps,word,aColors[count])) { 168 a_out << "by_value_colormap::set_by_value :" 169 << " in " << sout(aString) 170 << ", " << word << " not a color." 171 << std::endl; 172 aValues.clear(); 173 aColors.clear(); 174 return; 175 }} 176 {const std::string& word = ws[2*count+1]; 177 if(!to(word,aValues[count])) { 178 a_out << "by_value_colormap::set_by_value :" 179 << " in " << sout(aString) 180 << ", " << word << " not a number." 181 << std::endl; 182 aValues.clear(); 183 aColors.clear(); 184 return; 185 }} 186 } 187 const std::string& word = ws[wordn-1]; 188 if(!sg::find_color(a_cmaps,word,aColors[number])) { 189 a_out << "by_value_colormap::set_by_value :" 190 << " in " << sout(aString) 191 << ", " << word << " not a color." 192 << std::endl; 193 aValues.clear(); 194 aColors.clear(); 195 } 196 } else { 197 // <num> <col> <num> ... <col> <num> 198 aValues.resize(number+1); 199 aColors.resize(number); 200 for(size_t count=0;count<number;count++) { 201 {const std::string& word = ws[2*count]; 202 if(!to(word,aValues[count])) { 203 a_out << "by_value_colormap::set_by_value :" 204 << " in " << sout(aString) 205 << ", " << word << " not a number." 206 << std::endl; 207 aValues.clear(); 208 aColors.clear(); 209 return; 210 }} 211 {const std::string& word = ws[2*count+1]; 212 if(!sg::find_color(a_cmaps,word,aColors[count])) { 213 a_out << "by_value_colormap::set_by_value :" 214 << " in " << sout(aString) 215 << ", " << word << " not a color." 216 << std::endl; 217 aValues.clear(); 218 aColors.clear(); 219 return; 220 }} 221 } 222 {const std::string& word = ws[wordn-1]; 223 if(!to(word,aValues[number])) { 224 a_out << "by_value_colormap::set_by_value :" 225 << " in " << sout(aString) 226 << ", " << word << " not a number." 227 << std::endl; 228 aValues.clear(); 229 aColors.clear(); 230 return; 231 }} 232 } 233 } 234 } 235 236 static void get_by_value(float aValue, 237 const std::vector<float>& aValues, 238 const std::vector<colorf>& aColors, 239 colorf& a_col){ 240 // There are aValuen (n) entries in aValues and (n+1) aColors 241 // aColors[0] aValues[0] aColors[1] aValues[1]... 242 // aValues[n-2] aColors[n-1] aValues[n-1] aColors[n] 243 // black 10 cyan 50 green 100 orange 200 blue 300 pink 400 red 244 // valuen = 6 245 // values[0] 10 246 // values[1] 50 247 // values[2] 100 248 // values[3] 200 249 // values[4] 300 250 // values[5] 400 251 // 252 // colors[0] black 253 // colors[1] cyan 254 // colors[2] green 255 // colors[3] orange 256 // colors[4] blue 257 // colors[5] pink 258 // colors[6] red 259 size_t _valn = aValues.size(); 260 if(!_valn) {a_col = colorf_black();return;} 261 if(aColors.size()==(_valn+1)) { 262 // col0 val0 col1 val1 col2 val2 col3 263 if(aValue<aValues[0]) { 264 a_col = aColors[0]; 265 } else { 266 for(int count=0;count<=int(_valn-2);count++) { 267 if( (aValues[count]<=aValue) && (aValue<aValues[count+1]) ) { 268 a_col = aColors[count+1]; 269 return; 270 } 271 } 272 a_col = aColors[_valn]; 273 } 274 } else if((aColors.size()+1)==_valn) { 275 // val0 col0 val1 col1 val2 col2 val3 276 for(int count=0;count<=int(_valn-2);count++) { 277 if( (aValues[count]<=aValue) && (aValue<aValues[count+1]) ) { 278 a_col = aColors[count]; 279 return; 280 } 281 } 282 if(aValue<aValues[0]) {a_col = aColors[0];return;} 283 if(aValue>=aValues[_valn-1]) {a_col = aColors[aColors.size()-1];return;} 284 a_col = colorf_black(); 285 } else { 286 a_col = colorf_black(); 287 } 288 } 289 290 }; 291 292 class grey_scale_colormap : public base_colormap { 293 public: 294 TOOLS_SCLASS(tools::sg::grey_scale_colormap) 295 public: 296 virtual void get_color(float a_value,colorf& a_col) const { //a_value in [0,1] 297 get_grey(a_value,a_col); 298 } 299 virtual void* cast(const std::string& a_class) const { 300 if(void* p = cmp_cast<grey_scale_colormap>(this,a_class)) {return p;} 301 else return 0; 302 } 303 public: 304 grey_scale_colormap() {} //if not drawn in sg::plotter. 305 grey_scale_colormap(float a_min,float a_max,size_t a_ncell){ 306 //note : a_min, a_max, a_ncell (and then m_colors, m_values) are used by sg::plotter::update_cmap(). 307 m_values.resize(2); 308 m_values[0] = a_min; 309 m_values[1] = a_max; 310 set_colors(get_grey,a_ncell); 311 } 312 grey_scale_colormap(const grey_scale_colormap& aFrom):base_colormap(aFrom){} 313 grey_scale_colormap& operator=(const grey_scale_colormap& aFrom){ 314 base_colormap::operator=(aFrom); 315 return *this; 316 } 317 virtual ~grey_scale_colormap(){} 318 protected: 319 static void get_grey(float a_ratio,colorf& a_col) { 320 if(a_ratio<0.0F) a_ratio = 0; 321 if(a_ratio>1.0F) a_ratio = 1; 322 a_col.set_value(a_ratio,a_ratio,a_ratio,1); 323 } 324 }; 325 326 class grey_scale_inverse_colormap : public base_colormap { 327 public: 328 TOOLS_SCLASS(tools::sg::grey_scale_inverse_colormap) 329 public: 330 virtual void get_color(float a_value,colorf& a_col) const { //a_value in [0,1] 331 get_grey_inverse(a_value,a_col); 332 } 333 virtual void* cast(const std::string& a_class) const { 334 if(void* p = cmp_cast<grey_scale_inverse_colormap>(this,a_class)) {return p;} 335 else return 0; 336 } 337 public: 338 grey_scale_inverse_colormap() {} //if not drawn in sg::plotter. 339 grey_scale_inverse_colormap(float a_min,float a_max,size_t a_ncell){ 340 //note : a_min, a_max, a_ncell (and then m_colors, m_values) are used by sg::plotter::update_cmap(). 341 m_values.resize(2); 342 m_values[0] = a_min; 343 m_values[1] = a_max; 344 set_colors(get_grey_inverse,a_ncell); 345 } 346 grey_scale_inverse_colormap(const grey_scale_inverse_colormap& aFrom):base_colormap(aFrom){} 347 grey_scale_inverse_colormap& operator=(const grey_scale_inverse_colormap& aFrom){ 348 base_colormap::operator=(aFrom); 349 return *this; 350 } 351 virtual ~grey_scale_inverse_colormap(){} 352 protected: 353 static void get_grey_inverse(float a_ratio,colorf& a_col){ 354 if(a_ratio<0.0F) a_ratio = 0; 355 if(a_ratio>1.0F) a_ratio = 1; 356 a_ratio = 1 - a_ratio; 357 a_col.set_value(a_ratio,a_ratio,a_ratio,1); 358 } 359 }; 360 361 class violet_to_red_colormap : public base_colormap { 362 public: 363 TOOLS_SCLASS(tools::sg::violet_to_red_colormap) 364 public: 365 virtual void get_color(float a_value,colorf& a_col) const { //a_value in [0,1] 366 get_violet_to_red(a_value,a_col); 367 } 368 virtual void* cast(const std::string& a_class) const { 369 if(void* p = cmp_cast<violet_to_red_colormap>(this,a_class)) {return p;} 370 else return 0; 371 } 372 public: 373 violet_to_red_colormap() {} //if not drawn in sg::plotter. 374 violet_to_red_colormap(float a_min,float a_max,size_t a_ncell){ 375 //note : a_min, a_max, a_ncell (and then m_colors, m_values) are used by sg::plotter::update_cmap(). 376 set(a_min,a_max,a_ncell); 377 } 378 violet_to_red_colormap(const violet_to_red_colormap& aFrom):base_colormap(aFrom){} 379 violet_to_red_colormap& operator=(const violet_to_red_colormap& aFrom){ 380 base_colormap::operator=(aFrom); 381 return *this; 382 } 383 virtual ~violet_to_red_colormap(){} 384 public: 385 void set(float a_min,float a_max,size_t a_ncell){ 386 m_values.resize(2); 387 m_values[0] = a_min; 388 m_values[1] = a_max; 389 set_colors(get_violet_to_red,a_ncell); 390 } 391 protected: 392 static void get_violet_to_red(float a_ratio,colorf& a_col){ 393 if(a_ratio<0.0F) a_ratio = 0; 394 if(a_ratio>1.0F) a_ratio = 1; 395 // a_ratio in [0,1] 396 // From ROOT pretty palette. 397 // Initialize with the spectrum Violet->Red 398 // The color model used here is based on the HLS model which 399 // is much more suitable for creating palettes than RGB. 400 // Fixing the saturation and lightness we can scan through the 401 // spectrum of visible light by using "hue" alone. 402 // In Root hue takes values from 0 to 360. 403 float saturation = 1; 404 float lightness = 0.5; 405 float hue_mn = 0; 406 float hue_mx = 280; 407 float hue = hue_mx - a_ratio * (hue_mx-hue_mn); 408 float r,g,b; 409 hls_to_rgb(hue,lightness,saturation,r,g,b); 410 a_col.set_value(r,g,b,1); 411 } 412 413 }; 414 415 class const_colormap : public base_colormap { 416 public: 417 TOOLS_SCLASS(tools::sg::const_colormap) 418 public: 419 virtual void get_color(float,colorf& a_col) const { //a_value in [0,1] 420 a_col = m_colors[0]; 421 } 422 virtual void* cast(const std::string& a_class) const { 423 if(void* p = cmp_cast<const_colormap>(this,a_class)) {return p;} 424 else return 0; 425 } 426 public: 427 const_colormap(const colorf& aColor){m_colors.push_back(aColor);} 428 const_colormap(const const_colormap& aFrom):base_colormap(aFrom){} 429 const_colormap& operator=(const const_colormap& aFrom){ 430 base_colormap::operator=(aFrom); 431 return *this; 432 } 433 virtual ~const_colormap(){} 434 }; 435 436 }} 437 438 #endif