use crate::chan::Channel;
#[derive(Clone, Copy, Debug)]
pub enum Hexcone {
Red(f32),
Yellow(f32),
Green(f32),
Cyan(f32),
Blue(f32),
Magenta(f32),
}
impl Hexcone {
pub fn from_hue_prime(hp: f32) -> Self {
use Hexcone::*;
let h = hp as i32; let hf = hp.fract();
match h {
1 => Yellow(hf),
2 => Green(hf),
3 => Cyan(hf),
4 => Blue(hf),
5 => Magenta(hf),
_ => Red(hf),
}
}
fn secondary<C: Channel>(self, chroma: C) -> C {
use Hexcone::*;
match self {
Red(hf) | Green(hf) | Blue(hf) => chroma * C::from(hf),
Yellow(hf) | Cyan(hf) | Magenta(hf) => {
chroma * (C::MAX - C::from(hf))
}
}
}
pub fn rgb<C: Channel>(self, chroma: C) -> (C, C, C) {
use Hexcone::*;
let secondary = self.secondary(chroma);
match self {
Red(_) => (chroma, secondary, C::MIN),
Yellow(_) => (secondary, chroma, C::MIN),
Green(_) => (C::MIN, chroma, secondary),
Cyan(_) => (C::MIN, secondary, chroma),
Blue(_) => (secondary, C::MIN, chroma),
Magenta(_) => (chroma, C::MIN, secondary),
}
}
}
pub fn rgb_to_hue_chroma_value<C: Channel>(
red: C,
green: C,
blue: C,
) -> (C, C, C) {
let val = red.max(green).max(blue);
let chroma = val - red.min(green).min(blue);
let hue = if chroma > C::MIN {
(if val == red {
if green >= blue {
(green.to_f32() - blue.to_f32()) / chroma.to_f32()
} else {
6.0 - (blue.to_f32() - green.to_f32()) / chroma.to_f32()
}
} else if green == val {
2.0 + (blue.to_f32() - red.to_f32()) / chroma.to_f32()
} else {
4.0 + (red.to_f32() - green.to_f32()) / chroma.to_f32()
}) / 6.0
} else {
0.0
};
(C::from(hue), chroma, val)
}