use std::f32::consts::PI;
pub fn clamp_to_range(value: f32, min: f32, max: f32) -> f32 {
value.clamp(min, max)
}
pub fn normalize_angle(angle: f32) -> f32 {
let two_pi = 2.0 * PI;
((angle % two_pi) + two_pi) % two_pi
}
pub fn lerp(start: f32, end: f32, t: f32) -> f32 {
start + (end - start) * t
}
pub fn move_toward(current: f32, target: f32, max_delta: f32) -> f32 {
let diff = target - current;
if diff.abs() <= max_delta {
target
} else {
current + diff.signum() * max_delta
}
}
pub fn is_reasonable_float(value: f32) -> bool {
value.is_finite()
}
#[cfg(test)]
mod tests {
use super::*;
use std::f32::consts::PI;
#[test]
fn test_clamp_to_range() {
assert_eq!(clamp_to_range(-5.0, 0.0, 10.0), 0.0);
assert_eq!(clamp_to_range(15.0, 0.0, 10.0), 10.0);
assert_eq!(clamp_to_range(5.0, 0.0, 10.0), 5.0);
}
#[test]
fn test_normalize_angle() {
assert!((normalize_angle(3.0 * PI) - PI).abs() < 1e-6);
assert!((normalize_angle(-PI / 2.0) - (3.0 * PI / 2.0)).abs() < 1e-6);
assert!((normalize_angle(PI / 4.0) - PI / 4.0).abs() < 1e-6);
}
#[test]
fn test_lerp() {
assert_eq!(lerp(0.0, 10.0, 0.0), 0.0);
assert_eq!(lerp(0.0, 10.0, 1.0), 10.0);
assert_eq!(lerp(0.0, 10.0, 0.5), 5.0);
assert_eq!(lerp(5.0, 15.0, 0.5), 10.0);
}
#[test]
fn test_move_toward() {
assert_eq!(move_toward(0.0, 10.0, 5.0), 5.0);
assert_eq!(move_toward(8.0, 10.0, 5.0), 10.0); assert_eq!(move_toward(10.0, 0.0, 3.0), 7.0); assert_eq!(move_toward(5.0, 5.0, 1.0), 5.0); }
#[test]
fn test_is_reasonable_float() {
assert!(is_reasonable_float(5.0));
assert!(is_reasonable_float(-5.0));
assert!(is_reasonable_float(0.0));
assert!(!is_reasonable_float(f32::NAN));
assert!(!is_reasonable_float(f32::INFINITY));
assert!(!is_reasonable_float(f32::NEG_INFINITY));
}
}