00001
00007 #ifndef __COLORLOOKUP_H__
00008 #define __COLORLOOKUP_H__
00009
00010 #include <cassert>
00011 #include <algorithm>
00012 #include <vector>
00013
00014 #include "pixel.h"
00015 #include "scale.h"
00016
00017 #ifndef NO_VALGEN_STRINGS
00018
00019 #include <string>
00020 using std::string;
00021 #include "stringparser.h"
00022 #include "msg.h"
00023 #endif
00024
00025 namespace Plot {
00026
00027
00028
00029
00030
00031
00032
00033
00039 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00040 class ColorLookup {
00041 public:
00042 virtual ~ColorLookup() { }
00043
00045 ColorLookup(const Scale& scale=default_scale) : fn(scale) { }
00046
00050 virtual PixelType operator() (const double mag) const
00051 { return lookup(fn(mag)); }
00052
00053 protected:
00054 typedef Scale ScaleType;
00055 static ScaleType default_scale;
00056
00057 private:
00058 Scale fn;
00059
00061 virtual PixelType lookup(const Bounded::Magnitude mag) const=0;
00062 };
00063
00064
00065
00066 template<class PixelType, class Scale>
00067 typename ColorLookup<PixelType,Scale>::ScaleType ColorLookup<PixelType,Scale>::default_scale;
00068
00069
00070
00072 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00073 class SingleColorLookup : public ColorLookup<PixelType,Scale> {
00074 public:
00075 virtual ~SingleColorLookup() { }
00076 SingleColorLookup(Bounded::Magnitude hue=0.0, Bounded::Magnitude sat=0.0, Bounded::Magnitude val=0.5)
00077 : h(hue), s(sat), v(val) { }
00078
00079 #ifndef NO_VALGEN_STRINGS
00080 SingleColorLookup(StringArgs& args)
00081 : h(args.next(0.0)), s(args.next(0.0)), v(args.next(0.5)) { }
00082 #endif
00083
00084 private:
00085 virtual PixelType lookup(const Bounded::Magnitude) const
00086 { return PixelType(HSVPixel<>(h,s,v)); }
00087
00088 Bounded::Magnitude h,s,v;
00089 };
00090
00091
00092
00094 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00095 class HueColorLookup : public ColorLookup<PixelType,Scale> {
00096 public:
00097 virtual ~HueColorLookup() { }
00098 HueColorLookup(Bounded::Magnitude sat=1.0, Bounded::Magnitude val=1.0,
00099 const Scale& scale=default_scale)
00100 : ColorLookup<PixelType,Scale>(scale), s(sat), v(val) { }
00101
00102 #ifndef NO_VALGEN_STRINGS
00103 HueColorLookup(StringArgs& args, const Scale& scale=default_scale)
00104 : ColorLookup<PixelType,Scale>(scale), s(args.next(1.0)), v(args.next(1.0)) { }
00105 #endif
00106
00107 private:
00108 virtual PixelType lookup(const Bounded::Magnitude mag) const
00109 { return PixelType(HSVPixel<>(mag,s,v)); }
00110
00111 Bounded::Magnitude s,v;
00112 };
00113
00114
00115
00117 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00118 class SaturationColorLookup : public ColorLookup<PixelType,Scale> {
00119 public:
00120 virtual ~SaturationColorLookup() { }
00121 SaturationColorLookup(Bounded::Magnitude hue=0.0, Bounded::Magnitude val=1.0,
00122 const Scale& scale=default_scale)
00123 : ColorLookup<PixelType,Scale>(scale), h(hue), v(val) { }
00124
00125 #ifndef NO_VALGEN_STRINGS
00126 SaturationColorLookup(StringArgs& args, const Scale& scale=default_scale)
00127 : ColorLookup<PixelType,Scale>(scale), h(args.next(0.0)), v(args.next(1.0)) { }
00128 #endif
00129
00130 private:
00131 virtual PixelType lookup(const Bounded::Magnitude mag) const
00132 { return PixelType(HSVPixel<>(h,mag,v)); }
00133
00134 Bounded::Magnitude h,v;
00135 };
00136
00137
00138
00140 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00141 class ValueColorLookup : public ColorLookup<PixelType,Scale> {
00142 public:
00143 virtual ~ValueColorLookup() { }
00144 ValueColorLookup(Bounded::Magnitude hue=0.0, Bounded::Magnitude sat=0.0,
00145 const Scale& scale=default_scale)
00146 : ColorLookup<PixelType,Scale>(scale), h(hue), s(sat) { }
00147
00148 #ifndef NO_VALGEN_STRINGS
00149 ValueColorLookup(StringArgs& args, const Scale& scale=default_scale)
00150 : ColorLookup<PixelType,Scale>(scale), h(args.next(0.0)), s(args.next(0.0)) { }
00151 #endif
00152
00153 private:
00154 virtual PixelType lookup(const Bounded::Magnitude mag) const
00155 { return PixelType(HSVPixel<>(h,s,mag)); }
00156
00157 Bounded::Magnitude h,s;
00158 };
00159
00160
00161
00171 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00172 class SpecifiedHueLookup : public ColorLookup<PixelType,Scale> {
00173 public:
00174 virtual ~SpecifiedHueLookup() { }
00175 SpecifiedHueLookup(Bounded::Magnitude hue=0.0,
00176 Bounded::Magnitude confidence=1.0,
00177 bool paper_based_colors=false,
00178 const Scale& scale=default_scale)
00179 : ColorLookup<PixelType,Scale>(scale), h(hue), c(confidence) { }
00180
00181 #ifndef NO_VALGEN_STRINGS
00182 SpecifiedHueLookup(StringArgs& args,
00183 bool paper_based_colors=false,
00184 Bounded::Magnitude default_hue=0.0,
00185 const Scale& scale=default_scale)
00186 : ColorLookup<PixelType,Scale>(scale), h(args.next(default_hue)), c(args.next(1.0)),
00187 paper_based(paper_based_colors) { }
00188 #endif
00189
00190 private:
00191 virtual PixelType lookup(const Bounded::Magnitude mag) const {
00192 return (paper_based?
00193 PixelType(HSVPixel<>(h,mag,std::max(1.0-mag,c))) :
00194 PixelType(HSVPixel<>(h,c,mag)));
00195 }
00196
00197 Bounded::Magnitude h,c;
00198 const bool paper_based;
00199 };
00200
00201
00202
00212 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00213 class ColorLookupTable : public ColorLookup<PixelType,Scale> {
00214 protected:
00215 typedef std::vector<PixelType> Table;
00216
00217 public:
00218 ColorLookupTable(size_t numcolors,const Scale& scale=default_scale)
00219 : ColorLookup<PixelType,Scale>(scale), colors(numcolors), valid(true) { }
00220
00221 #ifndef NO_VALGEN_STRINGS
00222
00234 ColorLookupTable(const string& spec_="", size_t numcolors=0, const Scale& scale=default_scale)
00235 : ColorLookup<PixelType,Scale>(scale), colors(numcolors>0?numcolors:252), valid(true) {
00236
00237
00238 const string spec = (spec_.empty()? string("KRYW") : spec_);
00239 const size_t steps = spec.length();
00240 const size_t stepsize = size_t(colors.size()/(steps>1 ? (steps-1) : 1));
00241 size_t start,i;
00242 for (i=0,start=0; i<steps-1; i++,start+=stepsize)
00243 interpolate(start, start+stepsize,color(spec[i]), color(spec[i+1]));
00244 interpolate(start, colors.size(),color(spec[i]), color(spec[steps-1]));
00245 }
00246 #endif
00247
00248 virtual ~ColorLookupTable() { }
00249
00251 bool is_valid() { return valid; }
00252
00253 private:
00254 virtual PixelType lookup(const Bounded::Magnitude mag) const
00255 { return colors[Generic::crop(0,int(colors.size()-1),int(mag*(colors.size()-1)))]; }
00256
00257 protected:
00258 Table colors;
00259 bool valid;
00260
00264 void interpolate(const size_t start, const size_t finish,
00265 const PixelType& startcolor, const PixelType& finishcolor) {
00266 assert (start<=finish);
00267
00268 const size_t num_vals = size_t(finish-start);
00269 const double division = (num_vals!=0 ? 1.0/num_vals : 0);
00270
00271 const double rs = startcolor.red();
00272 const double gs = startcolor.green();
00273 const double bs = startcolor.blue();
00274
00275 const double rinc = division*(finishcolor.red() - startcolor.red());
00276 const double ginc = division*(finishcolor.green() - startcolor.green());
00277 const double binc = division*(finishcolor.blue() - startcolor.blue());
00278
00279 for(size_t i=0; i<num_vals; i++)
00280 colors[start+i]=PixelType(rs+rinc*i,gs+ginc*i,bs+binc*i);
00281 }
00282
00283
00286 PixelType color(const char c) {
00287 PixelType p;
00288 const double h=0.5;
00289 switch (c) {
00290 case 'R': p=PixelType(1,0,0); break; case 'r': p=PixelType(h,0,0); break;
00291 case 'Y': p=PixelType(1,1,0); break; case 'y': p=PixelType(h,h,0); break;
00292 case 'G': p=PixelType(0,1,0); break; case 'g': p=PixelType(0,h,0); break;
00293 case 'C': p=PixelType(0,1,1); break; case 'c': p=PixelType(0,h,h); break;
00294 case 'B': p=PixelType(0,0,1); break; case 'b': p=PixelType(0,0,h); break;
00295 case 'M': p=PixelType(1,0,1); break; case 'm': p=PixelType(h,0,h); break;
00296 case 'W': p=PixelType(1,1,1); break; case 'w': p=PixelType(h,h,h); break;
00297 case 'K': p=PixelType(0,0,0); break; case 'k': p=PixelType(0,0,0); break;
00298 default: valid=false;
00299 }
00300 return p;
00301 }
00302 };
00303
00304
00305
00308 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00309 class KRYWColorLookup : public ColorLookupTable<PixelType,Scale> {
00310 public:
00311 virtual ~KRYWColorLookup() { }
00312 KRYWColorLookup(size_t numcolors=0, const Scale& scale=default_scale)
00313 : ColorLookupTable<PixelType,Scale>((numcolors>0?numcolors:252),scale) {
00314 const size_t step = size_t(colors.size()/3);
00315 interpolate(0, step, PixelType(0,0,0), PixelType(1,0,0));
00316 interpolate(step, 2*step, PixelType(1,0,0), PixelType(1,1,0));
00317 interpolate(2*step, colors.size(), PixelType(1,1,0), PixelType(1,1,1));
00318 }
00319 };
00320
00321
00322
00323
00324
00325
00326
00328 #ifndef NO_VALGEN_STRINGS
00329 template<class PixelType=Plot::RGBPixel<>, class Scale=Scale::Linear<double> >
00330 class ColorLookupFactory {
00331 bool paper_based;
00332 Bounded::Magnitude default_hue;
00333
00334 public:
00335 typedef ColorLookup<PixelType> result_type;
00336 virtual ~ColorLookupFactory() { }
00337
00338 ColorLookupFactory(bool paper_based_colors=false,
00339 Bounded::Magnitude default_single_hue=0)
00340 : paper_based(paper_based_colors), default_hue(default_single_hue) { }
00341
00343 virtual result_type* operator() (string specification) const {
00344
00345 StringParser sp;
00346 StringArgs arglist(sp, specification);
00347 const string name=arglist.next(string(""));
00348 bool warned=false;
00349
00350
00351 const Scale scale=Scale((paper_based? -1.0 : 1.0),
00352 (paper_based? 1.0 : 0.0));
00353 result_type* clu=0;
00354
00355 if (name=="Hue") clu = new HueColorLookup<PixelType>(arglist);
00356 else if (name=="Saturation") clu = new SaturationColorLookup<PixelType>(arglist);
00357 else if (name=="Value") clu = new ValueColorLookup<PixelType>(arglist);
00358 else if (name=="Grayscale") clu = new ValueColorLookup<PixelType>(arglist,scale);
00359 else if (name=="SpecifiedColor") clu = new SingleColorLookup<PixelType>(arglist);
00360 else if (name=="SpecifiedHue") clu = new SpecifiedHueLookup<PixelType>(arglist,paper_based,default_hue);
00361
00362 else if (name=="Cold") clu = new ColorLookupTable<PixelType>(paper_based? "WBC" : "KBCW");
00363 else if (name=="Cool") clu = new ColorLookupTable<PixelType>(paper_based? "WbBC" : "KBC");
00364 else if (name=="Warm") clu = new ColorLookupTable<PixelType>(paper_based? "WrRY" : "KRY");
00365 else if (name=="Hot") clu = new ColorLookupTable<PixelType>(paper_based? "WRY" : "KRYW");
00366 else if (name=="CoolWarm") clu = new ColorLookupTable<PixelType>(paper_based? "CBbWrRY" : "CBKRY");
00367 else if (name=="ColdHot") clu = new ColorLookupTable<PixelType>(paper_based? "CBWRY" : "WCBKRYW");
00368 else if (name=="BlueRed") clu = new ColorLookupTable<PixelType>(paper_based? "BWR" : "BKR");
00369
00370
00371 else if (name=="RYW") clu = new ColorLookupTable<PixelType>(paper_based? "WRY" : "KRYW");
00372
00373 else {
00374 ColorLookupTable<PixelType>* c = new ColorLookupTable<PixelType>(name);
00375 if (c->is_valid()) clu = c;
00376 else {
00377 error("ColorLookup: Unknown or invalid type `" + name + "'");
00378 warned=true;
00379 }
00380 }
00381
00382 if (!warned && !arglist.empty())
00383 error("ColorLookup: Unused arguments: `" + arglist.stringrep() + "'");
00384
00385
00386 if (!clu) clu = new KRYWColorLookup<PixelType>(0,scale);
00387 return clu;
00388 }
00389
00390 virtual void error(const string& s) const {
00391 Msg::LevelHandler<>* mh = Msg::LevelHandler<>::default_instance();
00392 if (mh) (*mh)(Msg::Error,s);
00393 }
00394 };
00395 #endif
00396
00397
00398
00400 #define RYWColorLookup KRYWColorLookup
00401
00402
00403
00404 }
00405 #endif