#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AbsorptionBand {
pub center_nm: f32,
pub width_nm: f32,
pub peak: f32,
}
impl AbsorptionBand {
#[must_use]
pub const fn new(center_nm: f32, width_nm: f32, peak: f32) -> Self {
Self {
center_nm,
width_nm,
peak,
}
}
#[must_use]
pub fn evaluate(&self, lambda_nm: f32) -> f32 {
let t = (lambda_nm - self.center_nm) / self.width_nm;
self.peak * (-0.5 * t * t).exp()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AbsorptionTensor {
pub o_ray: Vec<AbsorptionBand>,
pub e_ray: Vec<AbsorptionBand>,
pub beta_ray: Option<Vec<AbsorptionBand>>,
pub is_pleochroic: bool,
}
impl AbsorptionTensor {
#[must_use]
pub fn isotropic(bands: Vec<AbsorptionBand>) -> Self {
Self {
o_ray: bands.clone(),
e_ray: bands,
beta_ray: None,
is_pleochroic: false,
}
}
#[must_use]
pub const fn uniaxial(o: Vec<AbsorptionBand>, e: Vec<AbsorptionBand>) -> Self {
Self {
o_ray: o,
e_ray: e,
beta_ray: None,
is_pleochroic: true,
}
}
#[must_use]
pub const fn biaxial(
alpha: Vec<AbsorptionBand>,
beta: Vec<AbsorptionBand>,
gamma: Vec<AbsorptionBand>,
) -> Self {
Self {
o_ray: alpha,
e_ray: gamma,
beta_ray: Some(beta),
is_pleochroic: true,
}
}
}
#[must_use]
pub fn legacy_rgb_bands(rgb: [f32; 3]) -> Vec<AbsorptionBand> {
vec![
AbsorptionBand::new(620.0, 55.0, rgb[0]),
AbsorptionBand::new(540.0, 45.0, rgb[1]),
AbsorptionBand::new(450.0, 45.0, rgb[2]),
]
}