use crate::astro::cio;
use crate::astro::earth_rotation::jd_ut1_from_tt_eop;
use crate::astro::eop::{EopProvider, EopValues};
use crate::astro::era::earth_rotation_angle;
use crate::astro::nutation::nutation_iau2000b;
use crate::astro::polar_motion::polar_motion_matrix_from_eop;
use crate::coordinates::frames::{EquatorialMeanJ2000, ICRS};
use crate::coordinates::transform::context::AstroContext;
use crate::coordinates::transform::providers::FrameRotationProvider;
use crate::time::JulianDate;
#[inline]
pub(crate) fn nutation_with_celestial_pole_offsets(
jd: JulianDate,
eop: EopValues,
) -> (qtty::Radians, qtty::Radians) {
let nut = nutation_iau2000b(jd);
let mut dpsi = nut.dpsi;
let mut deps = nut.deps;
let dx_rad = qtty::Radians::from(eop.dx);
let dy_rad = qtty::Radians::from(eop.dy);
let zero = qtty::Radians::new(0.0);
if dx_rad != zero || dy_rad != zero {
let sin_eps = nut.mean_obliquity.sin();
if sin_eps.abs() > 1e-15 {
dpsi += dx_rad / sin_eps;
}
deps += dy_rad;
}
(dpsi, deps)
}
pub(crate) fn itrs_to_equatorial_mean_j2000_rotation<Eph, Eop: EopProvider, Nut>(
jd: JulianDate,
ctx: &AstroContext<Eph, Eop, Nut>,
) -> affn::Rotation3 {
let eop = ctx.eop_at(jd);
let jd_ut1 = jd_ut1_from_tt_eop(jd, &eop);
let (dpsi, deps) = nutation_with_celestial_pole_offsets(jd, eop);
let cip = cio::cip_cio(jd, dpsi, deps);
let q = cio::gcrs_to_cirs_matrix(cip.x, cip.y, cip.s);
let w = polar_motion_matrix_from_eop(eop.xp, eop.yp, jd);
let era = earth_rotation_angle(jd_ut1);
let itrs_to_gcrs = q * affn::Rotation3::rz(-era) * w.inverse();
let icrs_to_j2000 = <() as FrameRotationProvider<ICRS, EquatorialMeanJ2000>>::rotation(jd, ctx);
icrs_to_j2000 * itrs_to_gcrs
}