#![allow(dead_code)]
use std::f32::consts::PI;
#[allow(dead_code)]
pub fn deg_to_rad(deg: f32) -> f32 {
deg * (PI / 180.0)
}
#[allow(dead_code)]
pub fn rad_to_deg(rad: f32) -> f32 {
rad * (180.0 / PI)
}
#[allow(dead_code)]
pub fn wrap_angle(angle: f32) -> f32 {
let mut a = angle % (2.0 * PI);
if a > PI {
a -= 2.0 * PI;
} else if a <= -PI {
a += 2.0 * PI;
}
a
}
#[allow(dead_code)]
pub fn angle_diff(a: f32, b: f32) -> f32 {
wrap_angle(b - a)
}
#[allow(dead_code)]
pub fn lerp_angle(a: f32, b: f32, t: f32) -> f32 {
let d = angle_diff(a, b);
wrap_angle(a + d * t)
}
#[allow(dead_code)]
pub fn angle_to_dir(angle: f32) -> [f32; 2] {
[angle.cos(), angle.sin()]
}
#[allow(dead_code)]
pub fn dir_to_angle(d: [f32; 2]) -> f32 {
d[1].atan2(d[0])
}
#[cfg(test)]
mod tests {
use super::*;
const EPS: f32 = 1e-4;
#[test]
fn test_deg_to_rad() {
assert!((deg_to_rad(180.0) - PI).abs() < EPS);
assert!((deg_to_rad(0.0)).abs() < EPS);
}
#[test]
fn test_rad_to_deg() {
assert!((rad_to_deg(PI) - 180.0).abs() < EPS);
assert!((rad_to_deg(0.0)).abs() < EPS);
}
#[test]
fn test_roundtrip() {
let orig = 123.456_f32;
let r = rad_to_deg(deg_to_rad(orig));
assert!((r - orig).abs() < EPS);
}
#[test]
fn test_wrap_angle_pi() {
let a = wrap_angle(PI);
assert!((a - PI).abs() < EPS || (a + PI).abs() < EPS);
}
#[test]
fn test_wrap_angle_overflow() {
let a = wrap_angle(3.0 * PI);
assert!(a.abs() < EPS + PI);
}
#[test]
fn test_angle_diff_zero() {
assert!((angle_diff(1.0, 1.0)).abs() < EPS);
}
#[test]
fn test_lerp_angle_t0() {
assert!((lerp_angle(0.0, PI / 2.0, 0.0)).abs() < EPS);
}
#[test]
fn test_lerp_angle_t1() {
assert!((lerp_angle(0.0, PI / 2.0, 1.0) - PI / 2.0).abs() < EPS);
}
#[test]
fn test_angle_to_dir_zero() {
let d = angle_to_dir(0.0);
assert!((d[0] - 1.0).abs() < EPS);
assert!((d[1]).abs() < EPS);
}
#[test]
fn test_dir_to_angle() {
let a = dir_to_angle([1.0, 0.0]);
assert!(a.abs() < EPS);
let b = dir_to_angle([0.0, 1.0]);
assert!((b - PI / 2.0).abs() < EPS);
}
}