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}