use apex_manifolds::LieGroup;
use apex_manifolds::Tangent;
use apex_manifolds::se3::{SE3, SE3Tangent};
use nalgebra::{DMatrix, DVector, UnitQuaternion};
use crate::factors::Factor;
pub(crate) fn assert_close(analytical: f64, fd: f64, tol: f64, label: &str) {
let err = (analytical - fd).abs();
assert!(
err < tol,
"{label}: analytical={analytical:.8} fd={fd:.8} err={err:.2e}"
);
}
pub(crate) fn make_pose(tx: f64, ty: f64, tz: f64, q: UnitQuaternion<f64>) -> DVector<f64> {
let q = q.quaternion();
DVector::from_vec(vec![tx, ty, tz, q.w, q.i, q.j, q.k])
}
pub(crate) fn identity_pose() -> DVector<f64> {
DVector::from_vec(vec![0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0])
}
pub(crate) fn perturb_se3(pose: &[f64], tangent: &[f64; 6]) -> DVector<f64> {
let se3 = SE3::from_param_slice(pose);
let tan = SE3Tangent::from_slice(tangent);
DVector::from_column_slice(se3.right_plus(&tan, None, None).as_param_slice())
}
pub(crate) fn compute_residual<F: Factor>(factor: &F, t_wa: &[f64], t_wb: &[f64]) -> Vec<f64> {
let mut residual = vec![0.0f64; factor.residual_dim()];
factor.linearize(&[t_wa, t_wb], &mut residual, None);
residual
}
pub(crate) fn compute_with_jacobian<F: Factor>(
factor: &F,
t_wa: &[f64],
t_wb: &[f64],
) -> (Vec<f64>, DMatrix<f64>) {
let (rows, cols) = factor.jacobian_shape();
let mut residual = vec![0.0f64; rows];
let mut jac_buf = vec![0.0f64; rows * cols];
let jac_mut = faer::mat::MatMut::from_column_major_slice_mut(&mut jac_buf, rows, cols);
factor.linearize(&[t_wa, t_wb], &mut residual, Some(jac_mut));
let jacobian = DMatrix::from_column_slice(rows, cols, &jac_buf);
(residual, jacobian)
}