use crate::formats::tle::TLE;
use chrono::Datelike;
use super::Sgp4Error;
#[derive(Clone, Debug)]
pub(crate) struct NativeElements {
pub(crate) epoch_jd_utc: tempoch::JulianDate<tempoch::UTC>,
pub(crate) inclination_rad: f64,
pub(crate) raan_rad: f64,
pub(crate) eccentricity: f64,
pub(crate) argument_of_perigee_rad: f64,
pub(crate) mean_anomaly_rad: f64,
pub(crate) mean_motion_rev_per_day: f64,
pub(crate) mean_motion_dot_rev_per_day2: f64,
pub(crate) mean_motion_ddot_rev_per_day3: f64,
pub(crate) bstar: f64,
}
pub(crate) fn tle_to_elements(tle: &TLE) -> Result<NativeElements, Sgp4Error> {
let dt_utc = tle
.epoch
.try_to_chrono()
.map_err(|e| Sgp4Error::TimeConversion(format!("TLE epoch → chrono failed: {e:?}")))?;
let datetime = dt_utc.naive_utc();
if datetime.year() < 1950 {
return Err(Sgp4Error::InvalidEpoch("year < 1950 not representable"));
}
if !tle.eccentricity.is_finite() || !(0.0..1.0).contains(&tle.eccentricity) {
return Err(Sgp4Error::InvalidElements {
details: format!("eccentricity outside [0, 1): {}", tle.eccentricity),
});
}
if !tle.mean_motion.value().is_finite() || tle.mean_motion.value() <= 0.0 {
return Err(Sgp4Error::InvalidElements {
details: format!("non-positive mean motion: {}", tle.mean_motion.value()),
});
}
Ok(NativeElements {
epoch_jd_utc: tle.epoch.to::<tempoch::JD>(),
inclination_rad: tle.inclination.value().to_radians(),
raan_rad: tle.raan.value().to_radians(),
eccentricity: tle.eccentricity,
argument_of_perigee_rad: tle.argument_of_perigee.value().to_radians(),
mean_anomaly_rad: tle.mean_anomaly.value().to_radians(),
mean_motion_rev_per_day: tle.mean_motion.value(),
mean_motion_dot_rev_per_day2: tle.mean_motion_dot,
mean_motion_ddot_rev_per_day3: tle.mean_motion_ddot,
bstar: tle.bstar,
})
}