use crate::math::Matrix6;
use core::fmt;
use nalgebra::SymmetricEigen;
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "anise.astro"))]
pub enum LocalFrame {
Inertial,
RIC,
VNC,
RCN,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "anise.astro"))]
pub struct Covariance {
pub matrix: Matrix6,
pub local_frame: LocalFrame,
}
impl fmt::Display for Covariance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Covariance in {:?}", self.local_frame)?;
write!(f, "{:.6}", self.matrix)
}
}
fn matrix_log_spd(mat: Matrix6) -> Option<Matrix6> {
let decomp = SymmetricEigen::new(mat);
if decomp.eigenvalues.iter().any(|&e| e <= 0.0) {
return None;
}
let log_eigenvalues = decomp.eigenvalues.map(|e| e.ln());
let log_diag = Matrix6::from_diagonal(&log_eigenvalues);
Some(decomp.eigenvectors * log_diag * decomp.eigenvectors.transpose())
}
pub(crate) fn interpolate_covar_log_euclidean(
covar0: Matrix6,
covar1: Matrix6,
alpha: f64,
) -> Option<Matrix6> {
let log_p0 = matrix_log_spd(covar0)?;
let log_p1 = matrix_log_spd(covar1)?;
let log_interp = log_p0 * (1.0 - alpha) + log_p1 * alpha;
matrix_exp_symmetric(log_interp)
}
fn matrix_exp_symmetric(mat: Matrix6) -> Option<Matrix6> {
let decomp = SymmetricEigen::new(mat);
let exp_eigenvalues = decomp.eigenvalues.map(|e| e.exp());
let exp_diag = Matrix6::from_diagonal(&exp_eigenvalues);
Some(decomp.eigenvectors * exp_diag * decomp.eigenvectors.transpose())
}