use core::ops::Mul;
use crate::linear_algebra::{Matrix, Vector};
use crate::scalar::Numeric;
use crate::spatial::Quaternion;
use crate::spatial::lie::{inverse_left_jacobian_so3, left_jacobian_so3, skew3};
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(clippy::upper_case_acronyms)]
pub struct SO3<T: Numeric> {
q: Quaternion<T>,
}
impl<T: Numeric> SO3<T> {
#[inline]
pub fn identity() -> Self {
SO3 {
q: Quaternion::identity(),
}
}
#[inline]
pub fn from_quaternion(q: Quaternion<T>) -> Self {
SO3 { q: q.normalized() }
}
#[inline]
pub fn try_from_quaternion(q: Quaternion<T>) -> Option<Self> {
q.try_normalized().map(|q| SO3 { q })
}
#[inline]
pub fn quaternion(self) -> Quaternion<T> {
self.q
}
#[inline]
pub fn compose(self, rhs: Self) -> Self {
SO3 { q: self.q * rhs.q }
}
#[inline]
pub fn inverse(self) -> Self {
SO3 {
q: self.q.conjugate(),
}
}
#[inline]
pub fn act(self, p: Vector<3, T>) -> Vector<3, T> {
self.q.transform_point(p)
}
#[inline]
pub fn exp(phi: Vector<3, T>) -> Self {
SO3 {
q: Quaternion::from_scaled_axis(phi),
}
}
#[inline]
pub fn log(self) -> Vector<3, T> {
self.q.to_scaled_axis()
}
#[inline]
pub fn hat(phi: Vector<3, T>) -> Matrix<3, 3, T> {
skew3(phi)
}
#[inline]
pub fn vee(m: Matrix<3, 3, T>) -> Vector<3, T> {
Vector::new([m[(2, 1)], m[(0, 2)], m[(1, 0)]])
}
#[inline]
pub fn adjoint(self) -> Matrix<3, 3, T> {
self.q.to_rotation_matrix()
}
#[inline]
pub fn to_matrix(self) -> Matrix<3, 3, T> {
self.q.to_rotation_matrix()
}
#[inline]
pub fn try_from_matrix(m: Matrix<3, 3, T>) -> Option<Self> {
Quaternion::try_from_rotation_matrix(m).map(|q| SO3 { q })
}
#[inline]
pub fn interpolate(self, other: Self, t: T) -> Self {
SO3 {
q: self.q.slerp(other.q, t),
}
}
#[inline]
pub fn normalized(self) -> Self {
SO3 {
q: self.q.normalized(),
}
}
#[inline]
pub fn left_jacobian(phi: Vector<3, T>) -> Matrix<3, 3, T> {
left_jacobian_so3(phi)
}
#[inline]
pub fn right_jacobian(phi: Vector<3, T>) -> Matrix<3, 3, T> {
left_jacobian_so3(-phi)
}
#[inline]
pub fn left_jacobian_inverse(phi: Vector<3, T>) -> Matrix<3, 3, T> {
inverse_left_jacobian_so3(phi)
}
#[inline]
pub fn right_jacobian_inverse(phi: Vector<3, T>) -> Matrix<3, 3, T> {
inverse_left_jacobian_so3(-phi)
}
}
impl<T: Numeric> Mul for SO3<T> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
self.compose(rhs)
}
}