#include "HSV.h"

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define max(a, b)  (((a) > (b)) ? (a) : (b))
#define min(a, b)  (((a) < (b)) ? (a) : (b))

 //fix Machine_epsilon
const double epsilon = 0.000001;

/**
David F. Rogers. 1985. 
"Procedural Elements for Computer Graphics."
McGraw-Hill, Inc.

Smith, Alvey Ray. 1978. "Color Gamut Transformation Pairs." 
Computer Graphics. v.12. pp.12-19 (Proc. SIGGRAPH 78).
*/

void HSV_to_RGB (double   H, double S,   double   V,
                 double & R, double & G, double & B)
{
    if (S < epsilon)
    {
        R = G = B = V;
    }
    else
    {
        H = H - floor (H/360.) * 360.;

        if (H<0. || H>360.) 
            H = 0;

        H /= 60.;
        double I = floor (H);
        double F = H - I;
        double M = V * (1 - S);
        double N = V * (1 - S*F);
        double K = V * (1 - S*(1 - F));

        switch ((int)I)
        {
            case 0: R = V; G = K; B = M; break;
            case 1: R = N; G = V; B = M; break;
            case 2: R = M; G = V; B = K; break;
            case 3: R = M; G = N; B = V; break;
            case 4: R = K; G = M; B = V; break;
            case 5: R = V; G = M; B = N; break;
            default: throw ("Error in HSV_to_RGB()");
        }
    }
}

void RGB_to_HSV (double   R, double   G, double   B,
                 double & H, double & S, double & V)
{
    V = max (R, max(G, B)); 
    double minimum = min (R, min(G, B));
 
    if (V < epsilon) S = 0;
    else             S = (V - minimum) / V;

    if (S < epsilon) H = 0;
    else
    {
        double r_tmp = (V - R) / (V - minimum);
        double g_tmp = (V - G) / (V - minimum);
        double b_tmp = (V - B) / (V - minimum);

        if (R == V) H =     b_tmp - g_tmp;
        if (G == V) H = 2 + r_tmp - b_tmp;
        if (B == V) H = 4 + g_tmp - r_tmp;

        H *= 60;

        if (H < 0) H += 360;
    }
}
