use crate::format::{TimeFormat, JD, MJD};
use crate::foundation::constats::{J2000_JD_TT_DAY, JD_MINUS_MJD};
use crate::qtty::{self, Day, Second};
use affn::algebra::{AffineMap1, Point1, Space};
pub(crate) trait DayEncoding: TimeFormat<Unit = qtty::unit::Day> {
fn j2000_origin() -> Day;
}
impl DayEncoding for JD {
fn j2000_origin() -> Day {
J2000_JD_TT_DAY
}
}
impl DayEncoding for MJD {
fn j2000_origin() -> Day {
J2000_JD_TT_DAY - JD_MINUS_MJD
}
}
#[derive(Debug, Copy, Clone)]
struct SourceDayAxis;
impl Space for SourceDayAxis {}
#[derive(Debug, Copy, Clone)]
struct TargetDayAxis;
impl Space for TargetDayAxis {}
#[inline]
pub(crate) fn affine_day_coordinate(source: Day, source_origin: Day, target_origin: Day) -> Day {
let map = AffineMap1::<SourceDayAxis, TargetDayAxis, qtty::unit::Day>::new(
source_origin,
target_origin,
1.0,
);
map.apply_point(Point1::<SourceDayAxis, qtty::unit::Day>::new(source))
.x()
}
#[inline]
pub(crate) fn day_to_j2000_seconds<F: DayEncoding>(day: Day) -> Second {
affine_day_coordinate(day, F::j2000_origin(), Day::new(0.0)).to::<qtty::unit::Second>()
}
#[inline]
pub(crate) fn j2000_seconds_to_day<F: DayEncoding>(seconds: Second) -> Day {
affine_day_coordinate(
seconds.to::<qtty::unit::Day>(),
Day::new(0.0),
F::j2000_origin(),
)
}
mod jd;
mod mjd;
pub(crate) use jd::jd_to_julian_centuries;
pub(crate) use mjd::{jd_to_mjd, mjd_to_unix_seconds, unix_seconds_to_jd, unix_seconds_to_mjd};
#[cfg(test)]
mod tests {
use super::*;
use crate::foundation::constats::J2000_JD_TT_DAY;
use crate::qtty::Second;
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 = day_to_j2000_seconds::<JD>(jd);
let back = j2000_seconds_to_day::<JD>(secs);
assert!((back - jd).abs() < EPS_D);
}
#[test]
fn mjd_j2000_round_trip() {
let mjd = Day::new(51_544.5);
let secs = day_to_j2000_seconds::<MJD>(mjd);
let back = j2000_seconds_to_day::<MJD>(secs);
assert!((back - mjd).abs() < EPS_D);
}
#[test]
fn j2000_epoch_is_zero_seconds() {
let secs = day_to_j2000_seconds::<JD>(J2000_JD_TT_DAY);
assert!(secs.abs() < EPS_S);
}
#[test]
fn julian_centuries_one_century() {
let jd = J2000_JD_TT_DAY + crate::qtty::time::JULIAN_CENTURY.to::<crate::qtty::unit::Day>();
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);
}
}