use crate::util::si::{QAngle, QLength};
use nalgebra::base::Matrix3;
use crate::Vector2;
#[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(position: Vector2<f64>, heading: QAngle) -> Self {
Pose {
position: Matrix3::new(
heading.cos(),
-heading.sin(),
position.x,
heading.sin(),
heading.cos(),
position.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) -> Vector2<f64> {
Vector2::<f64>::new(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(), 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(
Vector2::<f64>::new(self.position().x + other.position().x, self.position().y + other.position().y),
self.heading,
)
}
}
impl std::ops::Sub<Pose> for Pose {
type Output = Pose;
fn sub(self, other: Pose) -> Pose {
Pose::new(
Vector2::<f64>::new(self.position().x - other.position().x, self.position().y - other.position().y),
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(
Vector2::<f64>::new(self.position().x * rhs, self.position().y * rhs),
self.heading,
)
}
}
impl std::ops::Div<f64> for Pose {
type Output = Pose;
fn div(self, rhs: f64) -> Self::Output {
Pose::new(
Vector2::<f64>::new(self.position().x / rhs, self.position().y / rhs),
self.heading,
)
}
}
impl From<(f64, f64, f64)> for Pose {
fn from(value: (f64, f64, f64)) -> Self {
Self::new(Vector2::<f64>::new(value.0, value.1), QAngle::from_radians(value.2))
}
}
impl From<(f64, f64)> for Pose {
fn from(value: (f64, f64)) -> Self {
Self::new(Vector2::<f64>::new(value.0, value.1), Default::default())
}
}
impl Default for Pose {
fn default() -> Self {
Self::identity()
}
}