use crate::constants::MUNSELL_RENOTATION_DATA;
pub fn is_specification_in_renotation(spec: &[f64; 4]) -> bool {
let hue = spec[0];
let value = spec[1];
let chroma = spec[2];
let code = spec[3] as u8;
if crate::munsell_color_science::is_grey_munsell_colour(spec) {
for &((family, v, c), _) in MUNSELL_RENOTATION_DATA.iter() {
if family == "N" && (v - value).abs() < 1e-6 && c == 0.0 {
return true;
}
}
return false;
}
let family = match code {
1 => "B",
2 => "BG",
3 => "G",
4 => "GY",
5 => "Y",
6 => "YR",
7 => "R",
8 => "RP",
9 => "P",
10 => "PB",
_ => return false,
};
let hue_str = if (hue - hue.round()).abs() < 1e-6 {
format!("{}{}", hue.round() as i32, family)
} else {
format!("{:.1}{}", hue, family)
};
for &((f, v, c), _) in MUNSELL_RENOTATION_DATA.iter() {
if f == hue_str && (v - value).abs() < 1e-6 && (c - chroma).abs() < 1e-6 {
return true;
}
}
false
}
pub fn to_domain_1(a: f64) -> f64 {
a
}
pub fn from_range_1(a: f64) -> f64 {
a
}
pub fn to_domain_10(a: f64) -> f64 {
a * 10.0
}
pub fn from_range_10(a: f64) -> f64 {
a / 10.0
}
pub fn to_domain_100(a: f64) -> f64 {
a * 100.0
}
pub fn from_range_100(a: f64) -> f64 {
a / 100.0
}
pub fn sdiv(a: f64, b: f64) -> f64 {
if b.abs() < 1e-10 {
0.0
} else {
a / b
}
}
pub fn spow(a: f64, p: f64) -> f64 {
if a < 0.0 && (p - p.floor()).abs() > 1e-10 {
-((-a).powf(p))
} else {
a.powf(p)
}
}
pub fn is_numeric(a: f64) -> bool {
!a.is_nan() && !a.is_infinite()
}
pub fn is_integer(a: f64) -> bool {
(a - a.round()).abs() < 1e-10
}
pub fn as_float(a: f64) -> f64 {
a
}
pub fn as_float_scalar(a: f64) -> f64 {
a
}
pub fn as_int_scalar(a: f64) -> i32 {
a.round() as i32
}
pub fn euclidean_distance(a: &[f64], b: &[f64]) -> f64 {
if a.len() != b.len() {
return f64::NAN;
}
let sum: f64 = a.iter()
.zip(b.iter())
.map(|(ai, bi)| (ai - bi).powi(2))
.sum();
sum.sqrt()
}
pub fn tstack(arrays: &[f64]) -> Vec<f64> {
arrays.to_vec()
}
pub fn tsplit(array: &[f64]) -> Vec<f64> {
array.to_vec()
}
pub fn munsell_value_priest1920(y: f64) -> f64 {
10.0 * y.sqrt()
}
pub fn munsell_value_munsell1933(y: f64) -> f64 {
let inner = 1.4742 * y - 0.004743 * y * y;
if inner < 0.0 {
0.0
} else {
inner.sqrt()
}
}
pub fn munsell_value_moon1943(y: f64) -> f64 {
1.4 * y.powf(0.426)
}
pub fn munsell_value_saunderson1944(y: f64) -> f64 {
let y2 = y * y;
let _y3 = y2 * y;
2.468 * y.powf(1.0/3.0) - 1.636 * y.powf(2.0/3.0) + 0.168
}
pub fn munsell_value_ladd1955(y: f64) -> f64 {
if y <= 0.00856 {
9.033 * y
} else {
let y_cbrt = y.powf(1.0/3.0);
2.354 * y_cbrt - 1.354 * y_cbrt * y.powf(1.0/3.0)
}
}
pub fn munsell_value_mccamy1987(y: f64) -> f64 {
let y_percent = y * 100.0;
if y_percent < 0.31 {
10.0 * y
} else {
2.5 * y_percent.powf(0.43) - 1.7
}
}
pub fn munsell_value(y: f64, method: &str) -> f64 {
match method {
"ASTM D1535" => crate::munsell_color_science::munsell_value_astmd1535(y),
"Priest 1920" => munsell_value_priest1920(y),
"Munsell 1933" => munsell_value_munsell1933(y),
"Moon 1943" => munsell_value_moon1943(y),
"Saunderson 1944" => munsell_value_saunderson1944(y),
"Ladd 1955" => munsell_value_ladd1955(y),
"McCamy 1987" => munsell_value_mccamy1987(y),
_ => crate::munsell_color_science::munsell_value_astmd1535(y), }
}
pub fn is_caching_enabled() -> bool {
true
}
pub fn get_domain_range_scale() -> &'static str {
"1"
}
pub fn usage_warning(message: &str) {
eprintln!("Warning: {}", message);
}
pub fn cast<T>(value: f64) -> T
where
T: From<f64>
{
T::from(value)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_domain_scaling() {
assert_eq!(to_domain_10(0.5), 5.0);
assert_eq!(from_range_10(5.0), 0.5);
assert_eq!(to_domain_100(0.5), 50.0);
assert_eq!(from_range_100(50.0), 0.5);
}
#[test]
fn test_safe_operations() {
assert_eq!(sdiv(10.0, 2.0), 5.0);
assert_eq!(sdiv(10.0, 0.0), 0.0);
assert_eq!(spow(2.0, 3.0), 8.0);
assert_eq!(spow(-2.0, 2.0), 4.0);
}
#[test]
fn test_euclidean_distance() {
let a = vec![0.0, 0.0, 0.0];
let b = vec![3.0, 4.0, 0.0];
assert_eq!(euclidean_distance(&a, &b), 5.0);
}
#[test]
fn test_munsell_value_methods() {
let y = 0.5;
let astm = crate::munsell_color_science::munsell_value_astmd1535(y);
let priest = munsell_value_priest1920(y);
let munsell = munsell_value_munsell1933(y);
assert!(astm >= 0.0 && astm <= 10.0);
assert!(priest >= 0.0 && priest <= 10.0);
assert!(munsell >= 0.0 && munsell <= 10.0);
}
}