#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);
}
}