erfa_rust/
G17_safe.rs

1// G17
2//   g2icrs.c  → eraG2icrs_safe
3//   gc2gd.c   → eraGc2gd_safe
4//   gc2gde.c  → eraGc2gde_safe
5//   gd2gc.c   → eraGd2gc_safe
6//   gd2gce.c  → eraGd2gce_safe
7//   gmst00.c  → eraGmst00_safe
8//   gmst06.c  → eraGmst06_safe
9//   gmst82.c  → eraGmst82_safe
10//   gst00a.c  → eraGst00a_safe
11//   gst00b.c  → eraGst00b_safe
12//   gst06.c   → eraGst06_safe
13//   gst06a.c  → eraGst06a_safe
14//   gst94.c   → eraGst94_safe
15
16use crate::G11_safe::{eraEe00a_safe, eraEe00b_safe, eraEform_safe, eraEors_safe};
17use crate::G14_safe::{eraEqeq94_safe, eraEra00_safe};
18use crate::G1_safe::{eraAnp_safe, eraAnpm_safe};
19use crate::G26_safe::eraPnm06a_safe;
20use crate::G29_safe::eraS2c_safe;
21use crate::G30_safe::eraS06_safe;
22use crate::G33_safe::eraTrxp_safe;
23use crate::G6_safe::eraBpn2xy_safe;
24use crate::G7_safe::eraC2s_safe;
25use crate::H1_safe::{ERFA_DAS2R, ERFA_DAYSEC, ERFA_DJ00, ERFA_DJC, ERFA_DPI, ERFA_DS2R};
26
27pub type ErfaResult<T> = Result<T, ()>;
28
29//----------------------------------------------------------------------
30// G17/g2icrs.c → eraG2icrs_safe
31//----------------------------------------------------------------------
32// Convert Galactic (dl, db) to ICRS (dr, dd), radians.
33pub fn eraG2icrs_safe(dl: f64, db: f64) -> ErfaResult<(f64, f64)> {
34    // ICRS←Galactic rotation matrix (row-major)
35    const R: [[f64; 3]; 3] = [
36        [
37            -0.054_875_560_416_215_37,
38            -0.873_437_090_234_885_0,
39            -0.483_835_015_548_713_2,
40        ],
41        [
42            0.494_109_427_875_583_66,
43            -0.444_829_629_960_011_16,
44            0.746_982_244_497_218_9,
45        ],
46        [
47            -0.867_666_149_019_004_7,
48            -0.198_076_373_431_201_53,
49            0.455_983_776_175_066_9,
50        ],
51    ];
52
53    let v1 = eraS2c_safe(dl, db)?;
54    let v2 = eraTrxp_safe(&R, &v1)?;
55    let (mut dr, mut dd) = eraC2s_safe(&v2)?;
56    dr = eraAnp_safe(dr)?;
57    dd = eraAnpm_safe(dd)?;
58    Ok((dr, dd))
59}
60
61//----------------------------------------------------------------------
62// G17/gc2gd.c → eraGc2gd_safe
63//----------------------------------------------------------------------
64// Geocentric XYZ (m) to geodetic using ellipsoid selector n.
65pub fn eraGc2gd_safe(n: i32, xyz: &[f64; 3]) -> ErfaResult<(f64, f64, f64, i32)> {
66    let ((a, f), j_eform) = eraEform_safe(n)?;
67    let mut elong = 0.0_f64;
68    let mut phi = 0.0_f64;
69    let mut height = 0.0_f64;
70
71    let mut j = j_eform;
72    if j == 0 {
73        let (el, ph, h, j2) = eraGc2gde_safe(a, f, xyz)?;
74        elong = el;
75        phi = ph;
76        height = h;
77        if j2 < 0 {
78            j = -2;
79        }
80    }
81
82    if j < 0 {
83        elong = -1e9;
84        phi = -1e9;
85        height = -1e9;
86    }
87
88    Ok((elong, phi, height, j))
89}
90
91//----------------------------------------------------------------------
92// G17/gc2gde.c → eraGc2gde_safe
93//----------------------------------------------------------------------
94// Geocentric XYZ (m) to geodetic given ellipsoid (a,f).
95pub fn eraGc2gde_safe(a: f64, f: f64, xyz: &[f64; 3]) -> ErfaResult<(f64, f64, f64, i32)> {
96    if f < 0.0 || f >= 1.0 {
97        return Ok((0.0, 0.0, 0.0, -1));
98    }
99    if a <= 0.0 {
100        return Ok((0.0, 0.0, 0.0, -2));
101    }
102
103    let aeps2 = a * a * 1e-32;
104    let e2 = (2.0 - f) * f;
105    let e4t = e2 * e2 * 1.5;
106    let ec2 = 1.0 - e2;
107    if ec2 <= 0.0 {
108        return Ok((0.0, 0.0, 0.0, -1));
109    }
110    let ec = ec2.sqrt();
111    let b = a * ec;
112
113    let x = xyz[0];
114    let y = xyz[1];
115    let z = xyz[2];
116
117    let p2 = x * x + y * y;
118
119    let elong = if p2 > 0.0 { y.atan2(x) } else { 0.0 };
120
121    let absz = z.abs();
122
123    let (phi, height) = if p2 > aeps2 {
124        let p = p2.sqrt();
125        let s0 = absz / a;
126        let pn = p / a;
127        let zc = ec * s0;
128
129        let c0 = ec * pn;
130        let c02 = c0 * c0;
131        let c03 = c02 * c0;
132        let s02 = s0 * s0;
133        let s03 = s02 * s0;
134        let a02 = c02 + s02;
135        let a0 = a02.sqrt();
136        let a03 = a02 * a0;
137        let d0 = zc * a03 + e2 * s03;
138        let f0 = pn * a03 - e2 * c03;
139
140        let b0 = e4t * s02 * c02 * pn * (a0 - ec);
141        let s1 = d0 * f0 - b0 * s0;
142        let cc = ec * (f0 * f0 - b0 * c0);
143
144        let mut phi = (s1 / cc).atan();
145
146        let s12 = s1 * s1;
147        let cc2 = cc * cc;
148        let height = (p * cc + absz * s1 - a * (ec2 * s12 + cc2).sqrt()) / (s12 + cc2).sqrt();
149
150        if z < 0.0 {
151            phi = -phi;
152        }
153        (phi, height)
154    } else {
155        (ERFA_DPI / 2.0 * if z < 0.0 { -1.0 } else { 1.0 }, absz - b)
156    };
157
158    Ok((elong, phi, height, 0))
159}
160
161//----------------------------------------------------------------------
162// G17/gd2gc.c → eraGd2gc_safe
163//----------------------------------------------------------------------
164// Geodetic (elong, phi, height) to geocentric XYZ (m) using selector n.
165pub fn eraGd2gc_safe(n: i32, elong: f64, phi: f64, height: f64) -> ErfaResult<([f64; 3], i32)> {
166    let ((a, f), j_eform) = eraEform_safe(n)?;
167    let mut j = j_eform;
168    let mut xyz = [0.0_f64; 3];
169
170    if j == 0 {
171        let (out, j2) = eraGd2gce_safe(a, f, elong, phi, height)?;
172        xyz = out;
173        if j2 != 0 {
174            j = -2;
175        }
176    }
177
178    if j != 0 {
179        xyz = [0.0, 0.0, 0.0];
180    }
181    Ok((xyz, j))
182}
183
184//----------------------------------------------------------------------
185// G17/gd2gce.c → eraGd2gce_safe
186//----------------------------------------------------------------------
187// Geodetic (elong, phi, height) to geocentric XYZ (m) given (a,f).
188pub fn eraGd2gce_safe(
189    a: f64,
190    f: f64,
191    elong: f64,
192    phi: f64,
193    height: f64,
194) -> ErfaResult<([f64; 3], i32)> {
195    let sp = phi.sin();
196    let cp = phi.cos();
197    let mut w = 1.0 - f;
198    w *= w;
199    let d = cp * cp + w * sp * sp;
200    if d <= 0.0 {
201        return Ok(([0.0, 0.0, 0.0], -1));
202    }
203
204    let ac = a / d.sqrt();
205    let as_ = w * ac;
206
207    let r = (ac + height) * cp;
208    let x = r * elong.cos();
209    let y = r * elong.sin();
210    let z = (as_ + height) * sp;
211
212    Ok(([x, y, z], 0))
213}
214
215//----------------------------------------------------------------------
216// G17/gmst00.c → eraGmst00_safe
217//----------------------------------------------------------------------
218// GMST (IAU 2000), radians.
219pub fn eraGmst00_safe(uta: f64, utb: f64, tta: f64, ttb: f64) -> ErfaResult<f64> {
220    let t = ((tta - ERFA_DJ00) + ttb) / ERFA_DJC;
221    let gmst = eraAnp_safe(
222        eraEra00_safe(uta, utb)?
223            + (0.014_506
224                + (4612.157_399_66 + (1.396_677_21 + (-0.000_093_44 + 0.000_018_82 * t) * t) * t)
225                    * t)
226                * ERFA_DAS2R,
227    )?;
228    Ok(gmst)
229}
230
231//----------------------------------------------------------------------
232// G17/gmst06.c → eraGmst06_safe
233//----------------------------------------------------------------------
234// GMST (IAU 2006), radians.
235pub fn eraGmst06_safe(uta: f64, utb: f64, tta: f64, ttb: f64) -> ErfaResult<f64> {
236    let t = ((tta - ERFA_DJ00) + ttb) / ERFA_DJC;
237    let gmst = eraAnp_safe(
238        eraEra00_safe(uta, utb)?
239            + (0.014_506
240                + (4612.156_534
241                    + (1.391_581_7
242                        + (-0.000_000_44 + (-0.000_029_956 + (-0.000_000_036_8) * t) * t) * t)
243                        * t)
244                    * t)
245                * ERFA_DAS2R,
246    )?;
247    Ok(gmst)
248}
249
250//----------------------------------------------------------------------
251// G17/gmst82.c → eraGmst82_safe
252//----------------------------------------------------------------------
253// GMST (IAU 1982), radians.
254pub fn eraGmst82_safe(dj1: f64, dj2: f64) -> ErfaResult<f64> {
255    const A: f64 = 24_110.548_41 - ERFA_DAYSEC / 2.0;
256    const B: f64 = 8_640_184.812_866;
257    const C: f64 = 0.093_104;
258    const D: f64 = -6.2e-6;
259
260    let (d1, d2) = if dj1 < dj2 { (dj1, dj2) } else { (dj2, dj1) };
261    let t = (d1 + (d2 - ERFA_DJ00)) / ERFA_DJC;
262
263    let f = ERFA_DAYSEC * (d1.fract() + d2.fract());
264
265    let gmst = eraAnp_safe(ERFA_DS2R * (A + (B + (C + D * t) * t) * t + f))?;
266    Ok(gmst)
267}
268
269//----------------------------------------------------------------------
270// G17/gst00a.c → eraGst00a_safe
271//----------------------------------------------------------------------
272// GAST (IAU 2000A), radians.
273pub fn eraGst00a_safe(uta: f64, utb: f64, tta: f64, ttb: f64) -> ErfaResult<f64> {
274    let gmst00 = eraGmst00_safe(uta, utb, tta, ttb)?;
275    let ee00a = eraEe00a_safe(tta, ttb)?;
276    eraAnp_safe(gmst00 + ee00a)
277}
278
279//----------------------------------------------------------------------
280// G17/gst00b.c → eraGst00b_safe
281//----------------------------------------------------------------------
282// GAST (IAU 2000B), radians.
283pub fn eraGst00b_safe(uta: f64, utb: f64) -> ErfaResult<f64> {
284    let gmst00 = eraGmst00_safe(uta, utb, uta, utb)?; // TT from UT
285    let ee00b = eraEe00b_safe(uta, utb)?;
286    eraAnp_safe(gmst00 + ee00b)
287}
288
289//----------------------------------------------------------------------
290// G17/gst06.c → eraGst06_safe
291//----------------------------------------------------------------------
292// GAST (IAU 2006), radians, given NPB matrix.
293pub fn eraGst06_safe(
294    uta: f64,
295    utb: f64,
296    tta: f64,
297    ttb: f64,
298    rnpb: &[[f64; 3]; 3],
299) -> ErfaResult<f64> {
300    let (x, y) = eraBpn2xy_safe(rnpb)?;
301    let s = eraS06_safe(tta, ttb, x, y)?;
302    let era = eraEra00_safe(uta, utb)?;
303    let eors = eraEors_safe(rnpb, s)?;
304    eraAnp_safe(era - eors)
305}
306
307//----------------------------------------------------------------------
308// G17/gst06a.c → eraGst06a_safe
309//----------------------------------------------------------------------
310// GAST (IAU 2006/2000A), radians.
311pub fn eraGst06a_safe(uta: f64, utb: f64, tta: f64, ttb: f64) -> ErfaResult<f64> {
312    let rnpb = eraPnm06a_safe(tta, ttb)?;
313    eraGst06_safe(uta, utb, tta, ttb, &rnpb)
314}
315
316//----------------------------------------------------------------------
317// G17/gst94.c → eraGst94_safe
318//----------------------------------------------------------------------
319// GAST (IAU 1982/94), radians.
320pub fn eraGst94_safe(uta: f64, utb: f64) -> ErfaResult<f64> {
321    let gmst82 = eraGmst82_safe(uta, utb)?;
322    let eqeq94 = eraEqeq94_safe(uta, utb)?;
323    eraAnp_safe(gmst82 + eqeq94)
324}