pub mod coordinates;
pub mod locator;
pub mod origins;
pub use coordinates::CipCoordinates;
pub use locator::CioLocator;
pub use origins::EquationOfOrigins;
use crate::errors::AstroResult;
use crate::matrix::RotationMatrix3;
pub fn gcrs_to_cirs_matrix(x: f64, y: f64, s: f64) -> RotationMatrix3 {
let r2 = x * x + y * y;
let e = if r2 > 0.0 { libm::atan2(y, x) } else { 0.0 };
let d = libm::atan(libm::sqrt(r2 / (1.0 - r2)));
let mut matrix = RotationMatrix3::identity();
matrix.rotate_z(e);
matrix.rotate_y(d);
matrix.rotate_z(-(e + s));
matrix
}
#[derive(Debug, Clone, PartialEq)]
pub struct CioSolution {
pub cip: CipCoordinates,
pub s: f64,
pub equation_of_origins: f64,
}
impl CioSolution {
pub fn calculate(
npb_matrix: &crate::matrix::RotationMatrix3,
tt_centuries: f64,
) -> AstroResult<Self> {
let cip = CipCoordinates::from_npb_matrix(npb_matrix)?;
let locator = CioLocator::iau2006a(tt_centuries);
let s = locator.calculate(cip.x, cip.y)?;
let equation_of_origins = EquationOfOrigins::from_npb_and_locator(npb_matrix, s)?;
Ok(Self {
cip,
s,
equation_of_origins,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cio_identity_matrix_returns_zero_components() {
let identity = crate::matrix::RotationMatrix3::identity();
let solution = CioSolution::calculate(&identity, 0.0).unwrap();
assert!(solution.cip.x.abs() < 1e-15);
assert!(solution.cip.y.abs() < 1e-15);
assert!(solution.s.abs() < 1e-8);
assert!(solution.equation_of_origins.abs() < 1e-8);
}
#[test]
fn gcrs_to_cirs_matrix_with_zero_inputs_returns_identity() {
let matrix = gcrs_to_cirs_matrix(0.0, 0.0, 0.0);
let identity = RotationMatrix3::identity();
assert!(matrix.max_difference(&identity) < 1e-15);
}
#[test]
fn gcrs_to_cirs_matrix_is_rotation_matrix() {
let matrix = gcrs_to_cirs_matrix(1e-6, 2e-6, 5e-9);
assert!(matrix.is_rotation_matrix(1e-14));
}
#[test]
fn gcrs_to_cirs_matrix_small_cip_produces_near_identity() {
let x = 1e-6;
let y = 1e-6;
let s = 1e-9;
let matrix = gcrs_to_cirs_matrix(x, y, s);
let identity = RotationMatrix3::identity();
assert!(matrix.max_difference(&identity) < 1e-5);
}
}