pub const EIGHT_WAY_SECTOR: f32 = 0.382_683_43;
#[must_use]
pub fn eight_way(x: f32, y: f32, dead_zone: f32) -> (bool, bool, bool, bool) {
let length = x.hypot(y);
if length < dead_zone {
return (false, false, false, false);
}
let (x, y) = (x / length, y / length);
(
y >= EIGHT_WAY_SECTOR,
y <= -EIGHT_WAY_SECTOR,
x <= -EIGHT_WAY_SECTOR,
x >= EIGHT_WAY_SECTOR,
)
}
#[cfg(test)]
mod tests {
use super::*;
const DEAD_ZONE: f32 = 0.25;
#[test]
fn the_eight_sectors_are_the_angle_they_claim() {
let want = (std::f32::consts::PI / 8.0).sin();
assert!(
(EIGHT_WAY_SECTOR - want).abs() < 1e-6,
"EIGHT_WAY_SECTOR is {EIGHT_WAY_SECTOR}, sin(π/8) is {want}",
);
let at = |degrees: f32| {
let radians = degrees.to_radians();
eight_way(radians.cos(), radians.sin(), DEAD_ZONE)
};
assert_eq!(at(21.5), (false, false, false, true), "east");
assert_eq!(at(23.5), (true, false, false, true), "north-east");
assert_eq!(at(66.5), (true, false, false, true), "still north-east");
assert_eq!(at(68.5), (true, false, false, false), "north");
assert_eq!(at(180.0), (false, false, true, false), "west");
assert_eq!(at(-90.0), (false, true, false, false), "south");
}
#[test]
fn a_deflection_inside_the_dead_zone_asks_for_nothing() {
assert_eq!(eight_way(0.0, 0.0, DEAD_ZONE), (false, false, false, false));
assert_eq!(
eight_way(DEAD_ZONE * 0.99, 0.0, DEAD_ZONE),
(false, false, false, false),
);
assert_eq!(
eight_way(DEAD_ZONE * 1.01, 0.0, DEAD_ZONE),
(false, false, false, true),
);
}
}