computeMaxSaturation function
Implementation
double computeMaxSaturation(double a, double b) {
// Max saturation will be when one of r, g or b goes below zero.
// Select different coefficients depending on which component goes below zero first
double k0, k1, k2, k3, k4, wl, wm, ws;
if (-1.88170328 * a - 0.80936493 * b > 1) {
// Red component
k0 = 1.19086277;
k1 = 1.76576728;
k2 = 0.59662641;
k3 = 0.75515197;
k4 = 0.56771245;
wl = 4.0767416621;
wm = -3.3077115913;
ws = 0.2309699292;
} else if (1.81444104 * a - 1.19445276 * b > 1) {
// Green component
k0 = 0.73956515;
k1 = -0.45954404;
k2 = 0.08285427;
k3 = 0.12541070;
k4 = 0.14503204;
wl = -1.2684380046;
wm = 2.6097574011;
ws = -0.3413193965;
} else {
// Blue component
k0 = 1.35733652;
k1 = -0.00915799;
k2 = -1.15130210;
k3 = -0.50559606;
k4 = 0.00692167;
wl = -0.0041960863;
wm = -0.7034186147;
ws = 1.7076147010;
}
// Approximate max saturation using a polynomial:
double S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b;
// Do one step Halley's method to get closer
// this gives an error less than 10e6, except for some blue hues where the dS/dh is close to infinite
// this should be sufficient for most applications, otherwise do two/three steps
double kL = 0.3963377774 * a + 0.2158037573 * b;
double kM = -0.1055613458 * a - 0.0638541728 * b;
double kS = -0.0894841775 * a - 1.2914855480 * b;
{
double l_ = 1 + S * kL;
double m_ = 1 + S * kM;
double s_ = 1 + S * kS;
double l = l_ * l_ * l_;
double m = m_ * m_ * m_;
double s = s_ * s_ * s_;
double lDs = 3 * kL * l_ * l_;
double mDs = 3 * kM * m_ * m_;
double sDs = 3 * kS * s_ * s_;
double lDs2 = 6 * kL * kL * l_;
double mDs2 = 6 * kM * kM * m_;
double sDs2 = 6 * kS * kS * s_;
double f = wl * l + wm * m + ws * s;
double f1 = wl * lDs + wm * mDs + ws * sDs;
double f2 = wl * lDs2 + wm * mDs2 + ws * sDs2;
S = S - f * f1 / (f1 * f1 - 0.5 * f * f2);
}
return S;
}