use nalgebra::{
AbstractRotation, Isometry, Point, RealField, SMatrix, UnitComplex, UnitQuaternion,
};
use crate::{marker::PhantomData, utils::verify_rotation_matrix_determinant};
pub struct IsometryAbstractor<T: RealField, const N: usize> {
_precision: PhantomData<T>,
}
pub trait AbstractIsometry<T: RealField, const N: usize> {
type RotType: AbstractRotation<T, N> + Copy;
fn update_transform(
old_transform: &Isometry<T, Self::RotType, N>,
mean_a: Point<T, N>,
mean_b: Point<T, N>,
rot_mat: &SMatrix<T, N, N>,
) -> Isometry<T, Self::RotType, N>;
}
impl<T> AbstractIsometry<T, 2> for IsometryAbstractor<T, 2>
where
T: Copy + RealField,
{
type RotType = UnitComplex<T>;
#[cfg_attr(
feature = "tracing",
tracing::instrument("Update 2D Transform Using SVD", skip_all, level = "debug")
)]
fn update_transform(
old_transform: &Isometry<T, Self::RotType, 2>,
mean_a: Point<T, 2>,
mean_b: Point<T, 2>,
rot_mat: &SMatrix<T, 2, 2>,
) -> Isometry<T, Self::RotType, 2> {
let svd = rot_mat.svd(true, true);
let rotation = verify_rotation_matrix_determinant(svd.u.unwrap(), svd.v_t.unwrap());
let translation = mean_b.coords - (rotation * mean_a.coords);
Isometry::from_parts(translation.into(), Self::RotType::from_matrix(&rotation))
* old_transform
}
}
impl<T> AbstractIsometry<T, 3> for IsometryAbstractor<T, 3>
where
T: Copy + RealField,
{
type RotType = UnitQuaternion<T>;
#[cfg_attr(
feature = "tracing",
tracing::instrument("Update 3D Transform Using SVD", skip_all, level = "debug")
)]
fn update_transform(
old_transform: &Isometry<T, Self::RotType, 3>,
mean_a: Point<T, 3>,
mean_b: Point<T, 3>,
rot_mat: &SMatrix<T, 3, 3>,
) -> Isometry<T, Self::RotType, 3> {
let svd = rot_mat.svd(true, true);
let rotation = verify_rotation_matrix_determinant(svd.u.unwrap(), svd.v_t.unwrap());
let translation = mean_b.coords - (rotation * mean_a.coords);
Isometry::from_parts(translation.into(), Self::RotType::from_matrix(&rotation))
* old_transform
}
}