use crate::spaces::hsluv::{
calc_max_chroma_hpluv, calculate_bounding_lines, lch_to_luv, luv_to_lch, luv_to_xyz,
rgb_to_xyz_hsluv, xyz_to_luv, xyz_to_rgb_hsluv,
};
use crate::spaces::{Rgb, Xyz65};
use crate::traits::ColorSpace;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Hpluv {
pub h: f64,
pub s: f64,
pub l: f64,
pub alpha: Option<f64>,
}
impl ColorSpace for Hpluv {
const MODE: &'static str = "hpluv";
const CHANNELS: &'static [&'static str] = &["h", "s", "l"];
fn alpha(&self) -> Option<f64> {
self.alpha
}
fn with_alpha(self, alpha: Option<f64>) -> Self {
Self { alpha, ..self }
}
fn to_xyz65(&self) -> Xyz65 {
Rgb::from(*self).to_xyz65()
}
fn from_xyz65(xyz: Xyz65) -> Self {
Rgb::from_xyz65(xyz).into()
}
}
impl From<Rgb> for Hpluv {
fn from(c: Rgb) -> Self {
let (x, y, z) = rgb_to_xyz_hsluv(c.r, c.g, c.b);
let (l, u, v) = xyz_to_luv(x, y, z);
let (lch_l, lch_c, lch_h) = luv_to_lch(l, u, v);
let (h, s, l) = lch_to_hpluv(lch_l, lch_c, lch_h);
Self {
h,
s,
l,
alpha: c.alpha,
}
}
}
impl From<Hpluv> for Rgb {
fn from(c: Hpluv) -> Self {
let (lch_l, lch_c, lch_h) = hpluv_to_lch(c.h, c.s, c.l);
let (l, u, v) = lch_to_luv(lch_l, lch_c, lch_h);
let (x, y, z) = luv_to_xyz(l, u, v);
let (r, g, b) = xyz_to_rgb_hsluv(x, y, z);
Self {
r,
g,
b,
alpha: c.alpha,
}
}
}
fn hpluv_to_lch(h: f64, s: f64, l: f64) -> (f64, f64, f64) {
let (lch_l, lch_c) = if l > 99.9999999 {
(100.0, 0.0)
} else if l < 0.00000001 {
(0.0, 0.0)
} else {
let bl = calculate_bounding_lines(l);
let max = calc_max_chroma_hpluv(&bl);
(l, max / 100.0 * s)
};
(lch_l, lch_c, h)
}
fn lch_to_hpluv(l: f64, c: f64, h: f64) -> (f64, f64, f64) {
let (s, l_out) = if l > 99.9999999 {
(0.0, 100.0)
} else if l < 0.00000001 {
(0.0, 0.0)
} else {
let bl = calculate_bounding_lines(l);
let max = calc_max_chroma_hpluv(&bl);
(c / max * 100.0, l)
};
(h, s, l_out)
}