use std::cell::Cell;
use glam::Vec3;
use crate::{
geometry::plane::GpuFacetPlane,
render_setup::{hash_planes, measure_model_width},
};
pub(super) const GRID_DISC_RADIUS_SQ: f32 = 0.70;
const OUTLINE_COVERAGE: f32 = 0.95;
const STANDOFF_HALF_WIDTHS: f32 = 2.5;
const FALLBACK_HALF_WIDTH: f32 = 1.0;
thread_local! {
static LAST_MEASURED: Cell<Option<(u64, f32)>> = const { Cell::new(None) };
}
#[expect(
clippy::cast_possible_truncation,
reason = "f32 is the metrics geometry precision; a stone width in model units is in the normal float range"
)]
fn girdle_half_width(planes: &[GpuFacetPlane]) -> f32 {
let key = hash_planes(planes);
let cached = LAST_MEASURED
.with(Cell::get)
.filter(|&(hash, _)| hash == key);
if let Some((_, half_width)) = cached {
return half_width;
}
let half_width = measure_model_width(planes)
.filter(|width| width.is_finite() && *width > 0.0)
.map_or(FALLBACK_HALF_WIDTH, |width| (width * 0.5) as f32);
LAST_MEASURED.with(|slot| slot.set(Some((key, half_width))));
half_width
}
#[derive(Clone, Copy, Debug)]
pub(super) struct FanGeometry {
standoff: f32,
lateral: f32,
}
impl FanGeometry {
pub(super) fn for_planes(planes: &[GpuFacetPlane]) -> Self {
let half_width = girdle_half_width(planes);
Self {
standoff: STANDOFF_HALF_WIDTHS * half_width,
lateral: OUTLINE_COVERAGE * half_width / GRID_DISC_RADIUS_SQ.sqrt(),
}
}
pub(super) fn half_width(self) -> f32 {
self.standoff / STANDOFF_HALF_WIDTHS
}
pub(super) fn origin(self, forward: Vec3, right: Vec3, up: Vec3, u: f32, v: f32) -> Vec3 {
-forward * self.standoff + (u * self.lateral) * right + (v * self.lateral) * up
}
}