use nalgebra::{DMatrix, Vector3};
use super::Observer;
use crate::{illuminant::CieIlluminant, spectrum::NS, xyz::XYZ};
pub struct OptimalColors(XYZ, DMatrix<Vector3<f64>>);
impl OptimalColors {
pub fn new(observer: Observer, ref_white: CieIlluminant) -> OptimalColors {
let mut optcol: DMatrix<Vector3<f64>> = DMatrix::zeros(NS - 1, NS);
let spectral_locus = observer.monochromes(ref_white);
let white_point = spectral_locus[0].1.white_point();
for c in 0..NS {
optcol[(0, c)] = spectral_locus[c].1.xyz().xyz; }
for r in 1..NS - 1 {
for c in 0..NS {
let i = (c + r) % NS; optcol[(r, c)] = optcol[(r - 1, c)] + optcol[(0, i)];
}
}
OptimalColors(white_point, optcol)
}
pub fn white_point(&self) -> XYZ {
self.0
}
pub fn colors(&self) -> &DMatrix<Vector3<f64>> {
&self.1
}
pub fn observer(&self) -> Observer {
self.0.observer
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::illuminant::CieIlluminant;
use approx::assert_abs_diff_eq;
#[test]
fn test_optimal_colors_matrix_shape_and_first_row() {
let observer = Observer::Cie1931;
let ref_white = CieIlluminant::D65;
let opt_colors = OptimalColors::new(observer, ref_white);
let matrix = opt_colors.colors();
assert_eq!(matrix.nrows(), NS - 1, "Matrix should have NS-1 rows");
assert_eq!(matrix.ncols(), NS, "Matrix should have NS columns");
let spectral_locus = observer.monochromes(ref_white);
for (c, (_, sl_val)) in spectral_locus.iter().enumerate() {
let expected = sl_val.xyz().xyz;
let actual = matrix.row(0)[c];
assert_abs_diff_eq!(expected, actual, epsilon = 1e-10);
}
}
}