use core::{fmt::Display, ops::Mul};
use super::SO3;
use crate::{
utils::{approx_zero, axis_angle, hat, length},
Algebra, Real, Vec3,
};
use nalgebra::{Matrix3, Vector3};
#[allow(non_camel_case_types)]
#[derive(Debug)]
pub struct so3<T> {
pub(crate) val: Vector3<T>,
}
impl<T> Display for so3<T>
where
T: Display + Real,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
hat(&self.val).fmt(f)
}
}
impl<T> so3<T>
where
T: Real,
{
pub fn new(x: T, y: T, z: T) -> Self {
Self {
val: Vector3::new(x, y, z),
}
}
}
impl<T> Mul<T> for so3<T>
where
T: Real,
{
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
Self {
val: self.val * rhs,
}
}
}
impl<T> Algebra for so3<T>
where
T: Real,
{
type Group = SO3<T>;
type Vector = Vec3<T>;
fn exp(&self) -> Self::Group {
if approx_zero(length(&self.val)) {
SO3 {
val: Matrix3::identity(),
}
} else {
let (w, angle) = axis_angle(&self.val);
let w_so3 = hat(&w);
SO3 {
val: Matrix3::identity()
+ w_so3 * angle.sin()
+ w_so3 * w_so3 * (T::one() - angle.cos()),
}
}
}
fn vee(&self) -> Self::Vector {
Vec3 { val: self.val }
}
}
#[cfg(test)]
mod test {
use super::*;
use approx::assert_relative_eq;
use core::f64::consts::FRAC_PI_2;
#[test]
fn so3_exp() {
let so3 = so3 {
val: Vector3::new(0., 0., FRAC_PI_2),
};
let rot_mat = so3.exp();
assert_relative_eq!(
rot_mat.val,
&Matrix3::new(0., -1., 0., 1., 0., 0., 0., 0., 1.,)
);
}
#[test]
fn so3_vee() {
let so3 = so3 {
val: Vector3::new(0., 0., FRAC_PI_2),
};
let v = so3.vee();
assert_relative_eq!(v.val, Vector3::new(0., 0., FRAC_PI_2));
}
}