#[expect(
clippy::approx_constant,
reason = "the empirical bjango optical-overshoot ratio ~112.84%; coincidentally near 2/sqrt(pi), not derived from it"
)]
pub const CIRCLE_OVERSHOOT: f32 = 1.1284;
#[must_use]
pub fn overshoot(size: f32) -> f32 {
size * CIRCLE_OVERSHOOT
}
#[must_use]
pub fn centroid(vertices: &[(f32, f32)]) -> (f32, f32) {
if vertices.is_empty() {
return (0.0, 0.0);
}
let (sx, sy) = vertices
.iter()
.fold((0.0_f32, 0.0_f32), |(ax, ay), &(x, y)| (ax + x, ay + y));
#[expect(clippy::cast_precision_loss, reason = "vertex counts are tiny")]
let n = vertices.len() as f32;
(sx / n, sy / n)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn overshoot_is_the_circle_square_ratio() {
assert!((overshoot(100.0) - 112.84).abs() < 0.05);
assert!(overshoot(24.0) > 24.0);
}
#[test]
fn centroid_of_a_play_triangle_is_left_of_its_bbox_center() {
let tri = [(0.0, 0.0), (0.0, 1.0), (1.0, 0.5)];
let (cx, cy) = centroid(&tri);
assert!((cx - 1.0 / 3.0).abs() < 1e-6, "cx {cx}");
assert!((cy - 0.5).abs() < 1e-6, "cy {cy}");
assert!(cx < 0.5, "centroid left of bbox center");
}
#[test]
fn centroid_empty_is_origin() {
assert_eq!(centroid(&[]), (0.0, 0.0));
}
}