use apex_manifolds::LieGroup;
use apex_manifolds::se3::SE3;
use faer::prelude::ReborrowMut;
use nalgebra::Vector3;
use crate::core::variable::ManifoldVariable;
use crate::factors::Factor;
use crate::factors::common::math::skew;
use crate::factors::common::validate::expect_block_sizes;
#[derive(Debug, Clone)]
pub struct PlanarMotionFactor {
height: f64,
}
impl PlanarMotionFactor {
pub fn new(height: f64) -> Self {
Self { height }
}
pub fn ground() -> Self {
Self::new(0.0)
}
}
impl Factor for PlanarMotionFactor {
fn linearize(
&self,
params: &[&[f64]],
residual: &mut [f64],
jacobian: Option<faer::mat::MatMut<'_, f64>>,
) {
let pose = SE3::from_param_slice(params[0]);
let rotation = pose.rotation_so3().rotation_matrix();
residual[0] = pose.translation().z - self.height;
residual[1] = rotation[(2, 0)]; residual[2] = rotation[(2, 1)];
let Some(mut jac) = jacobian else { return };
for row in 0..3 {
for col in 0..6 {
*jac.rb_mut().get_mut(row, col) = 0.0;
}
}
for col in 0..3 {
*jac.rb_mut().get_mut(0, col) = rotation[(2, col)];
}
let z_row = rotation.row(2).transpose(); for (row, axis) in [Vector3::x(), Vector3::y()].iter().enumerate() {
let d = -(z_row.transpose() * skew(axis));
for col in 0..3 {
*jac.rb_mut().get_mut(row + 1, 3 + col) = d[(0, col)];
}
}
}
fn residual_dim(&self) -> usize {
3
}
fn jacobian_shape(&self) -> (usize, usize) {
(3, 6)
}
fn validate_variables(&self, variables: &[&dyn ManifoldVariable]) -> Result<(), String> {
expect_block_sizes(
variables,
&[SE3::REP_SIZE],
"PlanarMotionFactor expects [SE3 pose]",
)
}
}