use super::GemMaterial;
use crate::optics::{
absorption::AbsorptionTensor,
chromophore::{ChromophoreCatalogue, ColorRecipe, resolve},
zoning::{Zone, ZoneAbsorption, ZoneShape, ZonedAbsorption},
};
use glam::DVec3;
use std::sync::OnceLock;
pub const AMETRINE_AMETHYST_FE_PPMA: f64 = 28.7;
pub const AMETRINE_CITRINE_FE_PPMA: f64 = AMETRINE_AMETHYST_FE_PPMA;
const AMETHYST_TREATMENTS: &[&str] = &["gamma_irradiation"];
const CITRINE_TREATMENTS: &[&str] = &["gamma_irradiation", "thermal_anneal_450"];
fn quartz_iron_tensor(iron_ppma: f64, treatments: &[&str]) -> AbsorptionTensor {
let catalogue = ChromophoreCatalogue::global();
let mut recipe = ColorRecipe::new("quartz", catalogue.data_version);
assert!(
recipe.set_amount("Fe", iron_ppma),
"the iron amount is finite"
);
recipe.treatments = treatments.iter().map(|id| (*id).to_owned()).collect();
let (tensor, _warnings) = resolve(&recipe, catalogue)
.expect("the embedded catalogue resolves the quartz iron recipes");
tensor
}
fn zone_tensors() -> &'static (AbsorptionTensor, AbsorptionTensor) {
static TENSORS: OnceLock<(AbsorptionTensor, AbsorptionTensor)> = OnceLock::new();
TENSORS.get_or_init(|| {
(
quartz_iron_tensor(AMETRINE_AMETHYST_FE_PPMA, AMETHYST_TREATMENTS),
quartz_iron_tensor(AMETRINE_CITRINE_FE_PPMA, CITRINE_TREATMENTS),
)
})
}
#[must_use]
pub fn ametrine_zoning() -> ZonedAbsorption {
let (amethyst, citrine) = zone_tensors();
let mut zoning = ZonedAbsorption::new(ZoneAbsorption::per_mm(amethyst.clone()));
zoning.zones.push(Zone {
shape: ZoneShape::HalfSpace {
normal: DVec3::X,
offset: 0.0,
},
absorption: ZoneAbsorption::per_mm(citrine.clone()),
});
zoning
}
impl GemMaterial {
pub(super) fn built_in_material_ametrine() -> Self {
let citrine = Self::built_in_materials_amethyst_through_citrine()
.into_iter()
.find(|material| material.name == "Citrine")
.expect("the Citrine built-in is defined next to Amethyst");
Self {
name: "Ametrine".to_owned(),
..citrine
}
.with_zoning(ametrine_zoning())
}
}