use shared::Float; use shared::core::spectrum::{Spectrum, SpectrumTrait}; use shared::spectra::cie::{CIE_S_LAMBDA, CIE_S0, CIE_S1, CIE_S2, N_CIES}; use shared::spectra::{ BlackbodySpectrum, DenselySampledSpectrum, LAMBDA_MAX, LAMBDA_MIN, PiecewiseLinearSpectrum, }; use shared::utils::math::square; use std::hash::{Hash, Hasher}; #[derive(Clone, Debug, PartialEq)] pub struct DenselySampledSpectrumBuffer { pub lambda_min: i32, pub lambda_max: i32, pub values: Vec, } impl Eq for DenselySampledSpectrumBuffer {} impl Hash for DenselySampledSpectrumBuffer { fn hash(&self, state: &mut H) { self.lambda_min.hash(state); self.lambda_max.hash(state); for &val in &self.values { val.to_bits().hash(state); } } } impl DenselySampledSpectrumBuffer { pub fn new(lambda_min: i32, lambda_max: i32, values: Vec) -> Self { Self { lambda_min, lambda_max, values, } } pub fn new_zero(lambda_min: i32, lambda_max: i32) -> Self { let n_values = (lambda_max - lambda_min + 1).max(0) as usize; let values = vec![0.0; n_values]; Self::new(lambda_min, lambda_max, values) } pub fn from_spectrum(spec: &Spectrum) -> Self { let lambda_min = LAMBDA_MIN; let lambda_max = LAMBDA_MAX; let mut values = Vec::with_capacity((lambda_max - lambda_min + 1) as usize); for lambda in lambda_min..=lambda_max { values.push(spec.evaluate(lambda as Float)); } Self::new(lambda_min, lambda_max, values) } pub fn from_function(f: F, lambda_min: i32, lambda_max: i32) -> Self where F: Fn(Float) -> Float, { let mut values = Vec::with_capacity((lambda_max - lambda_min + 1) as usize); for lambda in lambda_min..=lambda_max { values.push(f(lambda as Float)); } Self::new(lambda_min, lambda_max, values) } pub fn generate_cie_d(temperature: Float) -> Self { let cct = temperature * 1.4388 / 1.4380; if cct < 4000.0 { return Self::from_function( |lambda| BlackbodySpectrum::new(cct).evaluate(lambda), LAMBDA_MIN, LAMBDA_MAX, ); } let x = if cct < 7000. { -4.607 * 1e9 / cct.powi(3) + 2.9678 * 1e6 / square(cct) + 0.09911 * 1e3 / cct + 0.244063 } else { -2.0064 * 1e9 / cct.powi(3) + 1.9018 * 1e6 / square(cct) + 0.24748 * 1e3 / cct + 0.23704 }; let y = -3. * x + 2.87 * x - 0.275; let m = 0.0241 + 0.2562 * x - 0.7341 * y; let m1 = (-1.3515 - 1.7703 * x + 5.9114 * y) / m; let m2 = (0.0300 - 31.4424 * x + 30.0717 * y) / m; let coarse_values: Vec = (0..N_CIES) .map(|i| (CIE_S0[i] + CIE_S1[i] * m1 + CIE_S2[i] * m2) * 0.01) .collect(); let temp_pls = PiecewiseLinearSpectrum { lambdas: CIE_S_LAMBDA.as_ptr().into(), values: coarse_values.as_ptr().into(), count: N_CIES as u32, }; Self::from_function(|lambda| temp_pls.evaluate(lambda), LAMBDA_MIN, LAMBDA_MAX) } pub fn device(&self) -> DenselySampledSpectrum { DenselySampledSpectrum { lambda_min: self.lambda_min, lambda_max: self.lambda_max, values: self.values.as_ptr().into(), } } pub fn scale(&mut self, s: Float) { for v in &mut self.values { *v *= s; } } }