use crate::linear_algebra::Vector3D;
use crate::scalar::Numeric;
use crate::spatial::SO3;
pub struct ExponentialMap;
impl ExponentialMap {
#[inline]
#[must_use]
pub fn attitude_step<T: Numeric>(
orientation: SO3<T>,
angular_rate: Vector3D<T>,
dt: T,
) -> SO3<T> {
orientation * SO3::exp(angular_rate * dt)
}
#[inline]
#[must_use]
pub fn attitude_step_with_angular_acceleration<T: Numeric>(
orientation: SO3<T>,
angular_rate: Vector3D<T>,
angular_acceleration: Vector3D<T>,
dt: T,
) -> SO3<T> {
let half_way_rate = angular_rate + angular_acceleration * (dt * T::HALF);
orientation * SO3::exp(half_way_rate * dt)
}
#[must_use]
pub fn integrate_attitude<T, F, O>(
angular_rate_at: &F,
t0: T,
start_orientation: SO3<T>,
dt: T,
steps: usize,
mut observer: O,
) -> SO3<T>
where
T: Numeric,
F: Fn(T, SO3<T>) -> Vector3D<T>,
O: FnMut(T, SO3<T>),
{
let half = dt * T::HALF;
let mut time = t0;
let mut orientation = start_orientation;
observer(time, orientation);
for _ in 0..steps {
let rate_at_start = angular_rate_at(time, orientation);
let half_way = Self::attitude_step(orientation, rate_at_start, half);
let half_way_rate = angular_rate_at(time + half, half_way);
orientation = Self::attitude_step(orientation, half_way_rate, dt);
time += dt;
observer(time, orientation);
}
orientation
}
}