cranpose-ui-graphics 0.1.167

Pure math/data for drawing & units in Cranpose
Documentation
use crate::{
    ArcGeometry, TAU,
    float::{at_least, within},
};

#[derive(Clone, Debug)]
struct AngleTrig<const N: usize> {
    keys: [u32; N],
    values: [(f32, f32); N],
    len: usize,
    next: usize,
}

impl<const N: usize> Default for AngleTrig<N> {
    fn default() -> Self {
        Self {
            keys: [0; N],
            values: [(0.0, 0.0); N],
            len: 0,
            next: 0,
        }
    }
}

impl<const N: usize> AngleTrig<N> {
    fn resolve(&mut self, angle: f32) -> (f32, f32) {
        let key = angle.to_bits();
        if let Some(index) = self.keys[..self.len].iter().position(|held| *held == key) {
            return self.values[index];
        }
        let result = angle.sin_cos();
        self.keys[self.next] = key;
        self.values[self.next] = result;
        self.len = (self.len + 1).min(N);
        self.next = (self.next + 1) % N;
        result
    }
}

#[derive(Clone, Debug, Default)]
pub(crate) struct ArcTrigCache {
    mid: AngleTrig<1>,
    half: AngleTrig<8>,
}

impl ArcTrigCache {
    pub(crate) fn resolve(&mut self, geometry: &ArcGeometry) -> [f32; 4] {
        if geometry.sweep_angle >= TAU && geometry.start_angle == 0.0 {
            return [0.0, -1.0, 0.0, -1.0];
        }
        let half_sweep = within(geometry.sweep_angle, 0.0, TAU) * 0.5;
        let (mid_sin, mid_cos) = self.mid.resolve(geometry.start_angle + half_sweep);
        let (half_sin, half_cos) = self.half.resolve(half_sweep);
        [mid_sin, mid_cos, at_least(half_sin, 0.0), half_cos]
    }
}

#[cfg(test)]
#[path = "tests/arc_trig_cache_tests.rs"]
mod tests;