// Scalar helpers shared by every coordinate-system module.
//
// UNITS: every angle in this library is in RADIANS.
///|
pub const PI : Double = 3.141592653589793
///|
pub const TAU : Double = 6.283185307179586
///|
pub const HALF_PI : Double = 1.5707963267948966
///|
pub const DEG2RAD : Double = 0.017453292519943295
///|
pub const RAD2DEG : Double = 57.29577951308232
///|
pub fn deg_to_rad(d : Double) -> Double {
d * DEG2RAD
}
///|
pub fn rad_to_deg(r : Double) -> Double {
r * RAD2DEG
}
///|
pub fn clamp(x : Double, lo : Double, hi : Double) -> Double {
if x < lo {
lo
} else if x > hi {
hi
} else {
x
}
}
///|
pub fn saturate(x : Double) -> Double {
clamp(x, 0.0, 1.0)
}
///|
pub fn lerp(a : Double, b : Double, t : Double) -> Double {
a + (b - a) * t
}
///|
/// |a - b| <= eps (absolute).
pub fn approx(a : Double, b : Double, eps : Double) -> Bool {
(a - b).abs() <= eps
}
///|
/// asin that tolerates |x| slightly above 1 from rounding error.
pub fn safe_asin(x : Double) -> Double {
@math.asin(clamp(x, -1.0, 1.0))
}
///|
/// acos that tolerates |x| slightly above 1 from rounding error.
pub fn safe_acos(x : Double) -> Double {
@math.acos(clamp(x, -1.0, 1.0))
}
///|
/// Wrap an angle into (-PI, PI].
pub fn wrap_pi(a : Double) -> Double {
if a > -PI && a <= PI {
return a
}
let r = a - TAU * @math.floor(a / TAU + 0.5)
// floor(a/TAU + 0.5) puts r in [-PI, PI); move -PI to +PI for a half-open (-PI, PI].
if r <= -PI {
r + TAU
} else {
r
}
}
///|
/// Wrap an angle into [0, TAU).
pub fn wrap_tau(a : Double) -> Double {
let r = a - TAU * @math.floor(a / TAU)
if r >= TAU {
0.0
} else {
r
}
}
///|
/// +1.0 for x >= 0 (including +0 and -0), -1.0 otherwise. Never returns 0.
pub fn sign_nz(x : Double) -> Double {
if x >= 0.0 {
1.0
} else {
-1.0
}
}
///|
/// Floor division remainder that is always in [0, n) for n > 0.
pub fn mod_floor(a : Int, n : Int) -> Int {
let r = a % n
if r < 0 {
r + n
} else {
r
}
}