use crate::bridge::render_thread::hash_planes;
use indicatrix::{geometry::plane::GpuFacetPlane, render_setup::measure_model_width};
#[derive(Debug, Default)]
pub struct StoneWidthCache {
key: Option<u64>,
width: Option<f64>,
}
impl StoneWidthCache {
#[must_use]
pub const fn new() -> Self {
Self {
key: None,
width: None,
}
}
pub fn ensure(&mut self, planes: &[GpuFacetPlane]) -> Option<f64> {
let key = hash_planes(planes);
if self.key != Some(key) {
self.width = measure_model_width(planes);
self.key = Some(key);
}
self.width
}
}
#[cfg(test)]
mod tests {
use super::*;
use indicatrix::geometry::cuts::StandardGemCuts;
#[test]
fn ensure_measures_the_standard_round_brilliant_girdle_width() {
let planes = StandardGemCuts::standard_round_brilliant();
let mut cache = StoneWidthCache::new();
let width = cache.ensure(&planes).expect("SRB must measure");
assert!(width > 0.0, "width {width}");
}
#[test]
fn ensure_is_stable_across_repeated_calls_with_unchanged_planes() {
let planes = StandardGemCuts::standard_round_brilliant();
let mut cache = StoneWidthCache::new();
let first = cache.ensure(&planes);
let second = cache.ensure(&planes);
assert_eq!(first, second);
}
#[test]
fn ensure_remeasures_when_the_design_changes() {
let srb = StandardGemCuts::standard_round_brilliant();
let emerald = StandardGemCuts::emerald_cut();
let mut cache = StoneWidthCache::new();
let srb_width = cache.ensure(&srb);
let emerald_width = cache.ensure(&emerald);
assert_eq!(emerald_width, measure_model_width(&emerald));
assert_ne!(
srb_width, emerald_width,
"SRB and emerald_cut have different girdle widths, so a stale \
(un-remeasured) result would show up as an equal width"
);
}
}