use crate::constats::{DAYS_PER_JC, J2000_JD_TT, JD_MINUS_MJD, UNIX_EPOCH_JD, UNIX_EPOCH_MJD};
use affn::algebra::{AffineMap1, Point1, Space};
use qtty::unit::{Day as DayUnit, Second as SecondUnit};
use qtty::{Day, Second};
#[derive(Debug, Copy, Clone)]
struct SourceDayAxis;
impl Space for SourceDayAxis {}
#[derive(Debug, Copy, Clone)]
struct TargetDayAxis;
impl Space for TargetDayAxis {}
#[inline]
fn affine_day_coordinate(source: Day, source_origin: Day, target_origin: Day) -> Day {
let map =
AffineMap1::<SourceDayAxis, TargetDayAxis, DayUnit>::new(source_origin, target_origin, 1.0);
map.apply_point(Point1::<SourceDayAxis, DayUnit>::new(source))
.x()
}
#[inline]
pub(crate) fn jd_to_j2000_seconds(jd: Day) -> Second {
affine_day_coordinate(jd, J2000_JD_TT, Day::new(0.0)).to::<SecondUnit>()
}
#[inline]
pub(crate) fn j2000_seconds_to_jd(seconds: Second) -> Day {
affine_day_coordinate(seconds.to::<DayUnit>(), Day::new(0.0), J2000_JD_TT)
}
#[inline]
pub(crate) fn mjd_to_j2000_seconds(mjd: Day) -> Second {
affine_day_coordinate(mjd, J2000_JD_TT - JD_MINUS_MJD, Day::new(0.0)).to::<SecondUnit>()
}
#[inline]
pub(crate) fn j2000_seconds_to_mjd(seconds: Second) -> Day {
affine_day_coordinate(
seconds.to::<DayUnit>(),
Day::new(0.0),
J2000_JD_TT - JD_MINUS_MJD,
)
}
#[inline]
pub(crate) fn jd_to_mjd(jd: Day) -> Day {
jd - JD_MINUS_MJD
}
#[inline]
pub(crate) fn jd_to_julian_centuries(jd: Day) -> f64 {
(jd - J2000_JD_TT) / DAYS_PER_JC
}
#[inline]
pub(crate) fn mjd_to_unix_seconds(mjd: Day) -> Second {
(mjd - UNIX_EPOCH_MJD).to::<SecondUnit>()
}
#[inline]
pub(crate) fn unix_seconds_to_mjd(seconds: Second) -> Day {
UNIX_EPOCH_MJD + seconds.to::<DayUnit>()
}
#[inline]
pub(crate) fn unix_seconds_to_jd(seconds: Second) -> Day {
UNIX_EPOCH_JD + seconds.to::<DayUnit>()
}
#[cfg(test)]
mod tests {
use super::*;
const EPS_S: Second = Second::new(1e-9);
const EPS_D: Day = Day::new(1e-15);
#[test]
fn jd_j2000_round_trip() {
let jd = Day::new(2_451_545.5);
let secs = jd_to_j2000_seconds(jd);
let back = j2000_seconds_to_jd(secs);
assert!((back - jd).abs() < EPS_D);
}
#[test]
fn mjd_j2000_round_trip() {
let mjd = Day::new(51_544.5);
let secs = mjd_to_j2000_seconds(mjd);
let back = j2000_seconds_to_mjd(secs);
assert!((back - mjd).abs() < EPS_D);
}
#[test]
fn j2000_epoch_is_zero_seconds() {
let secs = jd_to_j2000_seconds(J2000_JD_TT);
assert!(secs.abs() < EPS_S);
}
#[test]
fn julian_centuries_one_century() {
let jd = J2000_JD_TT + DAYS_PER_JC;
let t = jd_to_julian_centuries(jd);
assert!((t - 1.0).abs() < 1e-12);
}
#[test]
fn unix_mjd_round_trip() {
let mjd = Day::new(40_587.0); let secs = mjd_to_unix_seconds(mjd);
assert!(secs.abs() < EPS_S);
let back = unix_seconds_to_mjd(secs);
assert!((back - mjd).abs() < EPS_D);
}
}