erfa_rust/
G8_safe.rs

1// G8
2//   c2tcio.c  → eraC2tcio_safe
3//   c2teqx.c  → eraC2teqx_safe
4//   c2tpe.c   → eraC2tpe_safe
5//   c2txy.c   → eraC2txy_safe
6//   cal2jd.c  → eraCal2jd_safe
7//   cp.c      → eraCp_safe
8//   cpv.c     → eraCpv_safe
9//   cr.c      → eraCr_safe
10
11use crate::H1_safe::ERFA_DJM0;
12
13use crate::G11_safe::eraEe00_safe;
14use crate::G14_safe::eraEra00_safe;
15use crate::G17_safe::eraGmst00_safe;
16use crate::G25_safe::eraPn00_safe;
17use crate::G26_safe::eraPom00_safe;
18use crate::G28_safe::{eraRxr_safe, eraRz_safe};
19use crate::G30_safe::eraSp00_safe;
20use crate::G7_safe::eraC2ixy_safe;
21
22pub type ErfaResult<T> = Result<T, ()>;
23
24//----------------------------------------------------------------------
25// G8/c2tcio.c → eraC2tcio_safe
26//----------------------------------------------------------------------
27
28// Form the celestial-to-terrestrial matrix given rc2i, ERA and polar motion.
29pub fn eraC2tcio_safe(
30    rc2i: &[[f64; 3]; 3],
31    era: f64,
32    rpom: &[[f64; 3]; 3],
33    rc2t: &mut [[f64; 3]; 3],
34) -> ErfaResult<()> {
35    // rc2t ← rc2i
36    eraCr_safe(rc2i, rc2t)?;
37
38    // rc2t ← Rz(era) * rc2t
39    eraRz_safe(era, rc2t)?;
40
41    // rc2t ← rpom * rc2t
42    let m = eraRxr_safe(rpom, rc2t)?;
43    eraCr_safe(&m, rc2t)
44}
45
46//----------------------------------------------------------------------
47// G8/c2teqx.c → eraC2teqx_safe
48//----------------------------------------------------------------------
49
50// Form celestial-to-terrestrial using equinox method: rbpn, GMST+EE, rpom.
51pub fn eraC2teqx_safe(
52    rbpn: &[[f64; 3]; 3],
53    gst: f64,
54    rpom: &[[f64; 3]; 3],
55    rc2t: &mut [[f64; 3]; 3],
56) -> ErfaResult<()> {
57    // rc2t ← rbpn
58    eraCr_safe(rbpn, rc2t)?;
59
60    // rc2t ← Rz(gst) * rc2t
61    eraRz_safe(gst, rc2t)?;
62
63    // rc2t ← rpom * rc2t
64    let m = eraRxr_safe(rpom, rc2t)?;
65    eraCr_safe(&m, rc2t)
66}
67
68//----------------------------------------------------------------------
69// G8/c2tpe.c → eraC2tpe_safe
70//----------------------------------------------------------------------
71
72// Full celestial-to-terrestrial, IAU 2000 equinox-based (dψ, dε given).
73pub fn eraC2tpe_safe(
74    tta: f64,
75    ttb: f64,
76    uta: f64,
77    utb: f64,
78    dpsi: f64,
79    deps: f64,
80    xp: f64,
81    yp: f64,
82    rc2t: &mut [[f64; 3]; 3],
83) -> ErfaResult<()> {
84    // Celestial-to-true matrix components for this TT.
85    let (epsa, _rb, _rp, _rbp, _rn, rbpn) = eraPn00_safe(tta, ttb, dpsi, deps)?;
86
87    // Greenwich Mean Sidereal Time.
88    let gmst = eraGmst00_safe(uta, utb, tta, ttb)?;
89
90    // Equation of the equinoxes.
91    let ee = eraEe00_safe(tta, ttb, epsa, dpsi)?;
92
93    // TIO locator s'.
94    let sp = eraSp00_safe(tta, ttb)?;
95
96    // Polar-motion matrix.
97    let rpom = eraPom00_safe(xp, yp, sp)?;
98
99    // Combine to form celestial-to-terrestrial.
100    eraC2teqx_safe(&rbpn, gmst + ee, &rpom, rc2t)
101}
102
103//----------------------------------------------------------------------
104// G8/c2txy.c → eraC2txy_safe
105//----------------------------------------------------------------------
106
107// Celestial-to-terrestrial using X,Y (CIP) method.
108pub fn eraC2txy_safe(
109    tta: f64,
110    ttb: f64,
111    uta: f64,
112    utb: f64,
113    x: f64,
114    y: f64,
115    xp: f64,
116    yp: f64,
117    rc2t: &mut [[f64; 3]; 3],
118) -> ErfaResult<()> {
119    // Celestial-to-intermediate matrix from X,Y.
120    let rc2i = eraC2ixy_safe(tta, ttb, x, y)?;
121
122    // Earth rotation angle and TIO locator.
123    let era = eraEra00_safe(uta, utb)?;
124    let sp = eraSp00_safe(tta, ttb)?;
125
126    // Polar-motion matrix.
127    let rpom = eraPom00_safe(xp, yp, sp)?;
128
129    // Combine to form celestial-to-terrestrial.
130    eraC2tcio_safe(&rc2i, era, &rpom, rc2t)
131}
132
133//----------------------------------------------------------------------
134// G8/cal2jd.c → eraCal2jd_safe
135//----------------------------------------------------------------------
136
137// Gregorian calendar to JD, split into (djm0, djm); j=0 OK, -1/-2/-3 for errors.
138pub fn eraCal2jd_safe(iy: i32, im: i32, id: i32) -> ErfaResult<((f64, f64), i32)> {
139    const IYMIN: i32 = -4799;
140    const MTAB: [i32; 12] = [31, 28, 31, 30, 31, 31, 30, 31, 30, 31, 30, 31];
141
142    // Validate year & month.
143    let mut j = 0;
144    if iy < IYMIN {
145        j = -1;
146    } else if im < 1 || im > 12 {
147        j = -2;
148    }
149
150    // Leap year test for February.
151    let ly = if im == 2 && (iy % 4 == 0) && (iy % 100 != 0 || iy % 400 == 0) {
152        1
153    } else {
154        0
155    };
156
157    // Validate day; for -3 we still compute JD per C behavior.
158    if j == 0 && (id < 1 || id > MTAB[(im - 1) as usize] + ly) {
159        j = -3;
160    }
161
162    // Compute JD parts (djm0, djm).
163    let (djm0, djm) = {
164        let my = (im - 14) / 12;
165        let iyp = (iy + my) as i64;
166
167        let djm0 = ERFA_DJM0;
168        let djm = (1461 * (iyp + 4800) / 4 + 367 * (im as i64 - 2 - 12 * my as i64) / 12
169            - 3 * ((iyp + 4900) / 100) / 4
170            + id as i64
171            - 2_432_076) as f64;
172        (djm0, djm)
173    };
174
175    Ok(((djm0, djm), j))
176}
177
178//----------------------------------------------------------------------
179// G8/cp.c → eraCp_safe
180//----------------------------------------------------------------------
181
182// Copy 3-vector.
183pub fn eraCp_safe(p: &[f64; 3], c: &mut [f64; 3]) -> ErfaResult<()> {
184    c[0] = p[0];
185    c[1] = p[1];
186    c[2] = p[2];
187    Ok(())
188}
189
190//----------------------------------------------------------------------
191// G8/cpv.c → eraCpv_safe
192//----------------------------------------------------------------------
193
194// Copy position/velocity 3+3-vector.
195pub fn eraCpv_safe(pv: &[[f64; 3]; 2], c: &mut [[f64; 3]; 2]) -> ErfaResult<()> {
196    c[0][0] = pv[0][0];
197    c[0][1] = pv[0][1];
198    c[0][2] = pv[0][2];
199    c[1][0] = pv[1][0];
200    c[1][1] = pv[1][1];
201    c[1][2] = pv[1][2];
202    Ok(())
203}
204
205//----------------------------------------------------------------------
206// G8/cr.c → eraCr_safe
207//----------------------------------------------------------------------
208
209// Copy 3×3 matrix.
210pub fn eraCr_safe(r: &[[f64; 3]; 3], c: &mut [[f64; 3]; 3]) -> ErfaResult<()> {
211    for i in 0..3 {
212        for j in 0..3 {
213            c[i][j] = r[i][j];
214        }
215    }
216    Ok(())
217}