00001
00007 #ifndef __PIXEL_H__
00008 #define __PIXEL_H__
00009
00010 #include <cmath>
00011 #include "mathconstants.h"
00012
00013
00014 #include "../src/boundednumber.h"
00015
00016
00018 namespace Plot {
00019
00020
00021
00022
00023
00024
00025
00027 class Pixel {
00028 public:
00030 Pixel() : transparent(true) { }
00031
00033 Pixel(bool visible) : transparent(!visible) { }
00034
00036 Pixel(const Pixel& other) : transparent(other.transparent) { };
00037
00039 bool istransparent() { return transparent; }
00040
00042 void show() { transparent=false; }
00043
00045 void hide() { transparent=true; }
00046
00048 typedef Bounded::Integer<unsigned char> IComponent;
00049
00051 typedef Bounded::Float< float,1,0,Bounded::Crop<Bounded::LargeFloat> > FComponent;
00052
00054 typedef Bounded::Float< float,1,0,Bounded::Wrap<Bounded::LargeFloat> > HueComponent;
00055
00056 private:
00057 bool transparent;
00058 };
00059
00060
00061
00062
00063
00064
00065 template<class> class RGBPixel;
00066 template<class,class> class HSVPixel;
00067
00068
00069
00071 template<class Component=Pixel::IComponent>
00072 class RGBPixel : public Pixel
00073 {
00074 typedef RGBPixel self;
00075
00076 public:
00080 RGBPixel() : Pixel(), r(0), g(0), b(0) { }
00081
00088 RGBPixel(FComponent value) : Pixel(), r(value), g(value), b(value) { }
00089
00091 RGBPixel(FComponent red, FComponent green, FComponent blue, bool visible=true) : Pixel(visible),
00092 r(red), g(green), b(blue) { }
00093
00095 RGBPixel(const self& other)
00096 : Pixel(other), r(other.r), g(other.g), b(other.b) { }
00097
00099 template<class OComponent, class OHComponent>
00100 RGBPixel(const HSVPixel<OComponent,OHComponent>& O);
00102
00105 Bounded::Magnitude red() const { return r.mag(); }
00106 Bounded::Magnitude green() const { return g.mag(); }
00107 Bounded::Magnitude blue() const { return b.mag(); }
00109
00111 self operator+= (const self &B)
00112 { r=r+B.r; g=g+B.g; b=b+B.b; }
00113
00115 self& operator*=(const Bounded::LargeFloat m)
00116 { r*=m; g*=m; b*=m; return *this; }
00117
00120
00122 std::ostream& put(std::ostream& s) const
00123 { return s << "(" << red() << "," << green() << "," << blue() << ")"; }
00124
00126 self operator+(const self& o) {
00127 self tmp;
00128 tmp.r=r+o.r;
00129 tmp.g=g+o.g;
00130 tmp.b=b+o.b;
00131 return tmp;
00132 }
00133
00136 template<class OutputType>
00137 void write_binary(std::ostream& s, OutputType max_val) const {
00138 s.put(OutputType(max_val*red()));
00139 s.put(OutputType(max_val*green()));
00140 s.put(OutputType(max_val*blue()));
00141 }
00143
00144 private:
00145 Component r,g,b;
00146 };
00147
00148
00149
00151 template<class Component>
00152 std::ostream& operator<<(std::ostream& s, const RGBPixel<Component>& o)
00153 { return o.put(s); }
00154
00155
00156
00158 template<class Component=Pixel::FComponent, class HComponent=Pixel::HueComponent>
00159 class HSVPixel : public Pixel
00160 {
00161 public:
00165 HSVPixel() : Pixel(), h(0), s(0), v(0) { }
00166
00168 HSVPixel(HComponent hue, Component saturation, Component value)
00169 : Pixel(true), h(hue), s(saturation), v(value) { }
00170
00172 HSVPixel(const HSVPixel& other)
00173 : Pixel(other), h(other.h), s(other.s), v(other.v) { }
00174
00176 template<class OComponent>
00177 HSVPixel(const RGBPixel<OComponent>& other);
00179
00182 Bounded::Magnitude hue() const { return h.mag(); }
00183 Bounded::Magnitude saturation() const { return s.mag(); }
00184 Bounded::Magnitude value() const { return v.mag(); }
00186
00188 std::ostream& put(std::ostream& s)
00189 { return s << "(" << hue() << "," << saturation() << "," << value() << ")"; }
00190
00193 static int reversed_color_order;
00194
00195 private:
00196 HComponent h;
00197 Component s,v;
00198 };
00199
00200
00201
00202 template<class Component, class HComponent>
00203 int HSVPixel<Component,HComponent>::reversed_color_order=false;
00204
00205
00207 template<class Component>
00208 std::ostream& operator<<(std::ostream& s, const HSVPixel<Component>& o)
00209 { return o.put(s); }
00210
00211
00217 template<class Component>
00218 template<class OComponent, class OHComponent>
00219 RGBPixel<Component>::RGBPixel(const HSVPixel<OComponent,OHComponent>& other) : Pixel(other)
00220 {
00221 int j;
00222 double rd, gd, bd;
00223 double f, p, q, T;
00224 double hue;
00225
00226 const double h=(HSVPixel<OComponent,OHComponent>::reversed_color_order?
00227 1-other.hue() : other.hue());
00228 const double s=other.saturation();
00229 const double v=other.value();
00230
00231
00232 if (s==0.0) { rd = v; gd = v; bd = v; }
00233 else {
00234
00235 hue = h * 6.0;
00236
00237 j = (int) floor(hue);
00238 if (j<0) j=0;
00239 f = hue - j;
00240 p = v * (1-s);
00241 q = v * (1 - (s*f));
00242 T = v * (1 - (s*(1 - f)));
00243
00244 switch (j) {
00245 case 0: rd = v; gd = T; bd = p; break;
00246 case 1: rd = q; gd = v; bd = p; break;
00247 case 2: rd = p; gd = v; bd = T; break;
00248 case 3: rd = p; gd = q; bd = v; break;
00249 case 4: rd = T; gd = p; bd = v; break;
00250 case 5: rd = v; gd = p; bd = q; break;
00251 default: rd = v; gd = T; bd = p; break;
00252 }
00253 }
00254
00255 r = Component(Bounded::LargeInt(floor( rd*r.Max + 0.5 )));
00256 g = Component(Bounded::LargeInt(floor( gd*g.Max + 0.5 )));
00257 b = Component(Bounded::LargeInt(floor( bd*b.Max + 0.5 )));
00258 }
00259
00260
00261
00268 template<class Component, class HComponent>
00269 template<class OComponent>
00270 HSVPixel<Component,HComponent>::HSVPixel(const RGBPixel<OComponent>& other) : Pixel(other)
00271 {
00272 double r = other.red();
00273 double g = other.green();
00274 double b = other.blue();
00275
00276 double hh=0;
00277
00278 double maxval = std::max(std::max(r,g),b);
00279 double minval = std::min(std::min(r,g),b);
00280
00281
00282 v = maxval;
00283
00284
00285 s = (maxval == 0.0) ? 0.0 : ((maxval-minval)/maxval);
00286
00287
00288 if (s.mag() == 0.0)
00289 hh = 0;
00290 else {
00291 double delt = maxval - minval;
00292
00293 if (r == maxval)
00294 hh = (g - b)/delt;
00295
00296 else if (g == maxval)
00297 hh = 2.0 + (b - r)/delt;
00298
00299 else if (b == maxval)
00300 hh = 4.0 + (r - g)/delt;
00301
00302
00303
00304
00305
00306 hh *= (60.0/360.0); if (hh < 0.0) hh = hh+h.Max;
00307 }
00308 h = (reversed_color_order? 1.0-hh : hh);
00309 }
00310
00311
00312
00320 template<class HSVPixelType=HSVPixel<> >
00321 class PixelAverage {
00322 private:
00323 double valtot, colorx, colory, count;
00324
00325 public:
00326 PixelAverage() : valtot(0), colorx(0), colory(0), count(0) { }
00327
00329 void operator+=(HSVPixelType p) {
00330 const double angle = 2*(Math::pi)*p.hue();
00331 const double mag = p.saturation();
00332 colorx += mag * cos(angle);
00333 colory += mag * sin(angle);
00334 valtot += p.value();
00335 count++;
00336 }
00337
00339 HSVPixelType operator() () const {
00340 const Bounded::Magnitude hue = (colorx? atan2(colory,colorx)/2/(Math::pi) : 0.0);
00341 const Bounded::Magnitude sat = (count? sqrt(colorx*colorx+colory*colory)/count : 0.0);
00342 const Bounded::Magnitude val = (count? valtot/count : 0.0);
00343 return HSVPixel<>(hue,sat,val);
00344 }
00345 };
00346
00347
00348
00358 template<class HSVPixelType>
00359 RGBPixel<> contrasting_color( HSVPixelType prevailing_color) {
00360 const Bounded::Magnitude val = prevailing_color.value();
00361 if (val >= 0.75) return RGBPixel<>(0,0,0);
00362 else if (val < 0.25) return RGBPixel<>(1,1,1);
00363 else return RGBPixel<>(0,0,1);
00364 }
00365
00366
00367 }
00368 #endif