use crate::si::{QAngle, QLength};
use nalgebra::base::Matrix3;
#[derive(Debug, Clone, Copy)]
pub struct Pose {
position: Matrix3<f64>,
heading: QAngle,
}
impl std::fmt::Display for Pose {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[[{:.3}, {:.3}, {:.3}]\n\
[{:.3}, {:.3}, {:.3}]\n\
[{:.3}, {:.3}, {:.3}]]",
self.position.m11,
self.position.m12,
self.position.m13,
self.position.m21,
self.position.m22,
self.position.m23,
self.position.m31,
self.position.m32,
self.position.m33,
)
}
}
impl Pose {
pub fn new(x: f64, y: f64, heading: QAngle) -> Self {
Pose {
position: Matrix3::new(
heading.cos(),
-heading.sin(),
x,
heading.sin(),
heading.cos(),
y,
0.,
0.,
1.,
),
heading,
}
}
pub fn identity() -> Self {
Pose {
position: Matrix3::new(
QAngle::from_radians(0.).cos(),
QAngle::from_radians(0.).sin(),
0.0,
QAngle::from_radians(0.).sin(),
QAngle::from_radians(0.).cos(),
0.0,
0.,
0.,
1.,
),
heading: Default::default(),
}
}
pub const fn heading(&self) -> QAngle {
self.heading
}
pub fn position(&self) -> (f64, f64) {
(self.position.m13, self.position.m23)
}
pub fn angle(&self, other: Pose) -> QAngle {
QAngle::from_radians(libm::atan2(
other.position.m23 - self.position.m23,
other.position.m13 - self.position.m13,
))
}
pub fn rotate(&self, angle: QAngle) -> Pose {
Pose::new(self.position().0, self.position().1, self.heading + angle)
}
pub fn distance(&self, other: Pose) -> QLength {
QLength::from_meters(libm::hypot(
self.position.m13 - other.position.m13,
self.position.m23 - other.position.m23,
))
}
pub fn move_local(&self, other: Pose) -> Pose {
*self * other
}
pub fn move_global(&self, other: Pose) -> Pose {
other * *self
}
}
impl std::ops::Add<Pose> for Pose {
type Output = Pose;
fn add(self, other: Pose) -> Pose {
Pose::new(
self.position().0 + other.position().0,
self.position().1 + other.position().1,
self.heading,
)
}
}
impl std::ops::Sub<Pose> for Pose {
type Output = Pose;
fn sub(self, other: Pose) -> Pose {
Pose::new(
self.position().0 - other.position().0,
self.position().1 - other.position().1,
self.heading,
)
}
}
impl std::ops::Mul<Pose> for Pose {
type Output = Pose;
fn mul(self, rhs: Pose) -> Self::Output {
Pose {
position: self.position * rhs.position,
heading: self.heading + rhs.heading,
}
}
}
impl std::ops::Mul<f64> for Pose {
type Output = Pose;
fn mul(self, rhs: f64) -> Self::Output {
Pose::new(
self.position.m13 * rhs,
self.position.m23 * rhs,
self.heading,
)
}
}
impl std::ops::Div<f64> for Pose {
type Output = Pose;
fn div(self, rhs: f64) -> Self::Output {
Pose::new(
self.position.m13 / rhs,
self.position.m23 / rhs,
self.heading,
)
}
}
impl From<(f64, f64, f64)> for Pose {
fn from(value: (f64, f64, f64)) -> Self {
Self::new(value.0, value.1, QAngle::from_radians(value.2))
}
}
impl From<(f64, f64)> for Pose {
fn from(value: (f64, f64)) -> Self {
Self::new(value.0, value.1, Default::default())
}
}
impl Default for Pose {
fn default() -> Self {
Self::identity()
}
}