aboutsummaryrefslogtreecommitdiffstats
path: root/meowpp/colors/HSL.hpp
blob: 18c01dc4325add9475ebd1d41d1c148fe2d5ff6b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "HSL.h"

#include "RGB.h"
#include "YUV.h"

#include "../utility.h"

namespace meow{
  template<class T>
  inline HSL<T>::HSL(){ }
  template<class T>
  inline HSL<T>::HSL(T const& h, T const& s, T const& l){
    hsl_[0] = h; hsl_[1] = s; hsl_[2] = l;
  }
  template<class T>
  inline HSL<T>::HSL(T const* hsl){
    for(int i = 0; i < 3; i++) hsl_[i] = hsl[i];
  }

  template<class T>
  inline T HSL<T>::h() const { return hsl_[0]; }
  template<class T>
  inline T HSL<T>::s() const { return hsl_[1]; }
  template<class T>
  inline T HSL<T>::l() const { return hsl_[2]; }
  template<class T>
  inline T HSL<T>::hsl(size_t i) const {
    return hsl_[std::min((size_t)3 - 1, i)];
  }
  template<class T>
  inline T HSL<T>::lsh(size_t i)const{return hsl(2-i);}
  template<class T>
  inline T HSL<T>::h(T const& val){return (hsl_[0]=val);}
  template<class T>
  inline T HSL<T>::s(T const& val){return (hsl_[1]=val);}
  template<class T>
  inline T HSL<T>::l(T const& val){return (hsl_[2]=val);}
  template<class T>
  inline T HSL<T>::hsl(size_t i, T const& val){
    return (hsl_[std::min((size_t)3 - 1, i)] = val);
  }
  template<class T>
  inline T HSL<T>::lsh(size_t i, T const& val){
    return hsl(2 - i, val);
  }





  inline HSLf:: HSLf():  HSL(){ }
  inline HSLf::~HSLf(){ }
  inline HSLf::HSLf(double const&h,double const&s,double const&l):HSL(h,s,l){}
  inline HSLf::HSLf(double const* hsl):HSL(hsl){}
  inline double HSLf::hMin() const { return 0.0; }
  inline double HSLf::hMax() const { return 2.0 * PI; }
  inline double HSLf::sMin() const { return 0.0; }
  inline double HSLf::sMax() const { return 1.0; }
  inline double HSLf::lMin() const { return 0.0; }
  inline double HSLf::lMax() const { return 1.0; }




  template<class RGB_T, class HSL_T>
  inline void RGB_to_HSL(RGB<RGB_T> const& rgb, HSL<HSL_T>* hsl){
    double r = normalize(rgb.rMin(), rgb.rMax(), rgb.r());
    double g = normalize(rgb.gMin(), rgb.gMax(), rgb.g());
    double b = normalize(rgb.bMin(), rgb.bMax(), rgb.b());
    double mx = std::max(std::max(r, g), b);
    double mn = std::min(std::min(r, g), b);
    double h, s, l;
    if     (mx == mn         ) h = 0;
    else if(mx == r && g >= b) h = PI/3.0 * (g-b) / (mx-mn);
    else if(mx == r && g <  b) h = PI/3.0 * (g-b) / (mx-mn) + PI * 2.0;
    else if(mx == g          ) h = PI/3.0 * (b-r) / (mx-mn) + PI/3.0*2.0;
    else                       h = PI/3.0 * (r-g) / (mx-mn) + PI/3.0*4.0;
    l = 0.5 * (mx + mn);
    if     (l == 0   || mx == mn) s = 0;
    else if(l <  0.5            ) s = (mx - mn) / (2.0 * l);
    else                          s = (mx - mn) / (2 - 2.0 * l);
    hsl->h(h);
    hsl->s(s);
    hsl->l(l);
  }
  template<class HSL_T, class RGB_T>
  inline void HSL_to_RGB(HSL<HSL_T> const& hsl, RGB<RGB_T>* rgb){
    double h = normalize(hsl.hMin(), hsl.hMax(), hsl.h());
    double s = normalize(hsl.sMin(), hsl.sMax(), hsl.s());
    double l = normalize(hsl.lMin(), hsl.lMax(), hsl.l());
    if(s == 0){
      rgb->r(denormalize(rgb->rMin(), rgb->rMax(), l));
      rgb->g(denormalize(rgb->gMin(), rgb->gMax(), l));
      rgb->b(denormalize(rgb->bMin(), rgb->bMax(), l));
      return ;
    }
    double q = (l < 0.5 ? (l * (1 + s)) : (l + s - (l * s)));
    double p = 2 * l - q;
    double t_r = h + 1.0 / 3.0;
    double t_g = h;
    double t_b = h - 1.0 / 3.0;
    if(t_r < 0) t_r = t_r + 1.0;
    if(t_r > 1) t_r = t_r - 1.0;
    if(t_g < 0) t_g = t_g + 1.0;
    if(t_g > 1) t_g = t_g - 1.0;
    if(t_b < 0) t_b = t_b + 1.0;
    if(t_b > 1) t_b = t_b - 1.0;
    double r, g, b;
    if     (t_r < 1.0 / 6.0) r = p + (q - p) * 6 * t_r;
    else if(t_r < 0.5      ) r = q;
    else if(t_r < 2.0 / 3.0) r = p + (q - p) * 6 * (2.0 / 3.0 - t_r);
    else                     r = p;
    if     (t_g < 1.0 / 6.0) g = p + (q - p) * 6 * t_g;
    else if(t_g < 0.5      ) g = q;
    else if(t_g < 2.0 / 3.0) g = p + (q - p) * 6 * (2.0 / 3.0 - t_g);
    else                     g = p;
    if     (t_b < 1.0 / 6.0) b = p + (q - p) * 6 * t_b;
    else if(t_b < 0.5      ) b = q;
    else if(t_b < 2.0 / 3.0) b = p + (q - p) * 6 * (2.0 / 3.0 - t_b);
    else                     b = p;
    rgb->r(denormalize(rgb->rMin(), rgb->rMax(), r));
    rgb->g(denormalize(rgb->gMin(), rgb->gMax(), g));
    rgb->b(denormalize(rgb->bMin(), rgb->bMax(), b));
  }
  template<class YUV_T, class HSL_T>
  inline void YUV_to_HSL(YUV<YUV_T> const& yuv, HSL<HSL_T>* hsl){
    RGBf tmp;
    YUV_to_RGB(yuv, &tmp);
    RGB_to_HSL(tmp,  hsl);
  }
  template<class HSL_T, class YUV_T>
  inline void HSL_to_YUV(HSL<HSL_T> const& hsl, YUV<YUV_T>* yuv){
    RGBf tmp;
    HSL_to_RGB(hsl, &tmp);
    RGB_to_YUV(tmp,  yuv);
  }
}