#![allow(clippy::excessive_precision)]
use core::marker::PhantomData;
use crate::model::WavelengthGrid;
use crate::observer::{Cie1931, Cie1964, StandardObserver};
pub trait Illuminant: 'static {
type Observer: StandardObserver;
const WHITE_POINT_XY: [f32; 2];
const WHITE_POINT_XYZ: [f32; 3];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct D65<O: StandardObserver = Cie1931>(PhantomData<O>);
impl Illuminant for D65<Cie1931> {
type Observer = Cie1931;
const WHITE_POINT_XY: [f32; 2] = [0.3127, 0.3290];
const WHITE_POINT_XYZ: [f32; 3] = [0.95047, 1.00000, 1.08883];
}
impl Illuminant for D65<Cie1964> {
type Observer = Cie1964;
const WHITE_POINT_XY: [f32; 2] = [0.3138, 0.3310];
const WHITE_POINT_XYZ: [f32; 3] = [0.94811, 1.00000, 1.07304];
}
impl D65<Cie1931> {
#[rustfmt::skip]
pub const SPD_5NM: &'static [f32; 81] = &[
0.499755, 0.523118, 0.546482, 0.687015, 0.827549, 0.871204, 0.914860, 0.924589, 0.934318, 0.900570,
0.866823, 0.957736, 1.048650, 1.109360, 1.170080, 1.174100, 1.178120, 1.163360, 1.148610, 1.153920,
1.159230, 1.123670, 1.088110, 1.090820, 1.093540, 1.085780, 1.078020, 1.062960, 1.047900, 1.062390,
1.076890, 1.060470, 1.044050, 1.042250, 1.040460, 1.020230, 1.000000, 0.981671, 0.963342, 0.960611,
0.957880, 0.922368, 0.886856, 0.893459, 0.900062, 0.898026, 0.895991, 0.886489, 0.876987, 0.854936,
0.832886, 0.834939, 0.836992, 0.818630, 0.800268, 0.801207, 0.802146, 0.812462, 0.822778, 0.802810,
0.782842, 0.740027, 0.697213, 0.706652, 0.716091, 0.729790, 0.743490, 0.679765, 0.616040, 0.657448,
0.698856, 0.724862, 0.750869, 0.693398, 0.635927, 0.550054, 0.464182, 0.566118, 0.668054, 0.650942,
0.633830,
];
pub const fn spd<const BANDS: usize, G: WavelengthGrid<BANDS>>() -> [f32; BANDS] {
let mut out = [0.0f32; BANDS];
let mut i = 0;
while i < BANDS {
let nm = G::START_NM + i as f32 * G::STEP_NM;
if nm >= 380.0 && nm <= 780.0 {
let t = (nm - 380.0) / 5.0;
let lo = t as usize;
let hi = if lo < 80 { lo + 1 } else { 80 };
let frac = t - lo as f32;
out[i] = Self::SPD_5NM[lo] * (1.0 - frac) + Self::SPD_5NM[hi] * frac;
}
i += 1;
}
out
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct D50<O: StandardObserver = Cie1931>(PhantomData<O>);
impl Illuminant for D50<Cie1931> {
type Observer = Cie1931;
const WHITE_POINT_XY: [f32; 2] = [0.3457, 0.3585];
const WHITE_POINT_XYZ: [f32; 3] = [0.96422, 1.00000, 0.82521];
}
impl Illuminant for D50<Cie1964> {
type Observer = Cie1964;
const WHITE_POINT_XY: [f32; 2] = [0.3477, 0.3595];
const WHITE_POINT_XYZ: [f32; 3] = [0.96720, 1.00000, 0.81427];
}
impl D50<Cie1931> {
#[rustfmt::skip]
pub const SPD_5NM: &'static [f32; 81] = &[
0.266024, 0.314300, 0.333033, 0.443867, 0.588167, 0.664700, 0.741233, 0.771244, 0.801267, 0.769711,
0.738156, 0.865411, 0.992667, 1.056422, 1.120189, 1.116278, 1.112367, 1.127200, 1.142033, 1.139233,
1.136433, 1.111322, 1.086211, 1.089200, 1.092189, 1.083844, 1.075489, 1.064311, 1.053144, 1.067956,
1.082767, 1.064311, 1.045833, 1.049189, 1.052544, 1.026278, 1.000000, 0.994489, 0.988978, 0.986311,
0.983644, 0.949211, 0.914778, 0.924544, 0.934311, 0.926900, 0.919478, 0.909322, 0.899167, 0.877911,
0.856656, 0.858400, 0.860144, 0.844711, 0.829278, 0.829922, 0.830567, 0.839733, 0.848900, 0.830722,
0.812533, 0.770511, 0.728478, 0.738467, 0.748456, 0.763511, 0.778578, 0.715111, 0.651644, 0.703344,
0.755044, 0.791544, 0.828056, 0.765333, 0.702611, 0.611144, 0.519689, 0.638233, 0.756789, 0.738189,
0.719600,
];
pub const fn spd<const BANDS: usize, G: WavelengthGrid<BANDS>>() -> [f32; BANDS] {
let mut out = [0.0f32; BANDS];
let mut i = 0;
while i < BANDS {
let nm = G::START_NM + i as f32 * G::STEP_NM;
if nm >= 380.0 && nm <= 780.0 {
let t = (nm - 380.0) / 5.0;
let lo = t as usize;
let hi = if lo < 80 { lo + 1 } else { 80 };
let frac = t - lo as f32;
out[i] = Self::SPD_5NM[lo] * (1.0 - frac) + Self::SPD_5NM[hi] * frac;
}
i += 1;
}
out
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct D60<O: StandardObserver = Cie1931>(PhantomData<O>);
impl Illuminant for D60<Cie1931> {
type Observer = Cie1931;
const WHITE_POINT_XY: [f32; 2] = [0.32163, 0.33774];
const WHITE_POINT_XYZ: [f32; 3] = [0.95230, 1.00000, 1.00856];
}
impl Illuminant for D60<Cie1964> {
type Observer = Cie1964;
const WHITE_POINT_XY: [f32; 2] = [0.3223, 0.3348];
const WHITE_POINT_XYZ: [f32; 3] = [0.95002, 1.00000, 1.00350];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct DciWhite;
impl Illuminant for DciWhite {
type Observer = Cie1931;
const WHITE_POINT_XY: [f32; 2] = [0.3140, 0.3510];
const WHITE_POINT_XYZ: [f32; 3] = [0.89459, 1.00000, 0.95442];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct AcesWhitePoint;
impl Illuminant for AcesWhitePoint {
type Observer = Cie1931;
const WHITE_POINT_XY: [f32; 2] = [0.32168, 0.33767];
const WHITE_POINT_XYZ: [f32; 3] = [0.95265, 1.00000, 1.00883];
}