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, Matrix3D, Matrix6D, Vector, Vector3D, Vector6D};
use crate::scalar::Numeric;
use crate::spatial::{small_angle_inverse_so3_sq, small_angle_se3_sq, small_angle_so3_sq};
#[inline]
pub(crate) fn skew3<T: Numeric>(v: Vector3D<T>) -> Matrix3D<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: Vector3D<T>) -> Matrix3D<T> {
let theta_sq = phi.dot(phi);
let s = skew3(phi);
let s2 = s * s;
let (t1, t2) = small_angle_so3_sq::<T>();
let theta = theta_sq.sqrt();
let c1 = if theta_sq < t1 {
T::HALF - theta_sq / T::from_f64(24.0)
} else {
(T::ONE - theta.cos()) / theta_sq
};
let c2 = if theta_sq < t2 {
T::ONE / T::from_f64(6.0) - theta_sq / T::from_f64(120.0)
} else {
(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: Vector3D<T>) -> Matrix3D<T> {
let theta_sq = phi.dot(phi);
let s = skew3(phi);
let s2 = s * s;
let c3 = if theta_sq < small_angle_inverse_so3_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: Vector3D<T>, phi: Vector3D<T>) -> Matrix3D<T> {
let theta_sq = phi.dot(phi);
let p = skew3(rho);
let ph = skew3(phi);
let (t_c2, t_c3, t_c5) = small_angle_se3_sq::<T>();
let theta = theta_sq.sqrt();
let theta3 = theta_sq * theta;
let theta4 = theta_sq * theta_sq;
let theta5 = theta4 * theta;
let c2 = if theta_sq < t_c2 {
T::ONE / T::from_f64(6.0) - theta_sq / T::from_f64(120.0)
} else {
(theta - theta.sin()) / theta3
};
let c3 = if theta_sq < t_c3 {
-T::ONE / T::from_f64(24.0) + theta_sq / T::from_f64(720.0)
} else {
(T::ONE - theta_sq * T::HALF - theta.cos()) / theta4
};
let c5 = if theta_sq < t_c5 {
-T::ONE / T::from_f64(120.0) + theta_sq / T::from_f64(5040.0)
} else {
(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: Vector6D<T>) -> Matrix6D<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: Vector6D<T>) -> Matrix6D<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
}
})
}