use hifitime::Epoch;
use log::warn;
use snafu::ensure;
use super::{EphemerisError, NoEphemerisLoadedSnafu};
use crate::almanac::Almanac;
use crate::frames::Frame;
use crate::naif::daf::{DAFError, NAIFSummaryRecord};
use crate::NaifId;
pub const MAX_TREE_DEPTH: usize = 8;
impl Almanac {
pub fn try_find_ephemeris_root(&self) -> Result<NaifId, EphemerisError> {
ensure!(self.num_loaded_spk() > 0, NoEphemerisLoadedSnafu);
let mut common_center = i32::MAX;
for spk in self.spk_data.values().rev() {
for block_result in spk.iter_summary_blocks() {
let these_summaries = match block_result {
Ok(s) => s,
Err(e) => {
warn!("DAF/SPK is corrupted: {e}");
continue;
}
};
for summary in these_summaries {
if !summary.is_empty() && summary.center_id.abs() < common_center.abs() {
common_center = summary.center_id;
if common_center == 0 {
return Ok(common_center);
}
}
}
}
}
Ok(common_center)
}
pub fn ephemeris_path_to_root(
&self,
source: Frame,
epoch: Epoch,
) -> Result<(usize, [Option<NaifId>; MAX_TREE_DEPTH]), EphemerisError> {
let common_center = self.try_find_ephemeris_root()?;
let mut of_path = [None; MAX_TREE_DEPTH];
let mut of_path_len = 0;
if common_center == source.ephemeris_id {
return Ok((of_path_len, of_path));
}
let summary = self.spk_summary_at_epoch(source.ephemeris_id, epoch)?.0;
let mut center_id = summary.center_id;
of_path[of_path_len] = Some(summary.center_id);
of_path_len += 1;
if summary.center_id == common_center {
return Ok((of_path_len, of_path));
}
for _ in 0..MAX_TREE_DEPTH {
let summary = self.spk_summary_at_epoch(center_id, epoch)?.0;
center_id = summary.center_id;
of_path[of_path_len] = Some(center_id);
of_path_len += 1;
if center_id == common_center {
return Ok((of_path_len, of_path));
}
}
Err(EphemerisError::SPK {
action: "computing path to common node",
source: DAFError::MaxRecursionDepth,
})
}
pub fn common_ephemeris_path(
&self,
from_frame: Frame,
to_frame: Frame,
epoch: Epoch,
) -> Result<(usize, [Option<NaifId>; MAX_TREE_DEPTH], NaifId), EphemerisError> {
if from_frame == to_frame {
return Ok((0, [None; MAX_TREE_DEPTH], from_frame.ephemeris_id));
}
let (from_len, from_path) = self.ephemeris_path_to_root(from_frame, epoch)?;
let (to_len, to_path) = self.ephemeris_path_to_root(to_frame, epoch)?;
if from_len == 0 && to_len == 0 {
Err(EphemerisError::TranslationOrigin {
from: from_frame.into(),
to: to_frame.into(),
epoch,
})
} else if from_len != 0 && to_len == 0 {
Ok((from_len, from_path, to_frame.ephemeris_id))
} else if to_len != 0 && from_len == 0 {
Ok((to_len, to_path, from_frame.ephemeris_id))
} else {
let mut common_path = [None; MAX_TREE_DEPTH];
let mut items: usize = 0;
for to_obj in to_path.iter().take(to_len) {
if to_obj.unwrap() == from_frame.ephemeris_id {
common_path[0] = Some(from_frame.ephemeris_id);
items = 1;
return Ok((items, common_path, from_frame.ephemeris_id));
}
for from_obj in from_path.iter().take(from_len) {
if items == 0 && from_obj.unwrap() == to_frame.ephemeris_id {
common_path[0] = Some(to_frame.ephemeris_id);
items = 1;
return Ok((items, common_path, to_frame.ephemeris_id));
}
common_path[items] = Some(from_obj.unwrap());
items += 1;
if from_obj == to_obj {
return Ok((items, common_path, to_obj.unwrap()));
}
}
}
Err(EphemerisError::Unreachable)
}
}
}