use core::f32::consts::PI;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Twist {
pub vx: f32,
pub vy: f32,
pub omega: f32,
}
impl Twist {
pub fn new(vx: f32, vy: f32, omega: f32) -> Self {
Self { vx, vy, omega }
}
pub fn planar(vx: f32, omega: f32) -> Self {
Self { vx, vy: 0.0, omega }
}
pub fn zero() -> Self {
Self {
vx: 0.0,
vy: 0.0,
omega: 0.0,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Pose {
pub x: f32,
pub y: f32,
pub theta: f32,
}
impl Pose {
pub fn new(x: f32, y: f32, theta: f32) -> Self {
Self {
x,
y,
theta: wrap_pi(theta),
}
}
pub fn origin() -> Self {
Self {
x: 0.0,
y: 0.0,
theta: 0.0,
}
}
}
pub(crate) fn wrap_pi(angle: f32) -> f32 {
let two_pi = 2.0 * PI;
let mut a = angle % two_pi;
if a > PI {
a -= two_pi;
} else if a <= -PI {
a += two_pi;
}
a
}
pub(crate) fn magnitude(value: f32) -> f32 {
if value < 0.0 {
-value
} else {
value
}
}
pub(crate) fn clamp(value: f32, low: f32, high: f32) -> f32 {
if value < low {
low
} else if value > high {
high
} else {
value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn wrap_pi_folds_into_the_canonical_interval() {
assert!(wrap_pi(0.0).abs() < 1e-6);
assert!((wrap_pi(1.0) - 1.0).abs() < 1e-6);
assert!((wrap_pi(2.0 * PI + 0.3) - 0.3).abs() < 1e-5);
for k in -10..=10 {
let w = wrap_pi(k as f32 * 1.3);
assert!(w > -PI - 1e-4 && w <= PI + 1e-4);
}
}
#[test]
fn clamp_and_magnitude_behave() {
assert_eq!(clamp(5.0, 0.0, 1.0), 1.0);
assert_eq!(clamp(-5.0, 0.0, 1.0), 0.0);
assert_eq!(magnitude(-3.0), 3.0);
}
}