use crate::time::JulianDate;
use affn::Rotation3;
use qtty::*;
#[inline]
pub fn tio_locator_sp(jd_tt: JulianDate) -> Radians {
let t = jd_tt.julian_centuries().value();
MicroArcseconds::new(-47.0 * t).to::<Radian>()
}
pub fn polar_motion_matrix(xp: Radians, yp: Radians, sp: Radians) -> Rotation3 {
Rotation3::rz(-sp) * Rotation3::ry(xp) * Rotation3::rx(yp)
}
#[inline]
pub fn polar_motion_matrix_from_eop(
xp: Arcseconds,
yp: Arcseconds,
jd_tt: JulianDate,
) -> Rotation3 {
let sp = tio_locator_sp(jd_tt);
polar_motion_matrix(xp.to::<Radian>(), yp.to::<Radian>(), sp)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tio_locator_at_j2000_is_zero() {
let sp = tio_locator_sp(JulianDate::J2000);
assert!(
sp.value().abs() < 1e-15,
"s' at J2000 should be ~0, got {}",
sp
);
}
#[test]
fn tio_locator_is_small() {
let jd = JulianDate::new(2_460_000.5); let sp = tio_locator_sp(jd);
let sp_uas = sp.to::<MicroArcsecond>().value();
assert!(
sp_uas.abs() < 50.0,
"s' should be ~12 μas, got {} μas",
sp_uas
);
}
#[test]
fn polar_motion_identity_with_zero_poles() {
let zero = Radians::new(0.0);
let w = polar_motion_matrix(zero, zero, zero);
let m = w.as_matrix();
for (i, row) in m.iter().enumerate().take(3) {
assert!(
(row[i] - 1.0).abs() < 1e-15,
"W[{}][{}] = {}, expected 1",
i,
i,
row[i]
);
}
}
#[test]
fn polar_motion_is_proper_rotation() {
let xp = Arcseconds::new(0.1).to::<Radian>();
let yp = Arcseconds::new(0.3).to::<Radian>();
let sp = Radians::new(-1e-9);
let w = polar_motion_matrix(xp, yp, sp);
let m = w.as_matrix();
let det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
assert!((det - 1.0).abs() < 1e-14, "det(W) = {}, expected ≈ 1", det);
}
#[test]
fn polar_motion_small_angles() {
let w = polar_motion_matrix_from_eop(
Arcseconds::new(0.3),
Arcseconds::new(0.2),
JulianDate::new(2_460_000.5),
);
let m = w.as_matrix();
for (i, row) in m.iter().enumerate().take(3) {
assert!(
(row[i] - 1.0).abs() < 1e-10,
"W[{}][{}] = {}, should be ≈ 1 for small poles",
i,
i,
row[i]
);
}
}
}