mod se2;
mod se3;
mod so2;
mod so3;
pub use se2::SE2;
pub use se3::SE3;
pub use so2::SO2;
pub use so3::SO3;
use crate::linear_algebra::{Matrix, Vector};
use crate::scalar::Numeric;
use crate::spatial::small_angle_sq;
#[inline]
pub(crate) fn skew3<T: Numeric>(v: Vector<3, T>) -> Matrix<3, 3, T> {
let [x, y, z] = *v.as_array();
Matrix::new([[T::ZERO, -z, y], [z, T::ZERO, -x], [-y, x, T::ZERO]])
}
#[inline]
pub(crate) fn left_jacobian_so3<T: Numeric>(phi: Vector<3, T>) -> Matrix<3, 3, T> {
let theta_sq = phi.dot(phi);
let s = skew3(phi);
let s2 = s * s;
let (c1, c2) = if theta_sq < small_angle_sq::<T>() {
(
T::HALF - theta_sq / T::from_f64(24.0),
T::ONE / T::from_f64(6.0) - theta_sq / T::from_f64(120.0),
)
} else {
let theta = theta_sq.sqrt();
(
(T::ONE - theta.cos()) / theta_sq,
(theta - theta.sin()) / (theta_sq * theta),
)
};
Matrix::identity() + s.scale(c1) + s2.scale(c2)
}
#[inline]
pub(crate) fn inverse_left_jacobian_so3<T: Numeric>(phi: Vector<3, T>) -> Matrix<3, 3, T> {
let theta_sq = phi.dot(phi);
let s = skew3(phi);
let s2 = s * s;
let c3 = if theta_sq < small_angle_sq::<T>() {
T::ONE / T::from_f64(12.0) + theta_sq / T::from_f64(720.0)
} else {
let theta = theta_sq.sqrt();
let half = theta * T::HALF;
(T::ONE - half * (half.cos() / half.sin())) / theta_sq
};
Matrix::identity() - s.scale(T::HALF) + s2.scale(c3)
}
#[inline]
pub(crate) fn q_matrix_se3<T: Numeric>(rho: Vector<3, T>, phi: Vector<3, T>) -> Matrix<3, 3, T> {
let theta_sq = phi.dot(phi);
let p = skew3(rho);
let ph = skew3(phi);
let (c2, c3, c5) = if theta_sq < small_angle_sq::<T>() {
(
T::ONE / T::from_f64(6.0) - theta_sq / T::from_f64(120.0),
T::ONE / T::from_f64(24.0) - theta_sq / T::from_f64(720.0),
-T::ONE / T::from_f64(120.0) + theta_sq / T::from_f64(5040.0),
)
} else {
let theta = theta_sq.sqrt();
let theta3 = theta_sq * theta;
let theta4 = theta_sq * theta_sq;
let theta5 = theta4 * theta;
(
(theta - theta.sin()) / theta3,
(T::ONE - theta_sq * T::HALF - theta.cos()) / theta4,
(theta - theta.sin() - theta3 / T::from_f64(6.0)) / theta5,
)
};
let c4 = (c3 - T::from_f64(3.0) * c5) * T::HALF;
let phph = ph * p * ph; let t2 = ph * p + p * ph + phph; let t3 = ph * ph * p + p * ph * ph - phph.scale(T::from_f64(3.0)); let t4 = ph * p * ph * ph + ph * ph * p * ph; p.scale(T::HALF) + t2.scale(c2) - t3.scale(c3) - t4.scale(c4)
}
#[inline]
pub(crate) fn left_jacobian_se3<T: Numeric>(xi: Vector<6, T>) -> Matrix<6, 6, T> {
let [rx, ry, rz, px, py, pz] = *xi.as_array();
let rho = Vector::new([rx, ry, rz]);
let phi = Vector::new([px, py, pz]);
let j = left_jacobian_so3(phi);
let q = q_matrix_se3(rho, phi);
Matrix::from_fn(|i, k| {
if i < 3 && k < 3 {
j[(i, k)]
} else if i < 3 {
q[(i, k - 3)]
} else if k >= 3 {
j[(i - 3, k - 3)]
} else {
T::ZERO
}
})
}
#[inline]
pub(crate) fn inverse_left_jacobian_se3<T: Numeric>(xi: Vector<6, T>) -> Matrix<6, 6, T> {
let [rx, ry, rz, px, py, pz] = *xi.as_array();
let rho = Vector::new([rx, ry, rz]);
let phi = Vector::new([px, py, pz]);
let ji = inverse_left_jacobian_so3(phi);
let q = q_matrix_se3(rho, phi);
let top_right = -(ji * q * ji);
Matrix::from_fn(|i, k| {
if i < 3 && k < 3 {
ji[(i, k)]
} else if i < 3 {
top_right[(i, k - 3)]
} else if k >= 3 {
ji[(i - 3, k - 3)]
} else {
T::ZERO
}
})
}