use crate::consts::RGB_UNIT_MAX;
use crate::Hsl;
use crate::normalize::bound_ratio;
use crate::rgb::new_rgb_units;
use crate::units::Units;
static ONE: f64 = 1.0;
static TWO: f64 = 2.0;
static SIX: f64 = 6.0;
static ONE_THIRD: f64 = ONE / 3.0;
static TWO_THIRD: f64 = TWO / 3.0;
pub(crate) fn hsl_to_rgb(hsl: &Hsl) -> Units {
let [h, s, l]: [f64; 3] = hsl.units.as_ratio().into();
if s == 0.0 {
let unit = RGB_UNIT_MAX * l;
return new_rgb_units(unit, unit, unit);
}
let temp1 = if l < 0.5 { l * (ONE + s) } else { l + s - l * s };
let temp2 = TWO * l - temp1;
let hue = h;
let temp_r = bound_ratio(hue + ONE_THIRD);
let temp_g = bound_ratio(hue);
let temp_b = bound_ratio(hue - ONE_THIRD);
let r = calc_rgb_unit(temp_r, temp1, temp2);
let g = calc_rgb_unit(temp_g, temp1, temp2);
let b = calc_rgb_unit(temp_b, temp1, temp2);
new_rgb_units(r, g, b)
}
fn calc_rgb_unit(unit: f64, temp1: f64, temp2: f64) -> f64 {
let mut result = temp2;
if SIX * unit < ONE {
result = temp2 + (temp1 - temp2) * SIX * unit
} else if TWO * unit < ONE {
result = temp1
} else if 3.0 * unit < TWO {
result = temp2 + (temp1 - temp2) * (TWO_THIRD - unit) * SIX
}
result * RGB_UNIT_MAX
}
#[cfg(test)]
mod test {
use crate::{ApproxEq, ColorTuple, Hsl, Rgb};
#[test]
fn hsl_to_rgb_tst() {
use crate::converters::hsl_to_rgb;
fn a(x: ColorTuple, y: ColorTuple) -> bool {
let hsl = Hsl::from(x);
let rgb = Rgb::from(y);
hsl_to_rgb(&hsl).approx_eq_clarify(&rgb.units, 0.5)
}
assert!(a((200.0, 100.0, 30.0), (0.0, 102.0, 153.0)));
assert!(a((192.0, 67.0, 28.0), (24.0, 100.0, 119.0)));
assert!(a((48.0, 70.0, 50.0), (217.0, 181.0, 38.0)));
assert!(a((359.0, 33.0, 77.0), (216.0, 177.0, 178.0)));
}
}