Coverage Report

Created: 2026-09-04 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/sofars-0.6.1/src/astro/atoiq.rs
Line
Count
Source
1
use crate::vm::{anp, c2s, s2c};
2
3
use super::IauAstrom;
4
5
///  Quick observed −> CIRS
6
///
7
///  Quick observed place to CIRS, given the star-independent astrometry
8
///  parameters.
9
///
10
///  Use of this function is appropriate when efficiency is important and
11
///  where many star positions are all to be transformed for one date.
12
///  The star-independent astrometry parameters can be obtained by
13
///  calling iauApio[13] or iauApco[13].
14
///
15
///  This function is part of the International Astronomical Union's
16
///  SOFA (Standards of Fundamental Astronomy) software collection.
17
///
18
///  Status:  support function.
19
///
20
///  Given:
21
///  ```
22
///     type   char[]     type of coordinates: "R", "H" or "A" (Note 1)
23
///     ob1    double     observed Az, HA or RA (radians; Az is N=0,E=90)
24
///     ob2    double     observed ZD or Dec (radians)
25
///     astrom iauASTROM* star-independent astrometry parameters:
26
///      pmt    double       PM time interval (SSB, Julian years)
27
///      eb     double[3]    SSB to observer (vector, au)
28
///      eh     double[3]    Sun to observer (unit vector)
29
///      em     double       distance from Sun to observer (au)
30
///      v      double[3]    barycentric observer velocity (vector, c)
31
///      bm1    double       sqrt(1-|v|^2): reciprocal of Lorenz factor
32
///      bpn    double[3][3] bias-precession-nutation matrix
33
///      along  double       longitude + s' (radians)
34
///      xpl    double       polar motion xp wrt local meridian (radians)
35
///      ypl    double       polar motion yp wrt local meridian (radians)
36
///      sphi   double       sine of geodetic latitude
37
///      cphi   double       cosine of geodetic latitude
38
///      diurab double       magnitude of diurnal aberration vector
39
///      eral   double       "local" Earth rotation angle (radians)
40
///      refa   double       refraction constant A (radians)
41
///      refb   double       refraction constant B (radians)
42
///  ```
43
///  Returned:
44
///  ```
45
///     ri     double*    CIRS right ascension (CIO-based, radians)
46
///     di     double*    CIRS declination (radians)
47
///  ```
48
///  Notes:
49
///
50
///  1) "Observed" Az,ZD means the position that would be seen by a
51
///     perfect geodetically aligned theodolite.  This is related to
52
///     the observed HA,Dec via the standard rotation, using the geodetic
53
///     latitude (corrected for polar motion), while the observed HA and
54
///     (CIO-based) RA are related simply through the Earth rotation
55
///     angle and the site longitude.  "Observed" RA,Dec or HA,Dec thus
56
///     means the position that would be seen by a perfect equatorial
57
///     with its polar axis aligned to the Earth's axis of rotation.
58
///
59
///  2) Only the first character of the type argument is significant.
60
///     "R" or "r" indicates that ob1 and ob2 are the observed right
61
///     ascension (CIO-based) and declination;  "H" or "h" indicates that
62
///     they are hour angle (west +ve) and declination;  anything else
63
///     ("A" or "a" is recommended) indicates that ob1 and ob2 are
64
///     azimuth (north zero, east 90 deg) and zenith distance.  (Zenith
65
///     distance is used rather than altitude in order to reflect the
66
///     fact that no allowance is made for depression of the horizon.)
67
///
68
///  3) The accuracy of the result is limited by the corrections for
69
///     refraction, which use a simple A*tan(z) + B*tan^3(z) model.
70
///     Providing the meteorological parameters are known accurately and
71
///     there are no gross local effects, the predicted intermediate
72
///     coordinates should be within 0.05 arcsec (optical) or 1 arcsec
73
///     (radio) for a zenith distance of less than 70 degrees, better
74
///     than 30 arcsec (optical or radio) at 85 degrees and better than
75
///     20 arcmin (optical) or 25 arcmin (radio) at the horizon.
76
///
77
///     Without refraction, the complementary functions iauAtioq and
78
///     iauAtoiq are self-consistent to better than 1 microarcsecond all
79
///     over the celestial sphere.  With refraction included, consistency
80
///     falls off at high zenith distances, but is still better than
81
///     0.05 arcsec at 85 degrees.
82
///
83
///  4) It is advisable to take great care with units, as even unlikely
84
///     values of the input parameters are accepted and processed in
85
///     accordance with the models used.
86
///
87
///  Called:
88
///     iauS2c       spherical coordinates to unit vector
89
///     iauC2s       p-vector to spherical
90
///     iauAnp       normalize angle into range 0 to 2pi
91
///
92
0
pub fn atoiq(type_: &str, ob1: f64, ob2: f64, astrom: &IauAstrom) -> (f64, f64) {
93
    /* Minimum sin(alt) for refraction purposes */
94
    const SELMIN: f64 = 0.05;
95
96
    let c1: f64;
97
    let c2: f64;
98
    let mut ce: f64;
99
    let xaeo: f64;
100
    let yaeo: f64;
101
    let zaeo: f64;
102
0
    let mut v = [0.0; 3];
103
104
    /* Coordinate type. */
105
0
    let c_char = type_.chars().next().unwrap_or('A');
106
107
    /* Coordinates. */
108
0
    c1 = ob1;
109
0
    c2 = ob2;
110
111
    /* Sin, cos of latitude. */
112
0
    let sphi = astrom.sphi;
113
0
    let cphi = astrom.cphi;
114
115
    /* Standardize coordinate type. */
116
0
    let c = if c_char == 'r' || c_char == 'R' {
117
0
        'R'
118
0
    } else if c_char == 'h' || c_char == 'H' {
119
0
        'H'
120
    } else {
121
0
        'A'
122
    };
123
124
    /* If Az,ZD, convert to Cartesian (S=0,E=90). */
125
0
    if c == 'A' {
126
0
        ce = c2.sin();
127
0
        xaeo = -c1.cos() * ce;
128
0
        yaeo = c1.sin() * ce;
129
0
        zaeo = c2.cos();
130
0
    } else {
131
0
        let c1_mod = if c == 'R' { astrom.eral - c1 } else { c1 };
132
133
        /* To Cartesian -HA,Dec. */
134
0
        v = s2c(-c1_mod, c2);
135
0
        let xmhdo = v[0];
136
0
        let ymhdo = v[1];
137
0
        let zmhdo = v[2];
138
139
        /* To Cartesian Az,El (S=0,E=90). */
140
0
        xaeo = sphi * xmhdo - cphi * zmhdo;
141
0
        yaeo = ymhdo;
142
0
        zaeo = cphi * xmhdo + sphi * zmhdo;
143
    }
144
145
    /* Azimuth (S=0,E=90). */
146
0
    let az = if xaeo != 0.0 || yaeo != 0.0 {
147
0
        yaeo.atan2(xaeo)
148
    } else {
149
0
        0.0
150
    };
151
152
    /* Sine of observed ZD, and observed ZD. */
153
0
    let sz = (xaeo * xaeo + yaeo * yaeo).sqrt();
154
0
    let zdo = sz.atan2(zaeo);
155
156
    /*
157
     ** Refraction
158
     ** ----------
159
     */
160
161
    /* Fast algorithm using two constant model. */
162
0
    let refa = astrom.refa;
163
0
    let refb = astrom.refb;
164
0
    let tz = sz / if zaeo > SELMIN { zaeo } else { SELMIN };
165
0
    let dref = (refa + refb * tz * tz) * tz;
166
0
    let zdt = zdo + dref;
167
168
    /* To Cartesian Az,ZD. */
169
0
    ce = zdt.sin();
170
0
    let xaet = az.cos() * ce;
171
0
    let yaet = az.sin() * ce;
172
0
    let zaet = zdt.cos();
173
174
    /* Cartesian Az,ZD to Cartesian -HA,Dec. */
175
0
    let xmhda = sphi * xaet + cphi * zaet;
176
0
    let ymhda = yaet;
177
0
    let zmhda = -cphi * xaet + sphi * zaet;
178
179
    /* Diurnal aberration. */
180
0
    let f = 1.0 + astrom.diurab * ymhda;
181
0
    let xhd = f * xmhda;
182
0
    let yhd = f * (ymhda - astrom.diurab);
183
0
    let zhd = f * zmhda;
184
185
    /* Polar motion. */
186
0
    let sx = astrom.xpl.sin();
187
0
    let cx = astrom.xpl.cos();
188
0
    let sy = astrom.ypl.sin();
189
0
    let cy = astrom.ypl.cos();
190
0
    v[0] = cx * xhd + sx * sy * yhd - sx * cy * zhd;
191
0
    v[1] = cy * yhd + sy * zhd;
192
0
    v[2] = sx * xhd - cx * sy * yhd + cx * cy * zhd;
193
194
    /* To spherical -HA,Dec. */
195
0
    let (hma, di) = c2s(&v);
196
197
    /* Right ascension. */
198
0
    let ri = anp(astrom.eral + hma);
199
200
0
    (ri, di)
201
0
}