use derive_more::{AsMut, AsRef, Deref, DerefMut, From, Into};
use nalgebra::{Matrix3, Matrix4, Rotation3, Unit, Vector3};
use num_traits::Float;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, AsMut, AsRef, Deref, DerefMut, From, Into)]
pub struct Skew3(pub Vector3<f64>);
impl Skew3 {
pub fn rotation(self) -> Rotation3<f64> {
self.into()
}
pub fn vee(mat: Matrix3<f64>) -> Self {
Self(Vector3::new(mat.m32, mat.m13, mat.m21))
}
#[rustfmt::skip]
pub fn hat(self) -> Matrix3<f64> {
self.0.cross_matrix()
}
#[rustfmt::skip]
pub fn hat2(self) -> Matrix3<f64> {
let w = self.0;
let w11 = w.x * w.x;
let w12 = w.x * w.y;
let w13 = w.x * w.z;
let w22 = w.y * w.y;
let w23 = w.y * w.z;
let w33 = w.z * w.z;
Matrix3::new(
-w22 - w33, w12, w13,
w12, -w11 - w33, w23,
w13, w23, -w11 - w22,
)
}
pub fn bracket(self, rhs: Self) -> Self {
Self::vee(self.hat() * rhs.hat() - rhs.hat() * self.hat())
}
pub fn jacobian_input(self) -> Matrix4<f64> {
let rotation: Rotation3<f64> = self.into();
let matrix: Matrix3<f64> = rotation.into();
matrix.to_homogeneous()
}
pub fn jacobian_self(y: Vector3<f64>) -> Matrix3<f64> {
y.cross_matrix()
}
}
impl From<Skew3> for Rotation3<f64> {
fn from(w: Skew3) -> Self {
let theta2 = w.0.norm_squared();
if theta2 <= f64::epsilon() {
Rotation3::from_matrix(&(Matrix3::identity() + w.hat()))
} else {
let theta = theta2.sqrt();
let axis = Unit::new_unchecked(w.0 / theta);
Self::from_axis_angle(&axis, theta)
}
}
}
impl From<Rotation3<f64>> for Skew3 {
fn from(r: Rotation3<f64>) -> Self {
Self(r.scaled_axis())
}
}