#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MunsellColor {
pub hue_prefix: f32,
pub hue_letter: String,
pub value: f32,
pub chroma: f32,
}
impl MunsellColor {
pub fn new(hue_prefix: f32, hue_letter: impl Into<String>, value: f32, chroma: f32) -> Self {
Self {
hue_prefix,
hue_letter: hue_letter.into(),
value,
chroma,
}
}
pub fn notation(&self) -> String {
format!(
"{}{} {}/{}",
self.hue_prefix, self.hue_letter, self.value, self.chroma
)
}
}
#[derive(Debug, Default, Clone)]
pub struct MunsellExport {
pub entries: Vec<MunsellColor>,
}
impl MunsellExport {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, color: MunsellColor) {
self.entries.push(color);
}
pub fn count(&self) -> usize {
self.entries.len()
}
}
pub fn export_munsell_list(export: &MunsellExport) -> String {
export
.entries
.iter()
.map(|e| e.notation())
.collect::<Vec<_>>()
.join("\n")
}
pub fn validate_munsell(color: &MunsellColor) -> bool {
(0.0..=10.0).contains(&color.value) && color.chroma >= 0.0
}
pub fn munsell_value_to_y(v: f32) -> f32 {
let v = v.clamp(0.0, 10.0);
v * (1.1914 + v * (-0.22533 + v * (0.23352 + v * (-0.020484 + v * 0.00081939))))
}
pub fn achromatic_notation(value: f32) -> String {
format!("N {}", value.clamp(0.0, 10.0))
}
#[cfg(test)]
mod tests {
use super::*;
fn red() -> MunsellColor {
MunsellColor::new(5.0, "R", 5.0, 12.0)
}
#[test]
fn test_notation_format() {
assert_eq!(red().notation(), "5R 5/12");
}
#[test]
fn test_new_export_empty() {
assert_eq!(MunsellExport::new().count(), 0);
}
#[test]
fn test_add_entry() {
let mut exp = MunsellExport::new();
exp.add(red());
assert_eq!(exp.count(), 1);
}
#[test]
fn test_export_list_single() {
let mut exp = MunsellExport::new();
exp.add(red());
assert!(export_munsell_list(&exp).contains("5R"));
}
#[test]
fn test_validate_valid() {
assert!(validate_munsell(&red()));
}
#[test]
fn test_validate_invalid_value() {
let bad = MunsellColor::new(5.0, "R", 11.0, 4.0);
assert!(!validate_munsell(&bad));
}
#[test]
fn test_validate_negative_chroma() {
let bad = MunsellColor::new(5.0, "R", 5.0, -1.0);
assert!(!validate_munsell(&bad));
}
#[test]
fn test_munsell_value_to_y_black() {
assert!(munsell_value_to_y(0.0).abs() < 0.01);
}
#[test]
fn test_achromatic_notation() {
assert_eq!(achromatic_notation(5.0), "N 5");
}
#[test]
fn test_export_list_empty() {
assert_eq!(export_munsell_list(&MunsellExport::new()), "");
}
}