117 lines
3.5 KiB
Rust
117 lines
3.5 KiB
Rust
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<Float>,
|
|
}
|
|
|
|
impl Eq for DenselySampledSpectrumBuffer {}
|
|
|
|
impl Hash for DenselySampledSpectrumBuffer {
|
|
fn hash<H: Hasher>(&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<Float>) -> 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: 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<Float> = (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;
|
|
}
|
|
}
|
|
}
|