practical_astronomy_rust/
macros.rs

1use crate::types as pa_t;
2use crate::util as pa_u;
3
4/// Convert a Civil Time (hours,minutes,seconds) to Decimal Hours.
5///
6/// Original macro name: HMSDH
7pub fn hms_dh(hours: f64, minutes: f64, seconds: f64) -> f64 {
8    let f_hours = hours as f64;
9    let f_minutes = minutes as f64;
10    let f_seconds = seconds as f64;
11
12    let a = f_seconds.abs() / 60.0;
13    let b = (f_minutes.abs() + a) / 60.0;
14    let c = f_hours.abs() + b;
15
16    return if f_hours < 0.0 || f_minutes < 0.0 || f_seconds < 0.0 {
17        -c
18    } else {
19        c
20    };
21}
22
23/// Return the hour part of a Decimal Hours.
24///
25/// Original macro name: DHHour
26pub fn dh_hour(decimal_hours: f64) -> u32 {
27    let a = decimal_hours.abs();
28    let b = a * 3600.0;
29    let c = pa_u::round_f64(b - 60.0 * (b / 60.0).floor(), 2);
30    // let d = if c == 60.0 { 0.0 } else { c };
31    let e = if c == 60.0 { b + 60.0 } else { b };
32
33    return if decimal_hours < 0.0 {
34        -(e / 3600.0).floor() as u32
35    } else {
36        (e / 3600.0).floor() as u32
37    };
38}
39
40/// Return the minutes part of a Decimal Hours.
41///
42/// Original macro name: DHMin
43pub fn dh_min(decimal_hours: f64) -> u32 {
44    let a = decimal_hours.abs();
45    let b = a * 3600.0;
46    let c = pa_u::round_f64(b - 60.0 * (b / 60.0).floor(), 2);
47    let e = if c == 60.0 { b + 60.0 } else { b };
48
49    return ((e / 60.0).floor() % 60.0) as u32;
50}
51
52/// Return the seconds part of a Decimal Hours.
53///
54/// Original macro name: DHSec
55pub fn dh_sec(decimal_hours: f64) -> f64 {
56    let a = decimal_hours.abs();
57    let b = a * 3600.0;
58    let c = pa_u::round_f64(b - 60.0 * (b / 60.0).floor(), 2);
59    let d = if c == 60.0 { 0.0 } else { c };
60
61    return d;
62}
63
64/// Convert a Greenwich Date/Civil Date (day,month,year) to Julian Date.
65///
66/// Original macro name: CDJD
67pub fn cd_jd(day: f64, month: u32, year: u32) -> f64 {
68    let f_day = day as f64;
69    let f_month = month as f64;
70    let f_year = year as f64;
71
72    let y = if f_month < 3.0 { f_year - 1.0 } else { f_year };
73    let m = if f_month < 3.0 {
74        f_month + 12.0
75    } else {
76        f_month
77    };
78
79    let b: f64;
80
81    if f_year > 1582.0 {
82        let a = (y / 100.0).floor();
83        b = 2.0 - a + (a / 4.0).floor();
84    } else {
85        if f_year == 1582.0 && f_month > 10.0 {
86            let a = (y / 100.0).floor();
87            b = 2.0 - a + (a / 4.0).floor();
88        } else {
89            if f_year == 1582.0 && f_month == 10.0 && f_day >= 15.0 {
90                let a = (y / 100.0).floor();
91                b = 2.0 - a + (a / 4.0).floor();
92            } else {
93                b = 0.0;
94            }
95        }
96    }
97
98    let c = if y < 0.0 {
99        ((365.25 * y) - 0.75).floor()
100    } else {
101        (365.25 * y).floor()
102    };
103
104    let d = (30.6001 * (m + 1.0)).floor();
105
106    return b + c + d + f_day + 1720994.5;
107}
108
109/// Returns the day part of a Julian Date.
110///
111/// Original macro name: JDCDay
112pub fn jdc_day(julian_date: f64) -> f64 {
113    let i = (julian_date + 0.5).floor();
114    let f = julian_date + 0.5 - i;
115    let a = ((i - 1867216.25) / 36524.25).floor();
116    let b = if i > 2299160.0 {
117        i + 1.0 + a - (a / 4.0).floor()
118    } else {
119        i
120    };
121    let c = b + 1524.0;
122    let d = ((c - 122.1) / 365.25).floor();
123    let e = (365.25 * d).floor();
124    let g = ((c - e) / 30.6001).floor();
125
126    return c - e + f - (30.6001 * g).floor();
127}
128
129/// Returns the month part of a Julian Date.
130///
131/// Original macro name: JDCMonth
132pub fn jdc_month(julian_date: f64) -> u32 {
133    let i = (julian_date + 0.5).floor();
134    let _f = julian_date + 0.5 - i;
135    let a = ((i - 1867216.25) / 36524.25).floor();
136    let b = if i > 2299160.0 {
137        i + 1.0 + a - (a / 4.0).floor()
138    } else {
139        i
140    };
141    let c = b + 1524.0;
142    let d = ((c - 122.1) / 365.25).floor();
143    let e = (365.25 * d).floor();
144    let g = ((c - e) / 30.6001).floor();
145
146    let return_value = if g < 13.5 { g - 1.0 } else { g - 13.0 };
147
148    return return_value as u32;
149}
150
151/// Returns the year part of a Julian Date.
152///
153/// Original macro name: JDCYear
154pub fn jdc_year(julian_date: f64) -> u32 {
155    let i = (julian_date + 0.5).floor();
156    let _f = julian_date + 0.5 - i;
157    let a = ((i - 1867216.25) / 36524.25).floor();
158    let b = if i > 2299160.0 {
159        i + 1.0 + a - (a / 4.0).floor()
160    } else {
161        i
162    };
163    let c = b + 1524.0;
164    let d = ((c - 122.1) / 365.25).floor();
165    let e = (365.25 * d).floor();
166    let g = ((c - e) / 30.6001).floor();
167    let h = if g < 13.5 { g - 1.0 } else { g - 13.0 };
168
169    let return_value = if h > 2.5 { d - 4716.0 } else { d - 4715.0 };
170
171    return return_value as u32;
172}
173
174/// Convert a Julian Date to Day-of-Week (e.g., Sunday).
175///
176/// Original macro name: FDOW
177pub fn f_dow(julian_date: f64) -> String {
178    let j = (julian_date - 0.5).floor() + 0.5;
179    let n = (j + 1.5) % 7.0;
180
181    let return_value: &str;
182    match n as u32 {
183        0 => return_value = "Sunday",
184        1 => return_value = "Monday",
185        2 => return_value = "Tuesday",
186        3 => return_value = "Wednesday",
187        4 => return_value = "Thursday",
188        5 => return_value = "Friday",
189        6 => return_value = "Saturday",
190        _ => return_value = "Unknown",
191    }
192
193    return return_value.to_string();
194}
195
196/// Convert Right Ascension to Hour Angle.
197///
198/// Original macro name: RAHA
199pub fn ra_ha(
200    ra_hours: f64,
201    ra_minutes: f64,
202    ra_seconds: f64,
203    lct_hours: f64,
204    lct_minutes: f64,
205    lct_seconds: f64,
206    daylight_saving: i32,
207    zone_correction: i32,
208    local_day: f64,
209    local_month: u32,
210    local_year: u32,
211    geographical_longitude: f64,
212) -> f64 {
213    let a = lct_ut(
214        lct_hours,
215        lct_minutes,
216        lct_seconds,
217        daylight_saving,
218        zone_correction,
219        local_day,
220        local_month,
221        local_year,
222    );
223    let b = lct_gday(
224        lct_hours,
225        lct_minutes,
226        lct_seconds,
227        daylight_saving,
228        zone_correction,
229        local_day,
230        local_month,
231        local_year,
232    );
233    let c = lct_gmonth(
234        lct_hours,
235        lct_minutes,
236        lct_seconds,
237        daylight_saving,
238        zone_correction,
239        local_day,
240        local_month,
241        local_year,
242    );
243    let d = lct_gyear(
244        lct_hours,
245        lct_minutes,
246        lct_seconds,
247        daylight_saving,
248        zone_correction,
249        local_day,
250        local_month,
251        local_year,
252    );
253    let e = ut_gst(a, 0.0, 0.0, b, c, d);
254    let f = gst_lst(e, 0.0, 0.0, geographical_longitude);
255    let g = hms_dh(ra_hours, ra_minutes, ra_seconds);
256    let h = f - g;
257
258    return if h < 0.0 { 24.0 + h } else { h };
259}
260
261/// Convert Hour Angle to Right Ascension.
262///
263/// Original macro name: HARA
264pub fn ha_ra(
265    hour_angle_hours: f64,
266    hour_angle_minutes: f64,
267    hour_angle_seconds: f64,
268    lct_hours: f64,
269    lct_minutes: f64,
270    lct_seconds: f64,
271    daylight_saving: i32,
272    zone_correction: i32,
273    local_day: f64,
274    local_month: u32,
275    local_year: u32,
276    geographical_longitude: f64,
277) -> f64 {
278    let a = lct_ut(
279        lct_hours,
280        lct_minutes,
281        lct_seconds,
282        daylight_saving,
283        zone_correction,
284        local_day,
285        local_month,
286        local_year,
287    );
288    let b = lct_gday(
289        lct_hours,
290        lct_minutes,
291        lct_seconds,
292        daylight_saving,
293        zone_correction,
294        local_day,
295        local_month,
296        local_year,
297    );
298    let c = lct_gmonth(
299        lct_hours,
300        lct_minutes,
301        lct_seconds,
302        daylight_saving,
303        zone_correction,
304        local_day,
305        local_month,
306        local_year,
307    );
308    let d = lct_gyear(
309        lct_hours,
310        lct_minutes,
311        lct_seconds,
312        daylight_saving,
313        zone_correction,
314        local_day,
315        local_month,
316        local_year,
317    );
318    let e = ut_gst(a, 0.0, 0.0, b, c, d);
319    let f = gst_lst(e, 0.0, 0.0, geographical_longitude);
320    let g = hms_dh(hour_angle_hours, hour_angle_minutes, hour_angle_seconds);
321    let h = f - g;
322
323    return if h < 0.0 { 24.0 + h } else { h };
324}
325
326/// Convert Local Civil Time to Universal Time.
327///
328/// Original macro name: LctUT
329pub fn lct_ut(
330    lct_hours: f64,
331    lct_minutes: f64,
332    lct_seconds: f64,
333    daylight_saving: i32,
334    zone_correction: i32,
335    local_day: f64,
336    local_month: u32,
337    local_year: u32,
338) -> f64 {
339    let a = hms_dh(lct_hours, lct_minutes, lct_seconds as f64);
340    let b = a - daylight_saving as f64 - zone_correction as f64;
341    let c = local_day as f64 + (b / 24.0);
342    let d = cd_jd(c, local_month, local_year);
343    let e = jdc_day(d);
344    let e1 = e.floor();
345
346    return 24.0 * (e - e1);
347}
348
349/// Convert Universal Time to Local Civil Time.
350///
351/// Original macro name: UTLct
352pub fn ut_lct(
353    u_hours: f64,
354    u_minutes: f64,
355    u_seconds: f64,
356    daylight_saving: i32,
357    zone_correction: i32,
358    greenwich_day: f64,
359    greenwich_month: u32,
360    greenwich_year: u32,
361) -> f64 {
362    let a = hms_dh(u_hours, u_minutes, u_seconds);
363    let b = a + zone_correction as f64;
364    let c = b + daylight_saving as f64;
365    let d = cd_jd(greenwich_day, greenwich_month, greenwich_year) + (c / 24.0);
366    let e = jdc_day(d);
367    let e1 = e.floor();
368
369    return 24.0 * (e - e1);
370}
371
372/// Get Local Civil Day for Universal Time.
373///
374/// Original macro name: UTLcDay
375pub fn ut_lc_day(
376    u_hours: f64,
377    u_minutes: f64,
378    u_seconds: f64,
379    daylight_saving: i32,
380    zone_correction: i32,
381    greenwich_day: f64,
382    greenwich_month: u32,
383    greenwich_year: u32,
384) -> f64 {
385    let a = hms_dh(u_hours, u_minutes, u_seconds);
386    let b = a + zone_correction as f64;
387    let c = b + daylight_saving as f64;
388    let d = cd_jd(greenwich_day, greenwich_month, greenwich_year) + (c / 24.0);
389    let e = jdc_day(d);
390    let e1 = e.floor();
391
392    return e1;
393}
394
395/// Get Local Civil Month for Universal Time.
396///
397/// Original macro name: UTLcMonth
398pub fn ut_lc_month(
399    u_hours: f64,
400    u_minutes: f64,
401    u_seconds: f64,
402    daylight_saving: i32,
403    zone_correction: i32,
404    greenwich_day: f64,
405    greenwich_month: u32,
406    greenwich_year: u32,
407) -> u32 {
408    let a = hms_dh(u_hours, u_minutes, u_seconds);
409    let b = a + zone_correction as f64;
410    let c = b + daylight_saving as f64;
411    let d = cd_jd(greenwich_day, greenwich_month, greenwich_year) + (c / 24.0);
412
413    return jdc_month(d);
414}
415
416/// Get Local Civil Year for Universal Time.
417///
418/// Original macro name: UTLcYear
419pub fn ut_lc_year(
420    u_hours: f64,
421    u_minutes: f64,
422    u_seconds: f64,
423    daylight_saving: i32,
424    zone_correction: i32,
425    greenwich_day: f64,
426    greenwich_month: u32,
427    greenwich_year: u32,
428) -> u32 {
429    let a = hms_dh(u_hours, u_minutes, u_seconds);
430    let b = a + zone_correction as f64;
431    let c = b + daylight_saving as f64;
432    let d = cd_jd(greenwich_day, greenwich_month, greenwich_year) + (c / 24.0);
433
434    return jdc_year(d);
435}
436
437/// Determine Greenwich Day for Local Time.
438///
439/// Original macro name: LctGDay
440pub fn lct_gday(
441    lct_hours: f64,
442    lct_minutes: f64,
443    lct_seconds: f64,
444    daylight_saving: i32,
445    zone_correction: i32,
446    local_day: f64,
447    local_month: u32,
448    local_year: u32,
449) -> f64 {
450    let a = hms_dh(lct_hours, lct_minutes, lct_seconds as f64);
451    let b = a - daylight_saving as f64 - zone_correction as f64;
452    let c = local_day as f64 + (b / 24.0);
453    let d = cd_jd(c, local_month, local_year);
454    let e = jdc_day(d);
455
456    return e.floor();
457}
458
459/// Determine Greenwich Month for Local Time.
460///
461/// Original macro name: LctGMonth
462pub fn lct_gmonth(
463    lct_hours: f64,
464    lct_minutes: f64,
465    lct_seconds: f64,
466    daylight_saving: i32,
467    zone_correction: i32,
468    local_day: f64,
469    local_month: u32,
470    local_year: u32,
471) -> u32 {
472    let a = hms_dh(lct_hours, lct_minutes, lct_seconds as f64);
473    let b = a - daylight_saving as f64 - zone_correction as f64;
474    let c = local_day as f64 + (b / 24.0);
475    let d = cd_jd(c, local_month, local_year);
476
477    return jdc_month(d);
478}
479
480/// Determine Greenwich Year for Local Time.
481///
482/// Original macro name: LctGYear
483pub fn lct_gyear(
484    lct_hours: f64,
485    lct_minutes: f64,
486    lct_seconds: f64,
487    daylight_saving: i32,
488    zone_correction: i32,
489    local_day: f64,
490    local_month: u32,
491    local_year: u32,
492) -> u32 {
493    let a = hms_dh(lct_hours, lct_minutes, lct_seconds as f64);
494    let b = a - daylight_saving as f64 - zone_correction as f64;
495    let c = local_day as f64 + (b / 24.0);
496    let d = cd_jd(c, local_month, local_year);
497
498    return jdc_year(d);
499}
500
501/// Convert Universal Time to Greenwich Sidereal Time.
502///
503/// Original macro name: UTGST
504pub fn ut_gst(
505    u_hours: f64,
506    u_minutes: f64,
507    u_seconds: f64,
508    greenwich_day: f64,
509    greenwich_month: u32,
510    greenwich_year: u32,
511) -> f64 {
512    let a = cd_jd(greenwich_day as f64, greenwich_month, greenwich_year);
513    let b = a - 2451545.0;
514    let c = b / 36525.0;
515    let d = 6.697374558 + (2400.051336 * c) + (0.000025862 * c * c);
516    let e = d - (24.0 * (d / 24.0).floor());
517    let f = hms_dh(u_hours, u_minutes, u_seconds);
518    let g = f * 1.002737909;
519    let h = e + g;
520    return h - (24.0 * (h / 24.0).floor());
521}
522
523/// Convert Greenwich Sidereal Time to Local Sidereal Time.
524///
525/// Original macro name: GSTLST
526pub fn gst_lst(
527    greenwich_hours: f64,
528    greenwich_minutes: f64,
529    greenwich_seconds: f64,
530    geographical_longitude: f64,
531) -> f64 {
532    let a = hms_dh(greenwich_hours, greenwich_minutes, greenwich_seconds);
533    let b = geographical_longitude / 15.0;
534    let c = a + b;
535
536    return c - (24.0 * (c / 24.0).floor());
537}
538
539/// Convert Equatorial Coordinates to Azimuth (in decimal degrees).
540///
541/// Original macro name: EQAz
542pub fn eq_az(
543    hour_angle_hours: f64,
544    hour_angle_minutes: f64,
545    hour_angle_seconds: f64,
546    declination_degrees: f64,
547    declination_minutes: f64,
548    declination_seconds: f64,
549    geographical_latitude: f64,
550) -> f64 {
551    let a = hms_dh(hour_angle_hours, hour_angle_minutes, hour_angle_seconds);
552    let b = a * 15.0;
553    let c = b.to_radians();
554    let d = dms_dd(
555        declination_degrees,
556        declination_minutes,
557        declination_seconds,
558    );
559    let e = d.to_radians();
560    let f = geographical_latitude.to_radians();
561    let g = e.sin() * f.sin() + e.cos() * f.cos() * c.cos();
562    let h = -e.cos() * f.cos() * c.sin();
563    let i = e.sin() - (f.sin() * g);
564    let j = degrees(h.atan2(i));
565
566    return j - 360.0 * (j / 360.0).floor();
567}
568
569/// Convert Equatorial Coordinates to Altitude (in decimal degrees).
570///
571/// Original macro name: EQAlt
572pub fn eq_alt(
573    hour_angle_hours: f64,
574    hour_angle_minutes: f64,
575    hour_angle_seconds: f64,
576    declination_degrees: f64,
577    declination_minutes: f64,
578    declination_seconds: f64,
579    geographical_latitude: f64,
580) -> f64 {
581    let a = hms_dh(hour_angle_hours, hour_angle_minutes, hour_angle_seconds);
582    let b = a * 15.0;
583    let c = b.to_radians();
584    let d = dms_dd(
585        declination_degrees,
586        declination_minutes,
587        declination_seconds,
588    );
589    let e = d.to_radians();
590    let f = geographical_latitude.to_radians();
591    let g = e.sin() * f.sin() + e.cos() * f.cos() * c.cos();
592
593    return degrees(g.asin());
594}
595
596/// Convert Degrees Minutes Seconds to Decimal Degrees.
597///
598/// Original macro name: DMSDD
599pub fn dms_dd(degrees: f64, minutes: f64, seconds: f64) -> f64 {
600    let a = seconds.abs() / 60.0;
601    let b = (minutes.abs() + a) / 60.0;
602    let c = degrees.abs() + b;
603
604    return if degrees < 0.0 || minutes < 0.0 || seconds < 0.0 {
605        -c
606    } else {
607        c
608    };
609}
610
611/// Convert W to Degrees.
612///
613/// Original macro name: Degrees
614pub fn degrees(w: f64) -> f64 {
615    return w * 57.29577951;
616}
617
618/// Return Degrees part of Decimal Degrees.
619///
620/// Original macro name: DDDeg
621pub fn dd_deg(decimal_degrees: f64) -> f64 {
622    let a = decimal_degrees.abs();
623    let b = a * 3600.0;
624    let c = pa_u::round_f64(b - 60.0 * (b / 60.0).floor(), 2);
625    let _d = if c == 60.0 { 0.0 } else { c };
626    let e = if c == 60.0 { 60.0 } else { b };
627
628    return if decimal_degrees < 0.0 {
629        -(e / 3600.0).floor()
630    } else {
631        (e / 3600.0).floor()
632    };
633}
634
635/// Return Minutes part of Decimal Degrees.
636///
637/// Original macro name: DDMin
638pub fn dd_min(decimal_degrees: f64) -> f64 {
639    let a = decimal_degrees.abs();
640    let b = a * 3600.0;
641    let c = pa_u::round_f64(b - 60.0 * (b / 60.0).floor(), 2);
642    let _d = if c == 60.0 { 0.0 } else { c };
643    let e = if c == 60.0 { b + 60.0 } else { b };
644
645    return (e / 60.0).floor() % 60.0;
646}
647
648/// Return Seconds part of Decimal Degrees.
649///
650/// Original macro name: DDSec
651pub fn dd_sec(decimal_degrees: f64) -> f64 {
652    let a = decimal_degrees.abs();
653    let b = a * 3600.0;
654    let c = pa_u::round_f64(b - 60.0 * (b / 60.0).floor(), 2);
655    let d = if c == 60.0 { 0.0 } else { c };
656
657    return d;
658}
659
660/// Convert Decimal Degrees to Degree-Hours.
661///
662/// Original macro name: DDDH
663pub fn dd_dh(decimal_degrees: f64) -> f64 {
664    return decimal_degrees / 15.0;
665}
666
667/// Convert Degree-Hours to Decimal Degrees.
668///
669/// Original macro name: DHDD
670pub fn dh_dd(degree_hours: f64) -> f64 {
671    return degree_hours * 15.0;
672}
673
674/// Convert Horizon Coordinates to Declination (in decimal degrees).
675///
676/// Original macro name: HORDec
677pub fn hor_dec(
678    azimuth_degrees: f64,
679    azimuth_minutes: f64,
680    azimuth_seconds: f64,
681    altitude_degrees: f64,
682    altitude_minutes: f64,
683    altitude_seconds: f64,
684    geographical_latitude: f64,
685) -> f64 {
686    let a = dms_dd(azimuth_degrees, azimuth_minutes, azimuth_seconds);
687    let b = dms_dd(altitude_degrees, altitude_minutes, altitude_seconds);
688    let c = a.to_radians();
689    let d = b.to_radians();
690    let e = geographical_latitude.to_radians();
691    let f = d.sin() * e.sin() + d.cos() * e.cos() * c.cos();
692
693    return degrees(f.asin());
694}
695
696/// Convert Horizon Coordinates to Hour Angle (in decimal degrees).
697///
698/// Original macro name: HORHa
699pub fn hor_ha(
700    azimuth_degrees: f64,
701    azimuth_minutes: f64,
702    azimuth_seconds: f64,
703    altitude_degrees: f64,
704    altitude_minutes: f64,
705    altitude_seconds: f64,
706    geographical_latitude: f64,
707) -> f64 {
708    let a = dms_dd(azimuth_degrees, azimuth_minutes, azimuth_seconds);
709    let b = dms_dd(altitude_degrees, altitude_minutes, altitude_seconds);
710    let c = a.to_radians();
711    let d = b.to_radians();
712    let e = geographical_latitude.to_radians();
713    let f = d.sin() * e.sin() + d.cos() * e.cos() * c.cos();
714    let g = -d.cos() * e.cos() * c.sin();
715    let h = d.sin() - e.sin() * f;
716    let i = dd_dh(degrees(g.atan2(h)));
717
718    return i - 24.0 * (i / 24.0).floor();
719}
720
721/// Nutation amount to be added in ecliptic longitude, in degrees.
722///
723/// Original macro name: NutatLong
724pub fn nutat_long(gd: f64, gm: u32, gy: u32) -> f64 {
725    let dj = cd_jd(gd, gm, gy) - 2415020.0;
726    let t = dj / 36525.0;
727    let t2 = t * t;
728
729    let a = 100.0021358 * t;
730    let b = 360.0 * (a - a.floor());
731
732    let l1 = 279.6967 + 0.000303 * t2 + b;
733    let l2 = 2.0 * l1.to_radians();
734
735    let a = 1336.855231 * t;
736    let b = 360.0 * (a - a.floor());
737
738    let d1 = 270.4342 - 0.001133 * t2 + b;
739    let d2 = 2.0 * d1.to_radians();
740
741    let a = 99.99736056 * t;
742    let b = 360.0 * (a - a.floor());
743
744    let m1 = 358.4758 - 0.00015 * t2 + b;
745    let m1 = m1.to_radians();
746
747    let a = 1325.552359 * t;
748    let b = 360.0 * (a - a.floor());
749
750    let m2 = 296.1046 + 0.009192 * t2 + b;
751    let m2 = m2.to_radians();
752
753    let a = 5.372616667 * t;
754    let b = 360.0 * (a - a.floor());
755
756    let n1 = 259.1833 + 0.002078 * t2 - b;
757    let n1 = n1.to_radians();
758
759    let n2 = 2.0 * n1;
760
761    let dp = (-17.2327 - 0.01737 * t) * n1.sin();
762    let dp = dp + (-1.2729 - 0.00013 * t) * (l2).sin() + 0.2088 * (n2).sin();
763    let dp = dp - 0.2037 * (d2).sin() + (0.1261 - 0.00031 * t) * (m1).sin();
764    let dp = dp + 0.0675 * (m2).sin() - (0.0497 - 0.00012 * t) * (l2 + m1).sin();
765    let dp = dp - 0.0342 * (d2 - n1).sin() - 0.0261 * (d2 + m2).sin();
766    let dp = dp + 0.0214 * (l2 - m1).sin() - 0.0149 * (l2 - d2 + m2).sin();
767    let dp = dp + 0.0124 * (l2 - n1).sin() + 0.0114 * (d2 - m2).sin();
768
769    return dp / 3600.0;
770}
771
772/// Nutation of Obliquity.
773///
774/// Original macro name: NutatObl
775pub fn nutat_obl(greenwich_day: f64, greenwich_month: u32, greenwich_year: u32) -> f64 {
776    let dj = cd_jd(greenwich_day, greenwich_month, greenwich_year) - 2415020.0;
777    let t = dj / 36525.0;
778    let t2 = t * t;
779
780    let a = 100.0021358 * t;
781    let b = 360.0 * (a - a.floor());
782
783    let l1 = 279.6967 + 0.000303 * t2 + b;
784    let l2 = 2.0 * l1.to_radians();
785
786    let a = 1336.855231 * t;
787    let b = 360.0 * (a - a.floor());
788
789    let d1 = 270.4342 - 0.001133 * t2 + b;
790    let d2 = 2.0 * d1.to_radians();
791
792    let a = 99.99736056 * t;
793    let b = 360.0 * (a - a.floor());
794
795    let m1 = (358.4758 - 0.00015 * t2 + b).to_radians();
796    //M1 = math.radians(M1)
797
798    let a = 1325.552359 * t;
799    let b = 360.0 * (a - a.floor());
800
801    let m2 = (296.1046 + 0.009192 * t2 + b).to_radians();
802    // M2 = math.radians(M2)
803
804    let a = 5.372616667 * t;
805    let b = 360.0 * (a - a.floor());
806
807    let n1 = (259.1833 + 0.002078 * t2 - b).to_radians();
808    //	N1 = math.radians(N1)
809
810    let n2 = 2.0 * n1;
811
812    let ddo = (9.21 + 0.00091 * t) * n1.cos();
813    let ddo = ddo + (0.5522 - 0.00029 * t) * l2.cos() - 0.0904 * n2.cos();
814    let ddo = ddo + 0.0884 * d2.cos() + 0.0216 * (l2 + m1).cos();
815    let ddo = ddo + 0.0183 * (d2 - n1).cos() + 0.0113 * (d2 + m2).cos();
816    let ddo = ddo - 0.0093 * (l2 - m1).cos() - 0.0066 * (l2 - n1).cos();
817
818    return ddo / 3600.0;
819}
820
821/// Obliquity of the Ecliptic for a Greenwich Date.
822///
823/// Original macro name: Obliq
824pub fn obliq(greenwich_day: f64, greenwich_month: u32, greenwich_year: u32) -> f64 {
825    let a = cd_jd(greenwich_day, greenwich_month, greenwich_year);
826    let b = a - 2415020.0;
827    let c = (b / 36525.0) - 1.0;
828    let d = c * (46.815 + c * (0.0006 - (c * 0.00181)));
829    let e = d / 3600.0;
830
831    return 23.43929167 - e + nutat_obl(greenwich_day, greenwich_month, greenwich_year);
832}
833
834/// Convert Local Sidereal Time to Greenwich Sidereal Time.
835///
836/// Original macro name: LSTGST
837pub fn lst_gst(local_hours: f64, local_minutes: f64, local_seconds: f64, longitude: f64) -> f64 {
838    let a = hms_dh(local_hours, local_minutes, local_seconds);
839    let b = longitude / 15.0;
840    let c = a - b;
841    return c - (24.0 * (c / 24.0).floor());
842}
843
844/// Convert Greenwich Sidereal Time to Universal Time.
845///
846/// Original macro name: GSTUT
847pub fn gst_ut(
848    greenwich_sidereal_hours: f64,
849    greenwich_sidereal_minutes: f64,
850    greenwich_sidereal_seconds: f64,
851    greenwich_day: f64,
852    greenwich_month: u32,
853    greenwich_year: u32,
854) -> f64 {
855    let a = cd_jd(greenwich_day, greenwich_month, greenwich_year);
856    let b = a - 2451545.0;
857    let c = b / 36525.0;
858    let d = 6.697374558 + (2400.051336 * c) + (0.000025862 * c * c);
859    let e = d - (24.0 * (d / 24.0).floor());
860    let f = hms_dh(
861        greenwich_sidereal_hours,
862        greenwich_sidereal_minutes,
863        greenwich_sidereal_seconds,
864    );
865    let g = f - e;
866    let h = g - (24.0 * (g / 24.0).floor());
867    return h * 0.9972695663;
868}
869
870/// Status of conversion of Greenwich Sidereal Time to Universal Time.
871///
872/// Original macro name: eGSTUT
873pub fn e_gst_ut(gsh: f64, gsm: f64, gss: f64, gd: f64, gm: u32, gy: u32) -> String {
874    let a = cd_jd(gd, gm, gy);
875    let b = a - 2451545.0;
876    let c = b / 36525.0;
877    let d = 6.697374558 + (2400.051336 * c) + (0.000025862 * c * c);
878    let e = d - (24.0 * (d / 24.0).floor());
879    let f = hms_dh(gsh, gsm, gss);
880    let g = f - e;
881    let h = g - (24.0 * (g / 24.0).floor());
882
883    if (h * 0.9972695663) < (4.0 / 60.0) {
884        return "Warning".to_string();
885    } else {
886        return "OK".to_string();
887    };
888}
889
890/// Calculate Sun's ecliptic longitude.
891///
892/// Original macro name: SunLong
893pub fn sun_long(lch: f64, lcm: f64, lcs: f64, ds: i32, zc: i32, ld: f64, lm: u32, ly: u32) -> f64 {
894    let aa = lct_gday(lch, lcm, lcs, ds, zc, ld, lm, ly);
895    let bb = lct_gmonth(lch, lcm, lcs, ds, zc, ld, lm, ly);
896    let cc = lct_gyear(lch, lcm, lcs, ds, zc, ld, lm, ly);
897    let ut = lct_ut(lch, lcm, lcs, ds, zc, ld, lm, ly);
898    let dj = cd_jd(aa, bb, cc) - 2415020.0;
899    let t = (dj / 36525.0) + (ut / 876600.0);
900    let t2 = t * t;
901    let a = 100.0021359 * t;
902    let b = 360.0 * (a - (a).floor());
903
904    let l = 279.69668 + 0.0003025 * t2 + b;
905    let a = 99.99736042 * t;
906    let b = 360.0 * (a - a.floor());
907
908    let m1 = 358.47583 - (0.00015 + 0.0000033 * t) * t2 + b;
909    let ec = 0.01675104 - 0.0000418 * t - 0.000000126 * t2;
910
911    let am = m1.to_radians();
912    let at = true_anomaly(am, ec);
913    let _ae = eccentric_anomaly(am, ec);
914
915    let a = 62.55209472 * t;
916    let b = 360.0 * (a - (a).floor());
917
918    let a1 = (153.23 + b).to_radians();
919    let a = 125.1041894 * t;
920    let b = 360.0 * (a - (a).floor());
921
922    let b1 = (216.57 + b).to_radians();
923    let a = 91.56766028 * t;
924    let b = 360.0 * (a - (a).floor());
925
926    let c1 = (312.69 + b).to_radians();
927    let a = 1236.853095 * t;
928    let b = 360.0 * (a - (a).floor());
929
930    let d1 = (350.74 - 0.00144 * t2 + b).to_radians();
931    let e1 = (231.19 + 20.2 * t).to_radians();
932    let a = 183.1353208 * t;
933    let b = 360.0 * (a - (a).floor());
934    let h1 = (353.4 + b).to_radians();
935
936    let d2 = 0.00134 * a1.cos() + 0.00154 * b1.cos() + 0.002 * c1.cos();
937    let d2 = d2 + 0.00179 * d1.sin() + 0.00178 * e1.sin();
938    let d3 = 0.00000543 * a1.sin() + 0.00001575 * b1.sin();
939    let d3 = d3 + 0.00001627 * c1.sin() + 0.00003076 * d1.cos();
940    let _d3 = d3 + 0.00000927 * h1.sin();
941
942    let sr = at + (l - m1 + d2).to_radians();
943    let tp = 6.283185308;
944
945    let sr = sr - tp * (sr / tp).floor();
946    return degrees(sr);
947}
948
949/// Solve Kepler's equation, and return value of the true anomaly in radians.
950///
951/// Original macro name: TrueAnomaly
952pub fn true_anomaly(am: f64, ec: f64) -> f64 {
953    let tp = 6.283185308;
954    let m = am - tp * (am / tp).floor();
955    let mut ae = m;
956
957    while 1 == 1 {
958        let d = ae - (ec * (ae).sin()) - m;
959        if d.abs() < 0.000001 {
960            break;
961        }
962        let d = d / (1.0 - (ec * (ae).cos()));
963        ae = ae - d;
964    }
965
966    let a = ((1.0 + ec) / (1.0 - ec)).sqrt() * (ae / 2.0).tan();
967    let at = 2.0 * a.atan();
968
969    return at;
970}
971
972/// Solve Kepler's equation, and return value of the eccentric anomaly in radians.
973///
974/// Original macro name: EccentricAnomaly
975pub fn eccentric_anomaly(am: f64, ec: f64) -> f64 {
976    let tp = 6.283185308;
977    let m = am - tp * (am / tp).floor();
978    let mut ae = m;
979
980    while 1 == 1 {
981        let d = ae - (ec * (ae).sin()) - m;
982
983        if d.abs() < 0.000001 {
984            break;
985        }
986
987        let d = d / (1.0 - (ec * (ae).cos()));
988        ae = ae - d;
989    }
990
991    return ae;
992}
993
994/// Calculate effects of refraction.
995///
996/// Original macro name: Refract
997pub fn refract(y2: f64, sw: String, pr: f64, tr: f64) -> f64 {
998    let y = y2.to_radians();
999
1000    let d = if &sw[..1].to_string().to_lowercase() == "t" {
1001        -1.0
1002    } else {
1003        1.0
1004    };
1005
1006    if d == -1.0 {
1007        let y3 = y;
1008        let y1 = y;
1009        let mut r1 = 0.0;
1010
1011        while 1 == 1 {
1012            let y = y1 + r1;
1013            let _q = y;
1014            let rf = refract_l3035(pr, tr, y, d);
1015            if y < -0.087 {
1016                return 0.0;
1017            }
1018            let r2 = rf;
1019
1020            if (r2 == 0.0) || ((r2 - r1).abs() < 0.000001) {
1021                let q = y3;
1022                return degrees(q + rf);
1023            }
1024
1025            r1 = r2;
1026        }
1027    }
1028
1029    let rf = refract_l3035(pr, tr, y, d);
1030
1031    if y < -0.087 {
1032        return 0.0;
1033    }
1034
1035    let q = y;
1036
1037    return degrees(q + rf);
1038}
1039
1040/// Helper function for refract.
1041pub fn refract_l3035(pr: f64, tr: f64, y: f64, d: f64) -> f64 {
1042    if y < 0.2617994 {
1043        if y < -0.087 {
1044            return 0.0;
1045        }
1046
1047        let yd = degrees(y);
1048        let a = ((0.00002 * yd + 0.0196) * yd + 0.1594) * pr;
1049        let b = (273.0 + tr) * ((0.0845 * yd + 0.505) * yd + 1.0);
1050
1051        return (-(a / b) * d).to_radians();
1052    }
1053
1054    return -d * 0.00007888888 * pr / ((273.0 + tr) * (y).tan());
1055}
1056
1057/// Calculate corrected hour angle in decimal hours.
1058///
1059/// Original macro name: ParallaxHA
1060pub fn parallax_ha(
1061    hh: f64,
1062    hm: f64,
1063    hs: f64,
1064    dd: f64,
1065    dm: f64,
1066    ds: f64,
1067    sw: String,
1068    gp: f64,
1069    ht: f64,
1070    hp: f64,
1071) -> f64 {
1072    let a = gp.to_radians();
1073    let c1 = a.cos();
1074    let s1 = a.sin();
1075
1076    let u = (0.996647 * s1 / c1).atan();
1077    let c2 = u.cos();
1078    let s2 = u.sin();
1079    let b = ht / 6378160.0;
1080
1081    let rs = (0.996647 * s2) + (b * s1);
1082
1083    let rc = c2 + (b * c1);
1084    let tp = 6.283185308;
1085
1086    let rp = 1.0 / hp.to_radians().sin();
1087
1088    let x = (dh_dd(hms_dh(hh, hm, hs))).to_radians();
1089    let x1 = x;
1090    let y = (dms_dd(dd, dm, ds)).to_radians();
1091    let y1 = y;
1092
1093    let d = if &sw[..1].to_string().to_lowercase() == "t" {
1094        1.0
1095    } else {
1096        -1.0
1097    };
1098
1099    if d == 1.0 {
1100        let (p, _q) = parallax_ha_l2870(x, y, rc, rp, rs, tp);
1101        return dd_dh(degrees(p));
1102    }
1103
1104    let mut p1 = 0.0;
1105    let mut q1 = 0.0;
1106    let mut x_loop = x;
1107    let mut y_loop = y;
1108    while 1 == 1 {
1109        let (p, q) = parallax_ha_l2870(x_loop, y_loop, rc, rp, rs, tp);
1110        let p2 = p - x_loop;
1111        let q2 = q - y_loop;
1112
1113        let aa = (p2 - p1).abs();
1114        let bb = (q2 - q1).abs();
1115
1116        if (aa < 0.000001) && (bb < 0.000001) {
1117            let p = x1 - p2;
1118            let _q = y1 - q2;
1119            let _x_loop = x1;
1120            let _y_loop = y1;
1121
1122            return dd_dh(degrees(p));
1123        }
1124        x_loop = x1 - p2;
1125        y_loop = y1 - q2;
1126        p1 = p2;
1127        q1 = q2;
1128    }
1129
1130    return dd_dh(degrees(0.0));
1131}
1132
1133/// Helper function for parallax_ha.
1134pub fn parallax_ha_l2870(x: f64, y: f64, rc: f64, rp: f64, rs: f64, tp: f64) -> (f64, f64) {
1135    let cx = x.cos();
1136    let sy = y.sin();
1137    let cy = y.cos();
1138
1139    let aa = (rc * x.sin()) / ((rp * cy) - (rc * cx));
1140
1141    let dx = aa.atan();
1142    let p = x + dx;
1143    let cp = p.cos();
1144
1145    let p = p - tp * (p / tp).floor();
1146    let q = (cp * (rp * sy - rs) / (rp * cy * cx - rc)).atan();
1147
1148    return (p, q);
1149}
1150
1151/// Calculate corrected declination in decimal degrees.
1152///
1153/// Original macro name: ParallaxDec
1154pub fn parallax_dec(
1155    hh: f64,
1156    hm: f64,
1157    hs: f64,
1158    dd: f64,
1159    dm: f64,
1160    ds: f64,
1161    sw: String,
1162    gp: f64,
1163    ht: f64,
1164    hp: f64,
1165) -> f64 {
1166    let a = gp.to_radians();
1167    let c1 = a.cos();
1168    let s1 = a.sin();
1169
1170    let u = (0.996647 * s1 / c1).atan();
1171
1172    let c2 = u.cos();
1173    let s2 = u.sin();
1174    let b = ht / 6378160.0;
1175    let rs = (0.996647 * s2) + (b * s1);
1176
1177    let rc = c2 + (b * c1);
1178    let tp = 6.283185308;
1179
1180    let rp = 1.0 / hp.to_radians().sin();
1181
1182    let x = (dh_dd(hms_dh(hh, hm, hs))).to_radians();
1183    let x1 = x;
1184
1185    let y = (dms_dd(dd, dm, ds)).to_radians();
1186    let y1 = y;
1187    let d = if &sw[..1].to_string().to_lowercase() == "t" {
1188        1.0
1189    } else {
1190        -1.0
1191    };
1192
1193    if d == 1.0 {
1194        let (_p, q) = parallax_dec_l2870(x, y, rc, rp, rs, tp);
1195        return degrees(q);
1196    }
1197
1198    let mut p1 = 0.0;
1199    let mut q1 = 0.0;
1200
1201    let mut x_loop = x;
1202    let mut y_loop = y;
1203    while 1 == 1 {
1204        let (p, q) = parallax_dec_l2870(x_loop, y_loop, rc, rp, rs, tp);
1205        let p2 = p - x_loop;
1206        let q2 = q - y_loop;
1207        let aa = (p2 - p1).abs();
1208        let _bb = (q2 - q1).abs();
1209        if (aa < 0.000001) && (b < 0.000001) {
1210            let _p = x1 - p2;
1211            let q = y1 - q2;
1212            let _x_loop = x1;
1213            let _y_loop = y1;
1214            return degrees(q);
1215        }
1216        x_loop = x1 - p2;
1217        y_loop = y1 - q2;
1218        p1 = p2;
1219        q1 = q2;
1220    }
1221
1222    return degrees(0.0);
1223}
1224
1225/// Helper function for parallax_dec.
1226pub fn parallax_dec_l2870(x: f64, y: f64, rc: f64, rp: f64, rs: f64, tp: f64) -> (f64, f64) {
1227    let cx = x.cos();
1228    let sy = y.sin();
1229    let cy = y.cos();
1230
1231    let aa = (rc * x.sin()) / ((rp * cy) - (rc * cx));
1232    let dx = aa.atan();
1233    let p = x + dx;
1234    let cp = p.cos();
1235
1236    let p = p - tp * (p / tp).floor();
1237    let q = (cp * (rp * sy - rs) / (rp * cy * cx - rc)).atan();
1238
1239    return (p, q);
1240}
1241
1242/// Calculate Sun's angular diameter in decimal degrees.
1243///
1244/// Original macro name: SunDia
1245pub fn sun_dia(lch: f64, lcm: f64, lcs: f64, ds: i32, zc: i32, ld: f64, lm: u32, ly: u32) -> f64 {
1246    let a = sun_dist(lch, lcm, lcs, ds, zc, ld, lm, ly);
1247
1248    return 0.533128 / a;
1249}
1250
1251/// Calculate Sun's distance from the Earth in astronomical units.
1252///
1253/// Original macro name: SunDist
1254pub fn sun_dist(lch: f64, lcm: f64, lcs: f64, ds: i32, zc: i32, ld: f64, lm: u32, ly: u32) -> f64 {
1255    let aa = lct_gday(lch, lcm, lcs, ds, zc, ld, lm, ly);
1256    let bb = lct_gmonth(lch, lcm, lcs, ds, zc, ld, lm, ly);
1257    let cc = lct_gyear(lch, lcm, lcs, ds, zc, ld, lm, ly);
1258    let ut = lct_ut(lch, lcm, lcs, ds, zc, ld, lm, ly);
1259    let dj = cd_jd(aa, bb, cc) - 2415020.0;
1260
1261    let t = (dj / 36525.0) + (ut / 876600.0);
1262    let t2 = t * t;
1263
1264    let a = 100.0021359 * t;
1265    let b = 360.0 * (a - a.floor());
1266    let _l = 279.69668 + 0.0003025 * t2 + b;
1267    let a = 99.99736042 * t;
1268    let b = 360.0 * (a - (a).floor());
1269    let m1 = 358.47583 - (0.00015 + 0.0000033 * t) * t2 + b;
1270    let ec = 0.01675104 - 0.0000418 * t - 0.000000126 * t2;
1271
1272    let am = m1.to_radians();
1273    let _at = true_anomaly(am, ec);
1274    let ae = eccentric_anomaly(am, ec);
1275
1276    let a = 62.55209472 * t;
1277    let b = 360.0 * (a - a.floor());
1278    let a1 = (153.23 + b).to_radians();
1279    let a = 125.1041894 * t;
1280    let b = 360.0 * (a - a.floor());
1281    let b1 = (216.57 + b).to_radians();
1282    let a = 91.56766028 * t;
1283    let b = 360.0 * (a - a.floor());
1284    let c1 = (312.69 + b).to_radians();
1285    let a = 1236.853095 * t;
1286    let b = 360.0 * (a - a.floor());
1287    let d1 = (350.74 - 0.00144 * t2 + b).to_radians();
1288    let e1 = (231.19 + 20.2 * t).to_radians();
1289    let a = 183.1353208 * t;
1290    let b = 360.0 * (a - a.floor());
1291    let h1 = (353.4 + b).to_radians();
1292
1293    let _d2 = (0.00134 * a1.cos() + 0.00154 * b1.cos() + 0.002 * c1.cos())
1294        + (0.00179 * d1.sin() + 0.00178 * e1.sin());
1295    let d3 = (0.00000543 * a1.sin() + 0.00001575 * b1.sin())
1296        + (0.00001627 * c1.sin() + 0.00003076 * d1.cos())
1297        + (0.00000927 * h1.sin());
1298
1299    return 1.0000002 * (1.0 - ec * ae.cos()) + d3;
1300}
1301
1302/// Calculate geocentric ecliptic longitude for the Moon.
1303///
1304/// Original macro name: MoonLong
1305pub fn moon_long(lh: f64, lm: f64, ls: f64, ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
1306    let ut = lct_ut(lh, lm, ls, ds, zc, dy, mn, yr);
1307    let gd = lct_gday(lh, lm, ls, ds, zc, dy, mn, yr);
1308    let gm = lct_gmonth(lh, lm, ls, ds, zc, dy, mn, yr);
1309    let gy = lct_gyear(lh, lm, ls, ds, zc, dy, mn, yr);
1310    let t = ((cd_jd(gd, gm, gy) - 2415020.0) / 36525.0) + (ut / 876600.0);
1311    let t2 = t * t;
1312
1313    let m1 = 27.32158213;
1314    let m2 = 365.2596407;
1315    let m3 = 27.55455094;
1316    let m4 = 29.53058868;
1317    let m5 = 27.21222039;
1318    let m6 = 6798.363307;
1319    let q = cd_jd(gd, gm, gy) - 2415020.0 + (ut / 24.0);
1320    let m1 = q / m1;
1321    let m2 = q / m2;
1322    let m3 = q / m3;
1323    let m4 = q / m4;
1324    let m5 = q / m5;
1325    let m6 = q / m6;
1326    let m1 = 360.0 * (m1 - (m1).floor());
1327    let m2 = 360.0 * (m2 - (m2).floor());
1328    let m3 = 360.0 * (m3 - (m3).floor());
1329    let m4 = 360.0 * (m4 - (m4).floor());
1330    let m5 = 360.0 * (m5 - (m5).floor());
1331    let m6 = 360.0 * (m6 - (m6).floor());
1332
1333    let ml = 270.434164 + m1 - (0.001133 - 0.0000019 * t) * t2;
1334    let ms = 358.475833 + m2 - (0.00015 + 0.0000033 * t) * t2;
1335    let md = 296.104608 + m3 + (0.009192 + 0.0000144 * t) * t2;
1336    let me1 = 350.737486 + m4 - (0.001436 - 0.0000019 * t) * t2;
1337    let mf = 11.250889 + m5 - (0.003211 + 0.0000003 * t) * t2;
1338    let na = 259.183275 - m6 + (0.002078 + 0.0000022 * t) * t2;
1339    let a = (51.2 + 20.2 * t).to_radians();
1340    let s1 = a.sin();
1341    let s2 = ((na).to_radians()).sin();
1342    let b = 346.56 + (132.87 - 0.0091731 * t) * t;
1343    let s3 = 0.003964 * ((b).to_radians()).sin();
1344    let c = (na + 275.05 - 2.3 * t).to_radians();
1345    let s4 = c.sin();
1346    let ml = ml + 0.000233 * s1 + s3 + 0.001964 * s2;
1347    let ms = ms - 0.001778 * s1;
1348    let md = md + 0.000817 * s1 + s3 + 0.002541 * s2;
1349    let mf = mf + s3 - 0.024691 * s2 - 0.004328 * s4;
1350    let me1 = me1 + 0.002011 * s1 + s3 + 0.001964 * s2;
1351    let e = 1.0 - (0.002495 + 0.00000752 * t) * t;
1352    let e2 = e * e;
1353    let ml = (ml).to_radians();
1354    let ms = ms.to_radians();
1355    let _na = na.to_radians();
1356    let me1 = me1.to_radians();
1357    let mf = mf.to_radians();
1358    let md = md.to_radians();
1359
1360    let l = 6.28875 * (md).sin() + 1.274018 * (2.0 * me1 - md).sin();
1361    let l = l + 0.658309 * (2.0 * me1).sin() + 0.213616 * (2.0 * md).sin();
1362    let l = l - e * 0.185596 * (ms).sin() - 0.114336 * (2.0 * mf).sin();
1363    let l = l + 0.058793 * (2.0 * (me1 - md)).sin();
1364    let l = l + 0.057212 * e * (2.0 * me1 - ms - md).sin() + 0.05332 * (2.0 * me1 + md).sin();
1365    let l = l + 0.045874 * e * (2.0 * me1 - ms).sin() + 0.041024 * e * (md - ms).sin();
1366    let l = l - 0.034718 * (me1).sin() - e * 0.030465 * (ms + md).sin();
1367    let l = l + 0.015326 * (2.0 * (me1 - mf)).sin() - 0.012528 * (2.0 * mf + md).sin();
1368    let l = l - 0.01098 * (2.0 * mf - md).sin() + 0.010674 * (4.0 * me1 - md).sin();
1369    let l = l + 0.010034 * (3.0 * md).sin() + 0.008548 * (4.0 * me1 - 2.0 * md).sin();
1370    let l = l - e * 0.00791 * (ms - md + 2.0 * me1).sin() - e * 0.006783 * (2.0 * me1 + ms).sin();
1371    let l = l + 0.005162 * (md - me1).sin() + e * 0.005 * (ms + me1).sin();
1372    let l = l + 0.003862 * (4.0 * me1).sin() + e * 0.004049 * (md - ms + 2.0 * me1).sin();
1373    let l = l + 0.003996 * (2.0 * (md + me1)).sin() + 0.003665 * (2.0 * me1 - 3.0 * md).sin();
1374    let l = l + e * 0.002695 * (2.0 * md - ms).sin() + 0.002602 * (md - 2.0 * (mf + me1)).sin();
1375    let l = l + e * 0.002396 * (2.0 * (me1 - md) - ms).sin() - 0.002349 * (md + me1).sin();
1376    let l = l + e2 * 0.002249 * (2.0 * (me1 - ms)).sin() - e * 0.002125 * (2.0 * md + ms).sin();
1377    let l = l - e2 * 0.002079 * (2.0 * ms).sin() + e2 * 0.002059 * (2.0 * (me1 - ms) - md).sin();
1378    let l = l - 0.001773 * (md + 2.0 * (me1 - mf)).sin() - 0.001595 * (2.0 * (mf + me1)).sin();
1379    let l = l + e * 0.00122 * (4.0 * me1 - ms - md).sin() - 0.00111 * (2.0 * (md + mf)).sin();
1380    let l = l + 0.000892 * (md - 3.0 * me1).sin() - e * 0.000811 * (ms + md + 2.0 * me1).sin();
1381    let l = l + e * 0.000761 * (4.0 * me1 - ms - 2.0 * md).sin();
1382    let l = l + e2 * 0.000704 * (md - 2.0 * (ms + me1)).sin();
1383    let l = l + e * 0.000693 * (ms - 2.0 * (md - me1)).sin();
1384    let l = l + e * 0.000598 * (2.0 * (me1 - mf) - ms).sin();
1385    let l = l + 0.00055 * (md + 4.0 * me1).sin() + 0.000538 * (4.0 * md).sin();
1386    let l = l + e * 0.000521 * (4.0 * me1 - ms).sin() + 0.000486 * (2.0 * md - me1).sin();
1387    let l = l + e2 * 0.000717 * (md - 2.0 * ms).sin();
1388    let mm = unwind(ml + l.to_radians());
1389
1390    return degrees(mm);
1391}
1392
1393/// Calculate geocentric ecliptic latitude for the Moon.
1394///
1395/// Original macro name: MoonLat
1396pub fn moon_lat(lh: f64, lm: f64, ls: f64, ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
1397    let ut = lct_ut(lh, lm, ls, ds, zc, dy, mn, yr);
1398    let gd = lct_gday(lh, lm, ls, ds, zc, dy, mn, yr);
1399    let gm = lct_gmonth(lh, lm, ls, ds, zc, dy, mn, yr);
1400    let gy = lct_gyear(lh, lm, ls, ds, zc, dy, mn, yr);
1401    let t = ((cd_jd(gd, gm, gy) - 2415020.0) / 36525.0) + (ut / 876600.0);
1402    let t2 = t * t;
1403
1404    let m1 = 27.32158213;
1405    let m2 = 365.2596407;
1406    let m3 = 27.55455094;
1407    let m4 = 29.53058868;
1408    let m5 = 27.21222039;
1409    let m6 = 6798.363307;
1410    let q = cd_jd(gd, gm, gy) - 2415020.0 + (ut / 24.0);
1411    let m1 = q / m1;
1412    let m2 = q / m2;
1413    let m3 = q / m3;
1414    let m4 = q / m4;
1415    let m5 = q / m5;
1416    let m6 = q / m6;
1417    let m1 = 360.0 * (m1 - (m1).floor());
1418    let m2 = 360.0 * (m2 - (m2).floor());
1419    let m3 = 360.0 * (m3 - (m3).floor());
1420    let m4 = 360.0 * (m4 - (m4).floor());
1421    let m5 = 360.0 * (m5 - (m5).floor());
1422    let m6 = 360.0 * (m6 - (m6).floor());
1423
1424    let ml = 270.434164 + m1 - (0.001133 - 0.0000019 * t) * t2;
1425    let ms = 358.475833 + m2 - (0.00015 + 0.0000033 * t) * t2;
1426    let md = 296.104608 + m3 + (0.009192 + 0.0000144 * t) * t2;
1427    let me1 = 350.737486 + m4 - (0.001436 - 0.0000019 * t) * t2;
1428    let mf = 11.250889 + m5 - (0.003211 + 0.0000003 * t) * t2;
1429    let na = 259.183275 - m6 + (0.002078 + 0.0000022 * t) * t2;
1430    let a = (51.2 + 20.2 * t).to_radians();
1431    let s1 = (a).sin();
1432    let s2 = na.to_radians().sin();
1433    let b = 346.56 + (132.87 - 0.0091731 * t) * t;
1434    let s3 = 0.003964 * b.to_radians().sin();
1435    let c = (na + 275.05 - 2.3 * t).to_radians();
1436    let s4 = (c).sin();
1437    let ml = ml + 0.000233 * s1 + s3 + 0.001964 * s2;
1438    let ms = ms - 0.001778 * s1;
1439    let md = md + 0.000817 * s1 + s3 + 0.002541 * s2;
1440    let mf = mf + s3 - 0.024691 * s2 - 0.004328 * s4;
1441    let me1 = me1 + 0.002011 * s1 + s3 + 0.001964 * s2;
1442    let e = 1.0 - (0.002495 + 0.00000752 * t) * t;
1443    let e2 = e * e;
1444    let _ml = (ml).to_radians();
1445    let ms = (ms).to_radians();
1446    let na = (na).to_radians();
1447    let me1 = (me1).to_radians();
1448    let mf = (mf).to_radians();
1449    let md = (md).to_radians();
1450
1451    let g = 5.128189 * (mf).sin() + 0.280606 * (md + mf).sin();
1452    let g = g + 0.277693 * (md - mf).sin() + 0.173238 * (2.0 * me1 - mf).sin();
1453    let g = g + 0.055413 * (2.0 * me1 + mf - md).sin() + 0.046272 * (2.0 * me1 - mf - md).sin();
1454    let g = g + 0.032573 * (2.0 * me1 + mf).sin() + 0.017198 * (2.0 * md + mf).sin();
1455    let g = g + 0.009267 * (2.0 * me1 + md - mf).sin() + 0.008823 * (2.0 * md - mf).sin();
1456    let g =
1457        g + e * 0.008247 * (2.0 * me1 - ms - mf).sin() + 0.004323 * (2.0 * (me1 - md) - mf).sin();
1458    let g = g + 0.0042 * (2.0 * me1 + mf + md).sin() + e * 0.003372 * (mf - ms - 2.0 * me1).sin();
1459    let g = g + e * 0.002472 * (2.0 * me1 + mf - ms - md).sin();
1460    let g = g + e * 0.002222 * (2.0 * me1 + mf - ms).sin();
1461    let g = g + e * 0.002072 * (2.0 * me1 - mf - ms - md).sin();
1462    let g = g + e * 0.001877 * (mf - ms + md).sin() + 0.001828 * (4.0 * me1 - mf - md).sin();
1463    let g = g - e * 0.001803 * (mf + ms).sin() - 0.00175 * (3.0 * mf).sin();
1464    let g = g + e * 0.00157 * (md - ms - mf).sin() - 0.001487 * (mf + me1).sin();
1465    let g = g - e * 0.001481 * (mf + ms + md).sin() + e * 0.001417 * (mf - ms - md).sin();
1466    let g = g + e * 0.00135 * (mf - ms).sin() + 0.00133 * (mf - me1).sin();
1467    let g = g + 0.001106 * (mf + 3.0 * md).sin() + 0.00102 * (4.0 * me1 - mf).sin();
1468    let g = g + 0.000833 * (mf + 4.0 * me1 - md).sin() + 0.000781 * (md - 3.0 * mf).sin();
1469    let g =
1470        g + 0.00067 * (mf + 4.0 * me1 - 2.0 * md).sin() + 0.000606 * (2.0 * me1 - 3.0 * mf).sin();
1471    let g = g + 0.000597 * (2.0 * (me1 + md) - mf).sin();
1472    let g = g
1473        + e * 0.000492 * (2.0 * me1 + md - ms - mf).sin()
1474        + 0.00045 * (2.0 * (md - me1) - mf).sin();
1475    let g = g + 0.000439 * (3.0 * md - mf).sin() + 0.000423 * (mf + 2.0 * (me1 + md)).sin();
1476    let g = g + 0.000422 * (2.0 * me1 - mf - 3.0 * md).sin()
1477        - e * 0.000367 * (ms + mf + 2.0 * me1 - md).sin();
1478    let g = g - e * 0.000353 * (ms + mf + 2.0 * me1).sin() + 0.000331 * (mf + 4.0 * me1).sin();
1479    let g = g + e * 0.000317 * (2.0 * me1 + mf - ms + md).sin();
1480    let g = g + e2 * 0.000306 * (2.0 * (me1 - ms) - mf).sin() - 0.000283 * (md + 3.0 * mf).sin();
1481    let w1 = 0.0004664 * (na).cos();
1482    let w2 = 0.0000754 * (c).cos();
1483    let bm = (g).to_radians() * (1.0 - w1 - w2);
1484
1485    return degrees(bm);
1486}
1487
1488/// Calculate horizontal parallax for the Moon.
1489///
1490/// Original macro name: MoonHP
1491pub fn moon_hp(lh: f64, lm: f64, ls: f64, ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
1492    let ut = lct_ut(lh, lm, ls, ds, zc, dy, mn, yr);
1493    let gd = lct_gday(lh, lm, ls, ds, zc, dy, mn, yr);
1494    let gm = lct_gmonth(lh, lm, ls, ds, zc, dy, mn, yr);
1495    let gy = lct_gyear(lh, lm, ls, ds, zc, dy, mn, yr);
1496    let t = ((cd_jd(gd, gm, gy) - 2415020.0) / 36525.0) + (ut / 876600.0);
1497    let t2 = t * t;
1498
1499    let m1 = 27.32158213;
1500    let m2 = 365.2596407;
1501    let m3 = 27.55455094;
1502    let m4 = 29.53058868;
1503    let m5 = 27.21222039;
1504    let m6 = 6798.363307;
1505    let q = cd_jd(gd, gm, gy) - 2415020.0 + (ut / 24.0);
1506    let m1 = q / m1;
1507    let m2 = q / m2;
1508    let m3 = q / m3;
1509    let m4 = q / m4;
1510    let m5 = q / m5;
1511    let m6 = q / m6;
1512    let m1 = 360.0 * (m1 - (m1).floor());
1513    let m2 = 360.0 * (m2 - (m2).floor());
1514    let m3 = 360.0 * (m3 - (m3).floor());
1515    let m4 = 360.0 * (m4 - (m4).floor());
1516    let m5 = 360.0 * (m5 - (m5).floor());
1517    let m6 = 360.0 * (m6 - (m6).floor());
1518
1519    let ml = 270.434164 + m1 - (0.001133 - 0.0000019 * t) * t2;
1520    let ms = 358.475833 + m2 - (0.00015 + 0.0000033 * t) * t2;
1521    let md = 296.104608 + m3 + (0.009192 + 0.0000144 * t) * t2;
1522    let me1 = 350.737486 + m4 - (0.001436 - 0.0000019 * t) * t2;
1523    let mf = 11.250889 + m5 - (0.003211 + 0.0000003 * t) * t2;
1524    let na = 259.183275 - m6 + (0.002078 + 0.0000022 * t) * t2;
1525    let a = (51.2 + 20.2 * t).to_radians();
1526    let s1 = a.sin();
1527    let s2 = na.to_radians().sin();
1528    let b = 346.56 + (132.87 - 0.0091731 * t) * t;
1529    let s3 = 0.003964 * b.to_radians().sin();
1530    let c = (na + 275.05 - 2.3 * t).to_radians();
1531    let s4 = c.sin();
1532    let ml = ml + 0.000233 * s1 + s3 + 0.001964 * s2;
1533    let ms = ms - 0.001778 * s1;
1534    let md = md + 0.000817 * s1 + s3 + 0.002541 * s2;
1535    let mf = mf + s3 - 0.024691 * s2 - 0.004328 * s4;
1536    let me1 = me1 + 0.002011 * s1 + s3 + 0.001964 * s2;
1537    let e = 1.0 - (0.002495 + 0.00000752 * t) * t;
1538    let e2 = e * e;
1539    let _ml = (ml).to_radians();
1540    let ms = (ms).to_radians();
1541    let _na = (na).to_radians();
1542    let me1 = (me1).to_radians();
1543    let mf = (mf).to_radians();
1544    let md = (md).to_radians();
1545
1546    let pm = 0.950724 + 0.051818 * (md).cos() + 0.009531 * (2.0 * me1 - md).cos();
1547    let pm = pm + 0.007843 * (2.0 * me1).cos() + 0.002824 * (2.0 * md).cos();
1548    let pm = pm + 0.000857 * (2.0 * me1 + md).cos() + e * 0.000533 * (2.0 * me1 - ms).cos();
1549    let pm = pm + e * 0.000401 * (2.0 * me1 - md - ms).cos();
1550    let pm = pm + e * 0.00032 * (md - ms).cos() - 0.000271 * (me1).cos();
1551    let pm = pm - e * 0.000264 * (ms + md).cos() - 0.000198 * (2.0 * mf - md).cos();
1552    let pm = pm + 0.000173 * (3.0 * md).cos() + 0.000167 * (4.0 * me1 - md).cos();
1553    let pm = pm - e * 0.000111 * (ms).cos() + 0.000103 * (4.0 * me1 - 2.0 * md).cos();
1554    let pm = pm - 0.000084 * (2.0 * md - 2.0 * me1).cos() - e * 0.000083 * (2.0 * me1 + ms).cos();
1555    let pm = pm + 0.000079 * (2.0 * me1 + 2.0 * md).cos() + 0.000072 * (4.0 * me1).cos();
1556    let pm = pm + e * 0.000064 * (2.0 * me1 - ms + md).cos()
1557        - e * 0.000063 * (2.0 * me1 + ms - md).cos();
1558    let pm = pm + e * 0.000041 * (ms + me1).cos() + e * 0.000035 * (2.0 * md - ms).cos();
1559    let pm = pm - 0.000033 * (3.0 * md - 2.0 * me1).cos() - 0.00003 * (md + me1).cos();
1560    let pm = pm - 0.000029 * (2.0 * (mf - me1)).cos() - e * 0.000029 * (2.0 * md + ms).cos();
1561    let pm =
1562        pm + e2 * 0.000026 * (2.0 * (me1 - ms)).cos() - 0.000023 * (2.0 * (mf - me1) + md).cos();
1563    let pm = pm + e * 0.000019 * (4.0 * me1 - ms - md).cos();
1564
1565    return pm;
1566}
1567
1568/// Calculate distance from the Earth to the Moon (km).
1569///
1570/// Original macro name: MoonDist
1571pub fn moon_dist(lh: f64, lm: f64, ls: f64, ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
1572    let hp = (moon_hp(lh, lm, ls, ds, zc, dy, mn, yr)).to_radians();
1573    let r = 6378.14 / hp.sin();
1574
1575    return r;
1576}
1577
1578/// Calculate the Moon's angular diameter (degrees).
1579///
1580/// Original macro name: MoonSize
1581pub fn moon_size(lh: f64, lm: f64, ls: f64, ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
1582    let hp = (moon_hp(lh, lm, ls, ds, zc, dy, mn, yr)).to_radians();
1583    let r = 6378.14 / hp.sin();
1584    let th = 384401.0 * 0.5181 / r;
1585
1586    return th;
1587}
1588
1589/// Convert angle in radians to equivalent angle in degrees.
1590///
1591/// Original macro name: Unwind
1592pub fn unwind(w: f64) -> f64 {
1593    return w - 6.283185308 * (w / 6.283185308).floor();
1594}
1595
1596/// Convert angle in degrees to equivalent angle in the range 0 to 360 degrees.
1597///
1598/// Original macro name: UnwindDeg
1599pub fn unwind_deg(w: f64) -> f64 {
1600    return w - 360.0 * (w / 360.0).floor();
1601}
1602
1603/// Convert angle in radians to equivalent angle in degrees.
1604///
1605/// Original macro name: UnwindRad
1606#[allow(dead_code)]
1607pub fn unwind_rad(w: f64) -> f64 {
1608    return w - 6.283185308 * (w / 6.283185308).floor();
1609}
1610
1611/// Mean ecliptic longitude of the Sun at the epoch.
1612///
1613/// Original macro name: SunElong
1614pub fn sun_e_long(gd: f64, gm: u32, gy: u32) -> f64 {
1615    let t = (cd_jd(gd, gm, gy) - 2415020.0) / 36525.0;
1616    let t2 = t * t;
1617    let x = 279.6966778 + 36000.76892 * t + 0.0003025 * t2;
1618
1619    return x - 360.0 * (x / 360.0).floor();
1620}
1621
1622/// Longitude of the Sun at perigee.
1623///
1624/// Original macro name: SunPeri
1625pub fn sun_peri(gd: f64, gm: u32, gy: u32) -> f64 {
1626    let t = (cd_jd(gd, gm, gy) - 2415020.0) / 36525.0;
1627    let t2 = t * t;
1628    let x = 281.2208444 + 1.719175 * t + 0.000452778 * t2;
1629
1630    return x - 360.0 * (x / 360.0).floor();
1631}
1632
1633/// Eccentricity of the Sun-Earth orbit.
1634///
1635/// Original macro name: SunEcc
1636pub fn sun_ecc(gd: f64, gm: u32, gy: u32) -> f64 {
1637    let t = (cd_jd(gd, gm, gy) - 2415020.0) / 36525.0;
1638    let t2 = t * t;
1639
1640    return 0.01675104 - 0.0000418 * t - 0.000000126 * t2;
1641}
1642
1643/// Ecliptic - Declination (degrees).
1644///
1645/// Original macro name: ECDec
1646pub fn ec_dec(
1647    eld: f64,
1648    elm: f64,
1649    els: f64,
1650    bd: f64,
1651    bm: f64,
1652    bs: f64,
1653    gd: f64,
1654    gm: u32,
1655    gy: u32,
1656) -> f64 {
1657    let a = (dms_dd(eld, elm, els)).to_radians();
1658    let b = (dms_dd(bd, bm, bs)).to_radians();
1659    let c = (obliq(gd, gm, gy)).to_radians();
1660    let d = b.sin() * c.cos() + b.cos() * c.sin() * a.sin();
1661    return degrees(d.asin());
1662}
1663
1664/// Ecliptic - Right Ascension (degrees).
1665///
1666/// Original macro name: ECRA
1667pub fn ec_ra(
1668    eld: f64,
1669    elm: f64,
1670    els: f64,
1671    bd: f64,
1672    bm: f64,
1673    bs: f64,
1674    gd: f64,
1675    gm: u32,
1676    gy: u32,
1677) -> f64 {
1678    let a = (dms_dd(eld, elm, els)).to_radians();
1679    let b = (dms_dd(bd, bm, bs)).to_radians();
1680    let c = (obliq(gd, gm, gy)).to_radians();
1681    let d = a.sin() * c.cos() - b.tan() * c.sin();
1682    let e = a.cos();
1683    let f = degrees(d.atan2(e));
1684
1685    return f - 360.0 * (f / 360.0).floor();
1686}
1687
1688/// Calculate Sun's true anomaly, i.e., how much its orbit deviates from a true circle to an ellipse.
1689///
1690/// Original macro name: SunTrueAnomaly
1691pub fn sun_true_anomaly(
1692    lch: f64,
1693    lcm: f64,
1694    lcs: f64,
1695    ds: i32,
1696    zc: i32,
1697    ld: f64,
1698    lm: u32,
1699    ly: u32,
1700) -> f64 {
1701    let aa = lct_gday(lch, lcm, lcs, ds, zc, ld, lm, ly);
1702    let bb = lct_gmonth(lch, lcm, lcs, ds, zc, ld, lm, ly);
1703    let cc = lct_gyear(lch, lcm, lcs, ds, zc, ld, lm, ly);
1704    let ut = lct_ut(lch, lcm, lcs, ds, zc, ld, lm, ly);
1705    let dj = cd_jd(aa, bb, cc) - 2415020.0;
1706
1707    let t = (dj / 36525.0) + (ut / 876600.0);
1708    let t2 = t * t;
1709
1710    let a = 100.0021359 * t;
1711    let b = 360.0 * (a - a.floor());
1712    let _l = 279.69668 + 0.0003025 * t2 + b;
1713
1714    let a = 99.99736042 * t;
1715    let b = 360.0 * (a - a.floor());
1716
1717    let m1 = 358.47583 - (0.00015 + 0.0000033 * t) * t2 + b;
1718    let ec = 0.01675104 - 0.0000418 * t - 0.000000126 * t2;
1719
1720    let am = m1.to_radians();
1721
1722    return degrees(true_anomaly(am, ec));
1723}
1724
1725/// Calculate the Sun's mean anomaly.
1726///
1727/// Original macro name: SunMeanAnomaly
1728pub fn sun_mean_anomaly(
1729    lch: f64,
1730    lcm: f64,
1731    lcs: f64,
1732    ds: i32,
1733    zc: i32,
1734    ld: f64,
1735    lm: u32,
1736    ly: u32,
1737) -> f64 {
1738    let aa = lct_gday(lch, lcm, lcs, ds, zc, ld, lm, ly);
1739    let bb = lct_gmonth(lch, lcm, lcs, ds, zc, ld, lm, ly);
1740    let cc = lct_gyear(lch, lcm, lcs, ds, zc, ld, lm, ly);
1741    let ut = lct_ut(lch, lcm, lcs, ds, zc, ld, lm, ly);
1742    let dj = cd_jd(aa, bb, cc) - 2415020.0;
1743    let t = (dj / 36525.0) + (ut / 876600.0);
1744    let t2 = t * t;
1745    let a = 100.0021359 * t;
1746    let b = 360.0 * (a - a.floor());
1747    let m1 = 358.47583 - (0.00015 + 0.0000033 * t) * t2 + b;
1748    let am = unwind((m1).to_radians());
1749
1750    return am;
1751}
1752
1753/// Calculate local civil time of sunrise.
1754///
1755/// Original macro name: SunriseLCT
1756pub fn sunrise_lct(ld: f64, lm: u32, ly: u32, ds: i32, zc: i32, gl: f64, gp: f64) -> f64 {
1757    let di = 0.8333333;
1758    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1759    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1760    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1761    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1762
1763    let (_a, _x, _y, la, s) = sunrise_lct_l3710(gd, gm, gy, sr, di, gp);
1764
1765    let xx: f64;
1766    if s != "OK" {
1767        xx = -99.0;
1768    } else {
1769        let x = lst_gst(la, 0.0, 0.0, gl);
1770        let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
1771
1772        if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
1773            xx = -99.0;
1774        } else {
1775            let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
1776            let (_a, _x, _y, la, s) = sunrise_lct_l3710(gd, gm, gy, sr, di, gp);
1777
1778            if s != "OK" {
1779                xx = -99.0;
1780            } else {
1781                let x = lst_gst(la, 0.0, 0.0, gl);
1782                let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
1783                xx = ut_lct(ut, 0.0, 0.0, ds, zc, gd, gm, gy);
1784            }
1785        }
1786    }
1787
1788    return xx;
1789}
1790
1791/// Helper function for sunrise_lct().
1792pub fn sunrise_lct_l3710(
1793    gd: f64,
1794    gm: u32,
1795    gy: u32,
1796    sr: f64,
1797    di: f64,
1798    gp: f64,
1799) -> (f64, f64, f64, f64, String) {
1800    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
1801    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
1802    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
1803    let la = rise_set_local_sidereal_time_rise(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
1804    let s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
1805
1806    return (a, x, y, la, s.to_string());
1807}
1808
1809/// Calculate local civil time of sunset.
1810///
1811/// Original macro name: SunsetLCT
1812pub fn sunset_lct(ld: f64, lm: u32, ly: u32, ds: i32, zc: i32, gl: f64, gp: f64) -> f64 {
1813    let di = 0.8333333;
1814    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1815    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1816    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1817    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
1818
1819    let (_a, _x, _y, la, s) = sunset_lct_l3710(gd, gm, gy, sr, di, gp);
1820
1821    let xx: f64;
1822    if s != "OK" {
1823        xx = -99.0;
1824    } else {
1825        let x = lst_gst(la, 0.0, 0.0, gl);
1826        let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
1827
1828        if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
1829            xx = -99.0;
1830        } else {
1831            let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
1832            let (_a, _x, _y, la, s) = sunset_lct_l3710(gd, gm, gy, sr, di, gp);
1833
1834            if s != "OK" {
1835                xx = -99.0;
1836            } else {
1837                let x = lst_gst(la, 0.0, 0.0, gl);
1838                let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
1839                xx = ut_lct(ut, 0.0, 0.0, ds, zc, gd, gm, gy);
1840            }
1841        }
1842    }
1843    return xx;
1844}
1845
1846/// Helper function for sunset_lct().
1847pub fn sunset_lct_l3710(
1848    gd: f64,
1849    gm: u32,
1850    gy: u32,
1851    sr: f64,
1852    di: f64,
1853    gp: f64,
1854) -> (f64, f64, f64, f64, String) {
1855    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
1856    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
1857    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
1858    let la = rise_set_local_sidereal_time_set(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
1859    let s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
1860
1861    return (a, x, y, la, s);
1862}
1863
1864/// Local sidereal time of rise, in hours.
1865///
1866/// Original macro name: RSLSTR
1867pub fn rise_set_local_sidereal_time_rise(
1868    rah: f64,
1869    ram: f64,
1870    ras: f64,
1871    dd: f64,
1872    dm: f64,
1873    ds: f64,
1874    vd: f64,
1875    g: f64,
1876) -> f64 {
1877    let a = hms_dh(rah, ram, ras);
1878    let b = (dh_dd(a)).to_radians();
1879    let c = (dms_dd(dd, dm, ds)).to_radians();
1880    let d = (vd).to_radians();
1881    let e = (g).to_radians();
1882    let f = -((d).sin() + (e).sin() * (c).sin()) / ((e).cos() * (c).cos());
1883    let h = if f.abs() < 1.0 { f.acos() } else { 0.0 };
1884    let i = dd_dh(degrees(b - h));
1885
1886    return i - 24.0 * (i / 24.0).floor();
1887}
1888
1889/// Azimuth of rising, in degrees.
1890///
1891/// Original macro name: RSAZR
1892pub fn rise_set_azimuth_rise(
1893    rah: f64,
1894    ram: f64,
1895    ras: f64,
1896    dd: f64,
1897    dm: f64,
1898    ds: f64,
1899    vd: f64,
1900    g: f64,
1901) -> f64 {
1902    let a = hms_dh(rah, ram, ras);
1903    let _b = (dh_dd(a)).to_radians();
1904    let c = (dms_dd(dd, dm, ds)).to_radians();
1905    let d = vd.to_radians();
1906    let e = g.to_radians();
1907    let f = (c.sin() + d.sin() * e.sin()) / (d.cos() * e.cos());
1908    let h = if e_rs(rah, ram, ras, dd, dm, ds, vd, g) == "OK" {
1909        f.acos()
1910    } else {
1911        0.0
1912    };
1913    let i = degrees(h);
1914
1915    return i - 360.0 * (i / 360.0).floor();
1916}
1917
1918/// Local sidereal time of setting, in hours.
1919///
1920/// Original macro name: RSLSTS
1921pub fn rise_set_local_sidereal_time_set(
1922    rah: f64,
1923    ram: f64,
1924    ras: f64,
1925    dd: f64,
1926    dm: f64,
1927    ds: f64,
1928    vd: f64,
1929    g: f64,
1930) -> f64 {
1931    let a = hms_dh(rah, ram, ras);
1932    let b = (dh_dd(a)).to_radians();
1933    let c = (dms_dd(dd, dm, ds)).to_radians();
1934    let d = vd.to_radians();
1935    let e = g.to_radians();
1936    let f = -(d.sin() + e.sin() * c.sin()) / (e.cos() * c.cos());
1937    let h = if f.abs() < 1.0 { f.acos() } else { 0.0 };
1938    let i = dd_dh(degrees(b + h));
1939
1940    return i - 24.0 * (i / 24.0).floor();
1941}
1942
1943/// Azimuth of setting, in degrees.
1944///
1945/// Original macro name: RSAZS
1946pub fn rise_set_azimuth_set(
1947    rah: f64,
1948    ram: f64,
1949    ras: f64,
1950    dd: f64,
1951    dm: f64,
1952    ds: f64,
1953    vd: f64,
1954    g: f64,
1955) -> f64 {
1956    let a = hms_dh(rah, ram, ras);
1957    let _b = (dh_dd(a)).to_radians();
1958    let c = (dms_dd(dd, dm, ds)).to_radians();
1959    let d = vd.to_radians();
1960    let e = g.to_radians();
1961    let f = (c.sin() + d.sin() * e.sin()) / (d.cos() * e.cos());
1962    let h = if e_rs(rah, ram, ras, dd, dm, ds, vd, g) == "OK" {
1963        f.acos()
1964    } else {
1965        0.0
1966    };
1967    let i = 360.0 - degrees(h);
1968
1969    return i - 360.0 * (i / 360.0).floor();
1970}
1971
1972/// Rise/Set status.
1973///
1974/// Possible values: "OK", "** never rises", "** circumpolar"
1975///
1976/// Original macro name: eRS
1977pub fn e_rs(rah: f64, ram: f64, ras: f64, dd: f64, dm: f64, ds: f64, vd: f64, g: f64) -> String {
1978    let a = hms_dh(rah, ram, ras);
1979    let _b = dh_dd(a).to_radians();
1980    let c = (dms_dd(dd, dm, ds)).to_radians();
1981    let d = vd.to_radians();
1982    let e = g.to_radians();
1983    let f = -(d.sin() + e.sin() * c.sin()) / (e.cos() * c.cos());
1984
1985    let mut return_value = "OK";
1986    if f >= 1.0 {
1987        return_value = "** never rises";
1988    }
1989    if f <= -1.0 {
1990        return_value = "** circumpolar"
1991    }
1992
1993    return return_value.to_string();
1994}
1995
1996/// Sunrise/Sunset calculation status.
1997///
1998/// Original macro name: eSunRS
1999pub fn e_sun_rs(ld: f64, lm: u32, ly: u32, ds: i32, zc: i32, gl: f64, gp: f64) -> String {
2000    // S = ""
2001    let di = 0.8333333;
2002    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2003    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2004    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2005    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2006
2007    let (_a, _x, _y, la, s) = e_sun_rs_l3710(gd, gm, gy, sr, di, gp);
2008
2009    if s != "OK" {
2010        return s;
2011    } else {
2012        let x = lst_gst(la, 0.0, 0.0, gl);
2013        let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2014        let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
2015        let (_a, _x, _y, la, s) = e_sun_rs_l3710(gd, gm, gy, sr, di, gp);
2016        if s != "OK" {
2017            return s;
2018        } else {
2019            let x = lst_gst(la, 0.0, 0.0, gl);
2020            let _ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2021
2022            if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
2023                let s = s + " GST to UT conversion warning";
2024                return s;
2025            }
2026            return s;
2027        }
2028    }
2029}
2030
2031/// Helper function for e_sun_rs().
2032pub fn e_sun_rs_l3710(
2033    gd: f64,
2034    gm: u32,
2035    gy: u32,
2036    sr: f64,
2037    di: f64,
2038    gp: f64,
2039) -> (f64, f64, f64, f64, String) {
2040    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
2041    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2042    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2043    let la = rise_set_local_sidereal_time_rise(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2044    let s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2045
2046    return (a, x, y, la, s);
2047}
2048
2049/// Calculate azimuth of sunrise.
2050///
2051/// Original macro name: SunriseAz
2052pub fn sunrise_az(ld: f64, lm: u32, ly: u32, ds: i32, zc: i32, gl: f64, gp: f64) -> f64 {
2053    let di = 0.8333333;
2054    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2055    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2056    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2057    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2058
2059    let (_a, _x, _y, la, s) = sunrise_az_l3710(gd, gm, gy, sr, di, gp);
2060
2061    if s != "OK" {
2062        return -99.0;
2063    }
2064
2065    let x = lst_gst(la, 0.0, 0.0, gl);
2066    let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2067
2068    if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
2069        return -99.0;
2070    }
2071
2072    let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
2073    let (_a, x, y, _la, s) = sunrise_az_l3710(gd, gm, gy, sr, di, gp);
2074
2075    if s != "OK" {
2076        return -99.0;
2077    }
2078
2079    return rise_set_azimuth_rise(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2080}
2081
2082/// Helper function for sunrise_az().
2083pub fn sunrise_az_l3710(
2084    gd: f64,
2085    gm: u32,
2086    gy: u32,
2087    sr: f64,
2088    di: f64,
2089    gp: f64,
2090) -> (f64, f64, f64, f64, String) {
2091    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
2092    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2093    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2094    let la = rise_set_local_sidereal_time_rise(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2095    let s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2096
2097    return (a, x, y, la, s);
2098}
2099
2100/// Calculate azimuth of sunset.
2101///
2102/// Original macro name: SunsetAz
2103pub fn sunset_az(ld: f64, lm: u32, ly: u32, ds: i32, zc: i32, gl: f64, gp: f64) -> f64 {
2104    let di = 0.8333333;
2105    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2106    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2107    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2108    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2109
2110    let (_a, _x, _y, la, s) = sunset_az_l3710(gd, gm, gy, sr, di, gp);
2111
2112    if s != "OK" {
2113        return -99.0;
2114    }
2115
2116    let x = lst_gst(la, 0.0, 0.0, gl);
2117    let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2118
2119    if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
2120        return -99.0;
2121    }
2122
2123    let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
2124
2125    let (_a, x, y, _la, s) = sunset_az_l3710(gd, gm, gy, sr, di, gp);
2126
2127    if s != "OK" {
2128        return -99.0;
2129    }
2130    return rise_set_azimuth_set(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2131}
2132
2133/// Helper function for sunset_az().
2134pub fn sunset_az_l3710(
2135    gd: f64,
2136    gm: u32,
2137    gy: u32,
2138    sr: f64,
2139    di: f64,
2140    gp: f64,
2141) -> (f64, f64, f64, f64, String) {
2142    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
2143    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2144    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2145    let la = rise_set_local_sidereal_time_set(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2146    let s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2147
2148    return (a, x, y, la, s);
2149}
2150
2151/// Calculate morning twilight start, in local time.
2152///
2153/// Twilight type (TT) can be one of "C" (civil), "N" (nautical), or "A" (astronomical).
2154///
2155/// Original macro name: TwilightAMLCT
2156pub fn twilight_am_lct(
2157    ld: f64,
2158    lm: u32,
2159    ly: u32,
2160    ds: i32,
2161    zc: i32,
2162    gl: f64,
2163    gp: f64,
2164    tt: &pa_t::TwilightType,
2165) -> f64 {
2166    let di = match tt {
2167        pa_t::TwilightType::Astronomical => 18.0,
2168        pa_t::TwilightType::Civil => 6.0,
2169        pa_t::TwilightType::Nautical => 12.0,
2170    };
2171
2172    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2173    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2174    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2175    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2176
2177    let (_a, _x, _y, la, s) = twilight_am_lct_l3710(gd, gm, gy, sr, di, gp);
2178
2179    if s != "OK" {
2180        return -99.0;
2181    }
2182
2183    let x = lst_gst(la, 0.0, 0.0, gl);
2184    let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2185
2186    if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
2187        return -99.0;
2188    }
2189
2190    let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
2191
2192    let (_a, _x, _y, la, s) = twilight_am_lct_l3710(gd, gm, gy, sr, di, gp);
2193
2194    if s != "OK" {
2195        return -99.0;
2196    }
2197
2198    let x = lst_gst(la, 0.0, 0.0, gl);
2199    let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2200
2201    let xx = ut_lct(ut, 0.0, 0.0, ds, zc, gd, gm, gy);
2202
2203    return xx;
2204}
2205
2206/// Helper function for twilight_am_lct().
2207pub fn twilight_am_lct_l3710(
2208    gd: f64,
2209    gm: u32,
2210    gy: u32,
2211    sr: f64,
2212    di: f64,
2213    gp: f64,
2214) -> (f64, f64, f64, f64, String) {
2215    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
2216    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2217    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2218    let la = rise_set_local_sidereal_time_rise(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2219    let s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2220
2221    return (a, x, y, la, s);
2222}
2223
2224/// Calculate evening twilight end, in local time.
2225///
2226/// Twilight type can be one of "C" (civil), "N" (nautical), or "A" (astronomical).
2227///
2228/// Original macro name: TwilightPMLCT
2229pub fn twilight_pm_lct(
2230    ld: f64,
2231    lm: u32,
2232    ly: u32,
2233    ds: i32,
2234    zc: i32,
2235    gl: f64,
2236    gp: f64,
2237    tt: &pa_t::TwilightType,
2238) -> f64 {
2239    let di = match tt {
2240        pa_t::TwilightType::Astronomical => 18.0,
2241        pa_t::TwilightType::Civil => 6.0,
2242        pa_t::TwilightType::Nautical => 12.0,
2243    };
2244
2245    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2246    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2247    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2248    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2249
2250    let (_a, _x, _y, la, s) = twilight_pm_lct_l3710(gd, gm, gy, sr, di, gp);
2251
2252    if s != "OK" {
2253        return 0.0;
2254    }
2255
2256    let x = lst_gst(la, 0.0, 0.0, gl);
2257    let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2258
2259    if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
2260        return 0.0;
2261    }
2262
2263    let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
2264
2265    let (_a, _x, _y, la, s) = twilight_pm_lct_l3710(gd, gm, gy, sr, di, gp);
2266
2267    if s != "OK" {
2268        return 0.0;
2269    }
2270
2271    let x = lst_gst(la, 0.0, 0.0, gl);
2272    let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2273
2274    return ut_lct(ut, 0.0, 0.0, ds, zc, gd, gm, gy);
2275}
2276
2277/// Helper function for twilight_pm_lct().
2278pub fn twilight_pm_lct_l3710(
2279    gd: f64,
2280    gm: u32,
2281    gy: u32,
2282    sr: f64,
2283    di: f64,
2284    gp: f64,
2285) -> (f64, f64, f64, f64, String) {
2286    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
2287    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2288    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2289    let la = rise_set_local_sidereal_time_set(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2290    let s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2291
2292    return (a, x, y, la, s);
2293}
2294
2295/// Twilight calculation status.
2296///
2297/// Twilight type can be one of "C" (civil), "N" (nautical), or "A" (astronomical).
2298///
2299/// Original macro name: eTwilight
2300///
2301/// ## Returns
2302/// One of: "OK", "** lasts all night", or "** Sun too far below horizon"
2303pub fn e_twilight(
2304    ld: f64,
2305    lm: u32,
2306    ly: u32,
2307    ds: i32,
2308    zc: i32,
2309    gl: f64,
2310    gp: f64,
2311    tt: &pa_t::TwilightType,
2312) -> String {
2313    // S = ""
2314
2315    let di = match tt {
2316        pa_t::TwilightType::Astronomical => 18.0,
2317        pa_t::TwilightType::Civil => 6.0,
2318        pa_t::TwilightType::Nautical => 12.0,
2319    };
2320
2321    let gd = lct_gday(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2322    let gm = lct_gmonth(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2323    let gy = lct_gyear(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2324    let sr = sun_long(12.0, 0.0, 0.0, ds, zc, ld, lm, ly);
2325
2326    let (_a, _x, _y, la, s) = e_twilight_l3710(gd, gm, gy, sr, di, gp);
2327
2328    if s != "OK" {
2329        return s;
2330    }
2331
2332    let x = lst_gst(la, 0.0, 0.0, gl);
2333    let ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2334    let sr = sun_long(ut, 0.0, 0.0, 0, 0, gd, gm, gy);
2335
2336    let (_a, _x, _y, la, s) = e_twilight_l3710(gd, gm, gy, sr, di, gp);
2337
2338    if s != "OK" {
2339        return s;
2340    }
2341
2342    let x = lst_gst(la, 0.0, 0.0, gl);
2343    let _ut = gst_ut(x, 0.0, 0.0, gd, gm, gy);
2344
2345    if e_gst_ut(x, 0.0, 0.0, gd, gm, gy) != "OK" {
2346        let s = s + " GST to UT conversion warning";
2347
2348        return s;
2349    }
2350
2351    return s;
2352}
2353
2354/// Helper function for e_twilight().
2355pub fn e_twilight_l3710(
2356    gd: f64,
2357    gm: u32,
2358    gy: u32,
2359    sr: f64,
2360    di: f64,
2361    gp: f64,
2362) -> (f64, f64, f64, f64, String) {
2363    let a = sr + nutat_long(gd, gm, gy) - 0.005694;
2364    let x = ec_ra(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2365    let y = ec_dec(a, 0.0, 0.0, 0.0, 0.0, 0.0, gd, gm, gy);
2366    let la = rise_set_local_sidereal_time_rise(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2367    let mut s = e_rs(dd_dh(x), 0.0, 0.0, y, 0.0, 0.0, di, gp);
2368
2369    if s.len() > 2 {
2370        if &s[0..3].to_string() == "** c" {
2371            s = "** lasts all night".to_string();
2372        } else {
2373            if &s[0..3].to_string() == "** n" {
2374                s = "** Sun too far below horizon".to_string();
2375            }
2376        }
2377    }
2378
2379    return (a, x, y, la, s);
2380}
2381
2382/// Calculate the angle between two celestial objects.
2383///
2384/// Original macro name: Angle
2385pub fn angle(
2386    xx1: f64,
2387    xm1: f64,
2388    xs1: f64,
2389    dd1: f64,
2390    dm1: f64,
2391    ds1: f64,
2392    xx2: f64,
2393    xm2: f64,
2394    xs2: f64,
2395    dd2: f64,
2396    dm2: f64,
2397    ds2: f64,
2398    s: pa_t::AngleMeasure,
2399) -> f64 {
2400    let s_value = match s {
2401        pa_t::AngleMeasure::Degrees => "D",
2402        pa_t::AngleMeasure::Hours => "H",
2403    };
2404
2405    let a = if s_value == "H" {
2406        dh_dd(hms_dh(xx1, xm1, xs1))
2407    } else {
2408        dms_dd(xx1, xm1, xs1)
2409    };
2410    let b = a.to_radians();
2411    let c = dms_dd(dd1, dm1, ds1);
2412    let d = c.to_radians();
2413    let e = if s_value == "H" {
2414        dh_dd(hms_dh(xx2, xm2, xs2))
2415    } else {
2416        dms_dd(xx2, xm2, xs2)
2417    };
2418    let f = e.to_radians();
2419    let g = dms_dd(dd2, dm2, ds2);
2420    let h = g.to_radians();
2421    let i = (d.sin() * h.sin() + d.cos() * h.cos() * (b - f).cos()).acos();
2422
2423    return degrees(i);
2424}
2425
2426#[derive(Clone)]
2427pub struct PlDataStruct {
2428    pub value1: f64,
2429    pub value2: f64,
2430    pub value3: f64,
2431    pub value4: f64,
2432    pub value5: f64,
2433    pub value6: f64,
2434    pub value7: f64,
2435    pub value8: f64,
2436    pub value9: f64,
2437}
2438
2439/// Calculate several planetary properties.
2440///
2441/// Original macro names: PlanetLong, PlanetLat, PlanetDist, PlanetHLong1, PlanetHLong2, PlanetHLat, PlanetRVect
2442///
2443/// ## Arguments
2444/// * `lh` -- Local civil time, hour part.
2445/// * `lm` -- Local civil time, minutes part.
2446/// * `ls` -- Local civil time, seconds part.
2447/// * `ds` -- Daylight Savings offset.
2448/// * `zc` -- Time zone correction, in hours.
2449/// * `dy` -- Local date, day part.
2450/// * `mn` -- Local date, month part.
2451/// * `yr` -- Local date, year part.
2452/// * `s` -- Planet name.
2453///
2454/// ## Returns
2455/// * `planet_longitude` -- Ecliptic longitude, in degrees.
2456/// * `planet_latitude` -- Ecliptic latitude, in degrees.
2457/// * `planet_distance_au` -- Earth-planet distance, in AU.
2458/// * `planet_h_long1` -- Heliocentric orbital longitude, in degrees.
2459/// * `planet_h_long2` -- NOT USED
2460/// * `planet_h_lat` -- NOT USED
2461/// * `planet_r_vect` -- Sun-planet distance (length of radius vector), in AU.
2462pub fn planet_coordinates(
2463    lh: f64,
2464    lm: f64,
2465    ls: f64,
2466    ds: i32,
2467    zc: i32,
2468    dy: f64,
2469    mn: u32,
2470    yr: u32,
2471    s: String,
2472) -> (f64, f64, f64, f64, f64, f64, f64) {
2473    let a11 = 178.179078;
2474    let a12 = 415.2057519;
2475    let a13 = 0.0003011;
2476    let a14 = 0.0;
2477    let a21 = 75.899697;
2478    let a22 = 1.5554889;
2479    let a23 = 0.0002947;
2480    let a24 = 0.0;
2481    let a31 = 0.20561421;
2482    let a32 = 0.00002046;
2483    let a33 = -0.00000003;
2484    let a34 = 0.0;
2485    let a41 = 7.002881;
2486    let a42 = 0.0018608;
2487    let a43 = -0.0000183;
2488    let a44 = 0.0;
2489    let a51 = 47.145944;
2490    let a52 = 1.1852083;
2491    let a53 = 0.0001739;
2492    let a54 = 0.0;
2493    let a61 = 0.3870986;
2494    let a62 = 6.74;
2495    let a63 = -0.42;
2496
2497    let b11 = 342.767053;
2498    let b12 = 162.5533664;
2499    let b13 = 0.0003097;
2500    let b14 = 0.0;
2501    let b21 = 130.163833;
2502    let b22 = 1.4080361;
2503    let b23 = -0.0009764;
2504    let b24 = 0.0;
2505    let b31 = 0.00682069;
2506    let b32 = -0.00004774;
2507    let b33 = 0.000000091;
2508    let b34 = 0.0;
2509    let b41 = 3.393631;
2510    let b42 = 0.0010058;
2511    let b43 = -0.000001;
2512    let b44 = 0.0;
2513    let b51 = 75.779647;
2514    let b52 = 0.89985;
2515    let b53 = 0.00041;
2516    let b54 = 0.0;
2517    let b61 = 0.7233316;
2518    let b62 = 16.92;
2519    let b63 = -4.4;
2520
2521    let c11 = 293.737334;
2522    let c12 = 53.17137642;
2523    let c13 = 0.0003107;
2524    let c14 = 0.0;
2525    let c21 = 334.218203;
2526    let c22 = 1.8407584;
2527    let c23 = 0.0001299;
2528    let c24 = -0.00000119;
2529    let c31 = 0.0933129;
2530    let c32 = 0.000092064;
2531    let c33 = -0.000000077;
2532    let c34 = 0.0;
2533    let c41 = 1.850333;
2534    let c42 = -0.000675;
2535    let c43 = 0.0000126;
2536    let c44 = 0.0;
2537    let c51 = 48.786442;
2538    let c52 = 0.7709917;
2539    let c53 = -0.0000014;
2540    let c54 = -0.00000533;
2541    let c61 = 1.5236883;
2542    let c62 = 9.36;
2543    let c63 = -1.52;
2544
2545    let d11 = 238.049257;
2546    let d12 = 8.434172183;
2547    let d13 = 0.0003347;
2548    let d14 = -0.00000165;
2549    let d21 = 12.720972;
2550    let d22 = 1.6099617;
2551    let d23 = 0.00105627;
2552    let d24 = -0.00000343;
2553    let d31 = 0.04833475;
2554    let d32 = 0.00016418;
2555    let d33 = -0.0000004676;
2556    let d34 = -0.0000000017;
2557    let d41 = 1.308736;
2558    let d42 = -0.0056961;
2559    let d43 = 0.0000039;
2560    let d44 = 0.0;
2561    let d51 = 99.443414;
2562    let d52 = 1.01053;
2563    let d53 = 0.00035222;
2564    let d54 = -0.00000851;
2565    let d61 = 5.202561;
2566    let d62 = 196.74;
2567    let d63 = -9.4;
2568
2569    let e11 = 266.564377;
2570    let e12 = 3.398638567;
2571    let e13 = 0.0003245;
2572    let e14 = -0.0000058;
2573    let e21 = 91.098214;
2574    let e22 = 1.9584158;
2575    let e23 = 0.00082636;
2576    let e24 = 0.00000461;
2577    let e31 = 0.05589232;
2578    let e32 = -0.0003455;
2579    let e33 = -0.000000728;
2580    let e34 = 0.00000000074;
2581    let e41 = 2.492519;
2582    let e42 = -0.0039189;
2583    let e43 = -0.00001549;
2584    let e44 = 0.00000004;
2585    let e51 = 112.790414;
2586    let e52 = 0.8731951;
2587    let e53 = -0.00015218;
2588    let e54 = -0.00000531;
2589    let e61 = 9.554747;
2590    let e62 = 165.6;
2591    let e63 = -8.88;
2592
2593    let f11 = 244.19747;
2594    let f12 = 1.194065406;
2595    let f13 = 0.000316;
2596    let f14 = -0.0000006;
2597    let f21 = 171.548692;
2598    let f22 = 1.4844328;
2599    let f23 = 0.0002372;
2600    let f24 = -0.00000061;
2601    let f31 = 0.0463444;
2602    let f32a = -0.00002658;
2603    let f33 = 0.000000077;
2604    let f34 = 0.0;
2605    let f41 = 0.772464;
2606    let f42 = 0.0006253;
2607    let f43 = 0.0000395;
2608    let f44 = 0.0;
2609    let f51 = 73.477111;
2610    let f52 = 0.4986678;
2611    let f53 = 0.0013117;
2612    let f54 = 0.0;
2613    let f61 = 19.21814;
2614    let f62 = 65.8;
2615    let f63 = -7.19;
2616
2617    let g11 = 84.457994;
2618    let g12 = 0.6107942056;
2619    let g13 = 0.0003205;
2620    let g14 = -0.0000006;
2621    let g21 = 46.727364;
2622    let g22 = 1.4245744;
2623    let g23 = 0.00039082;
2624    let g24 = -0.000000605;
2625    let g31 = 0.00899704;
2626    let g32 = 0.00000633;
2627    let g33 = -0.000000002;
2628    let g34 = 0.0;
2629    let g41 = 1.779242;
2630    let g42 = -0.0095436;
2631    let g43 = -0.0000091;
2632    let g44 = 0.0;
2633    let g51 = 130.681389;
2634    let g52 = 1.098935;
2635    let g53 = 0.00024987;
2636    let g54 = -0.000004718;
2637    let g61 = 30.10957;
2638    let g62 = 62.2;
2639    let g63 = -6.87;
2640
2641    let mut pl: Vec<PlDataStruct> = Vec::new();
2642    pl.push(PlDataStruct {
2643        value1: 0.0,
2644        value2: 0.0,
2645        value3: 0.0,
2646        value4: 0.0,
2647        value5: 0.0,
2648        value6: 0.0,
2649        value7: 0.0,
2650        value8: 0.0,
2651        value9: 0.0,
2652    });
2653
2654    let mut ip = 0;
2655    let b = lct_ut(lh, lm, ls, ds, zc, dy, mn, yr);
2656    let gd = lct_gday(lh, lm, ls, ds, zc, dy, mn, yr);
2657    let gm = lct_gmonth(lh, lm, ls, ds, zc, dy, mn, yr);
2658    let gy = lct_gyear(lh, lm, ls, ds, zc, dy, mn, yr);
2659    let a = cd_jd(gd, gm, gy);
2660    let t = ((a - 2415020.0) / 36525.0) + (b / 876600.0);
2661
2662    let u_s = s.to_lowercase();
2663
2664    if u_s == "mercury" {
2665        ip = 1;
2666    }
2667    if u_s == "venus" {
2668        ip = 2;
2669    }
2670    if u_s == "mars" {
2671        ip = 3;
2672    }
2673    if u_s == "jupiter" {
2674        ip = 4;
2675    }
2676    if u_s == "saturn" {
2677        ip = 5;
2678    }
2679    if u_s == "uranus" {
2680        ip = 6;
2681    }
2682    if u_s == "neptune" {
2683        ip = 7;
2684    }
2685    if ip == 0 {
2686        return (
2687            degrees(unwind(0.0)),
2688            degrees(unwind(0.0)),
2689            degrees(unwind(0.0)),
2690            degrees(unwind(0.0)),
2691            degrees(unwind(0.0)),
2692            degrees(unwind(0.0)),
2693            degrees(unwind(0.0)),
2694        );
2695    }
2696
2697    let a0 = a11;
2698    let a1 = a12;
2699    let a2 = a13;
2700    let a3 = a14;
2701    let b0 = a21;
2702    let b1 = a22;
2703    let b2 = a23;
2704    let b3 = a24;
2705    let c0 = a31;
2706    let c1 = a32;
2707    let c2 = a33;
2708    let c3 = a34;
2709    let d0 = a41;
2710    let d1 = a42;
2711    let d2 = a43;
2712    let d3 = a44;
2713    let e0 = a51;
2714    let e1 = a52;
2715    let e2 = a53;
2716    let e3 = a54;
2717    let f = a61;
2718    let g = a62;
2719    let h = a63;
2720    let aa = a1 * t;
2721    let b = 360.0 * (aa - aa.floor());
2722    let c = a0 + b + (a3 * t + a2) * t * t;
2723
2724    pl.push(PlDataStruct {
2725        value1: c - 360.0 * (c / 360.0).floor(),
2726        value2: (a1 * 0.009856263) + (a2 + a3) / 36525.0,
2727        value3: ((b3 * t + b2) * t + b1) * t + b0,
2728        value4: ((c3 * t + c2) * t + c1) * t + c0,
2729        value5: ((d3 * t + d2) * t + d1) * t + d0,
2730        value6: ((e3 * t + e2) * t + e1) * t + e0,
2731        value7: f,
2732        value8: g,
2733        value9: h,
2734    });
2735
2736    let a0 = b11;
2737    let a1 = b12;
2738    let a2 = b13;
2739    let a3 = b14;
2740    let b0 = b21;
2741    let b1 = b22;
2742    let b2 = b23;
2743    let b3 = b24;
2744    let c0 = b31;
2745    let c1 = b32;
2746    let c2 = b33;
2747    let c3 = b34;
2748    let d0 = b41;
2749    let d1 = b42;
2750    let d2 = b43;
2751    let d3 = b44;
2752    let e0 = b51;
2753    let e1 = b52;
2754    let e2 = b53;
2755    let e3 = b54;
2756    let f = b61;
2757    let g = b62;
2758    let h = b63;
2759    let aa = a1 * t;
2760    let b = 360.0 * (aa - (aa).floor());
2761    let c = a0 + b + (a3 * t + a2) * t * t;
2762    pl.push(PlDataStruct {
2763        value1: c - 360.0 * (c / 360.0).floor(),
2764        value2: (a1 * 0.009856263) + (a2 + a3) / 36525.0,
2765        value3: ((b3 * t + b2) * t + b1) * t + b0,
2766        value4: ((c3 * t + c2) * t + c1) * t + c0,
2767        value5: ((d3 * t + d2) * t + d1) * t + d0,
2768        value6: ((e3 * t + e2) * t + e1) * t + e0,
2769        value7: f,
2770        value8: g,
2771        value9: h,
2772    });
2773
2774    let a0 = c11;
2775    let a1 = c12;
2776    let a2 = c13;
2777    let a3 = c14;
2778    let b0 = c21;
2779    let b1 = c22;
2780    let b2 = c23;
2781    let b3 = c24;
2782    let c0 = c31;
2783    let c1 = c32;
2784    let c2 = c33;
2785    let c3 = c34;
2786    let d0 = c41;
2787    let d1 = c42;
2788    let d2 = c43;
2789    let d3 = c44;
2790    let e0 = c51;
2791    let e1 = c52;
2792    let e2 = c53;
2793    let e3 = c54;
2794    let f = c61;
2795    let g = c62;
2796    let h = c63;
2797
2798    let aa = a1 * t;
2799    let b = 360.0 * (aa - (aa).floor());
2800    let c = a0 + b + (a3 * t + a2) * t * t;
2801    pl.push(PlDataStruct {
2802        value1: c - 360.0 * (c / 360.0).floor(),
2803        value2: (a1 * 0.009856263) + (a2 + a3) / 36525.0,
2804        value3: ((b3 * t + b2) * t + b1) * t + b0,
2805        value4: ((c3 * t + c2) * t + c1) * t + c0,
2806        value5: ((d3 * t + d2) * t + d1) * t + d0,
2807        value6: ((e3 * t + e2) * t + e1) * t + e0,
2808        value7: f,
2809        value8: g,
2810        value9: h,
2811    });
2812
2813    let a0 = d11;
2814    let a1 = d12;
2815    let a2 = d13;
2816    let a3 = d14;
2817    let b0 = d21;
2818    let b1 = d22;
2819    let b2 = d23;
2820    let b3 = d24;
2821    let c0 = d31;
2822    let c1 = d32;
2823    let c2 = d33;
2824    let c3 = d34;
2825    let d0 = d41;
2826    let d1 = d42;
2827    let d2 = d43;
2828    let d3 = d44;
2829    let e0 = d51;
2830    let e1 = d52;
2831    let e2 = d53;
2832    let e3 = d54;
2833    let f = d61;
2834    let g = d62;
2835    let h = d63;
2836
2837    let aa = a1 * t;
2838    let b = 360.0 * (aa - (aa).floor());
2839    let c = a0 + b + (a3 * t + a2) * t * t;
2840    pl.push(PlDataStruct {
2841        value1: c - 360.0 * (c / 360.0).floor(),
2842        value2: (a1 * 0.009856263) + (a2 + a3) / 36525.0,
2843        value3: ((b3 * t + b2) * t + b1) * t + b0,
2844        value4: ((c3 * t + c2) * t + c1) * t + c0,
2845        value5: ((d3 * t + d2) * t + d1) * t + d0,
2846        value6: ((e3 * t + e2) * t + e1) * t + e0,
2847        value7: f,
2848        value8: g,
2849        value9: h,
2850    });
2851
2852    let a0 = e11;
2853    let a1 = e12;
2854    let a2 = e13;
2855    let a3 = e14;
2856    let b0 = e21;
2857    let b1 = e22;
2858    let b2 = e23;
2859    let b3 = e24;
2860    let c0 = e31;
2861    let c1 = e32;
2862    let c2 = e33;
2863    let c3 = e34;
2864    let d0 = e41;
2865    let d1 = e42;
2866    let d2 = e43;
2867    let d3 = e44;
2868    let e0 = e51;
2869    let e1 = e52;
2870    let e2 = e53;
2871    let e3 = e54;
2872    let f = e61;
2873    let g = e62;
2874    let h = e63;
2875
2876    let aa = a1 * t;
2877    let b = 360.0 * (aa - (aa).floor());
2878    let c = a0 + b + (a3 * t + a2) * t * t;
2879    pl.push(PlDataStruct {
2880        value1: c - 360.0 * (c / 360.0).floor(),
2881        value2: (a1 * 0.009856263) + (a2 + a3) / 36525.0,
2882        value3: ((b3 * t + b2) * t + b1) * t + b0,
2883        value4: ((c3 * t + c2) * t + c1) * t + c0,
2884        value5: ((d3 * t + d2) * t + d1) * t + d0,
2885        value6: ((e3 * t + e2) * t + e1) * t + e0,
2886        value7: f,
2887        value8: g,
2888        value9: h,
2889    });
2890
2891    let a0 = f11;
2892    let a1 = f12;
2893    let a2 = f13;
2894    let a3 = f14;
2895    let b0 = f21;
2896    let b1 = f22;
2897    let b2 = f23;
2898    let b3 = f24;
2899    let c0 = f31;
2900    let c1 = f32a;
2901    let c2 = f33;
2902    let c3 = f34;
2903    let d0 = f41;
2904    let d1 = f42;
2905    let d2 = f43;
2906    let d3 = f44;
2907    let e0 = f51;
2908    let e1 = f52;
2909    let e2 = f53;
2910    let e3 = f54;
2911    let f = f61;
2912    let g = f62;
2913    let h = f63;
2914
2915    let aa = a1 * t;
2916    let b = 360.0 * (aa - (aa).floor());
2917    let c = a0 + b + (a3 * t + a2) * t * t;
2918    pl.push(PlDataStruct {
2919        value1: c - 360.0 * (c / 360.0).floor(),
2920        value2: (a1 * 0.009856263) + (a2 + a3) / 36525.0,
2921        value3: ((b3 * t + b2) * t + b1) * t + b0,
2922        value4: ((c3 * t + c2) * t + c1) * t + c0,
2923        value5: ((d3 * t + d2) * t + d1) * t + d0,
2924        value6: ((e3 * t + e2) * t + e1) * t + e0,
2925        value7: f,
2926        value8: g,
2927        value9: h,
2928    });
2929
2930    let a0 = g11;
2931    let a1 = g12;
2932    let a2 = g13;
2933    let a3 = g14;
2934    let b0 = g21;
2935    let b1 = g22;
2936    let b2 = g23;
2937    let b3 = g24;
2938    let c0 = g31;
2939    let c1 = g32;
2940    let c2 = g33;
2941    let c3 = g34;
2942    let d0 = g41;
2943    let d1 = g42;
2944    let d2 = g43;
2945    let d3 = g44;
2946    let e0 = g51;
2947    let e1 = g52;
2948    let e2 = g53;
2949    let e3 = g54;
2950    let f = g61;
2951    let g = g62;
2952    let h = g63;
2953
2954    let aa = a1 * t;
2955    let b = 360.0 * (aa - (aa).floor());
2956    let c = a0 + b + (a3 * t + a2) * t * t;
2957    pl.push(PlDataStruct {
2958        value1: c - 360.0 * (c / 360.0).floor(),
2959        value2: (a1 * 0.009856263) + (a2 + a3) / 36525.0,
2960        value3: ((b3 * t + b2) * t + b1) * t + b0,
2961        value4: ((c3 * t + c2) * t + c1) * t + c0,
2962        value5: ((d3 * t + d2) * t + d1) * t + d0,
2963        value6: ((e3 * t + e2) * t + e1) * t + e0,
2964        value7: f,
2965        value8: g,
2966        value9: h,
2967    });
2968
2969    let mut li = 0.0;
2970    let _tp = 2.0 * std::f64::consts::PI;
2971    let ms = sun_mean_anomaly(lh, lm, ls, ds, zc, dy, mn, yr);
2972    let sr = (sun_long(lh, lm, ls, ds, zc, dy, mn, yr)).to_radians();
2973    let re = sun_dist(lh, lm, ls, ds, zc, dy, mn, yr);
2974    let lg = sr + std::f64::consts::PI;
2975
2976    let mut l0 = 0.0;
2977    let _v0 = 0.0;
2978    let mut s0 = 0.0;
2979    let mut p0 = 0.0;
2980    let mut vo = 0.0;
2981    let mut lp1 = 0.0;
2982    let mut ll = 0.0;
2983    let mut rd = 0.0;
2984    let mut pd = 0.0;
2985    let mut sp = 0.0;
2986    let mut ci = 0.0;
2987
2988    for k in 1..3 {
2989        let pl_instance = pl.clone();
2990        let mut ap: Vec<f64> = Vec::new();
2991        ap.push(0.0);
2992        for j in 1..8 {
2993            let pl_loop_instance = pl.clone();
2994
2995            ap.push(
2996                (pl_loop_instance[j as usize].value1
2997                    - pl_loop_instance[j as usize].value3
2998                    - li * pl_loop_instance[j as usize].value2)
2999                    .to_radians(),
3000            );
3001        }
3002
3003        let mut qa = 0.0;
3004        let mut qb = 0.0;
3005        let mut qc = 0.0;
3006        let mut qd = 0.0;
3007        let mut qe = 0.0;
3008        let mut qf = 0.0;
3009        let mut qg = 0.0;
3010        let _a = 0.0;
3011        let _sa = 0.0;
3012        let _ca = 0.0;
3013
3014        if ip == 1 {
3015            let (qa_temp, qb_temp) = planet_long_l4685(ap.clone());
3016            qa = qa_temp;
3017            qb = qb_temp;
3018        }
3019        if ip == 2 {
3020            let (qa_temp, qb_temp, qc_temp, qe_temp) = planet_long_l4735(ap.clone(), ms, t);
3021            qa = qa_temp;
3022            qb = qb_temp;
3023            qc = qc_temp;
3024            qe = qe_temp;
3025        }
3026        if ip == 3 {
3027            let (_a_temp, _sa_temp, _ca_temp, qc_temp, qe_temp, qa_temp, qb_temp) =
3028                planet_long_l4810(ap.clone(), ms);
3029            // a = a_temp;
3030            // sa = sa_temp;
3031            // ca = ca_temp;
3032            qc = qc_temp;
3033            qe = qe_temp;
3034            qa = qa_temp;
3035            qb = qb_temp;
3036        }
3037        if [4, 5, 6, 7].contains(&ip) {
3038            let (qa_temp, qb_temp, qc_temp, qd_temp, qe_temp, qf_temp, qg_temp) =
3039                planet_long_l4945(t, ip, pl_instance.clone());
3040            qa = qa_temp;
3041            qb = qb_temp;
3042            qc = qc_temp;
3043            qd = qd_temp;
3044            qe = qe_temp;
3045            qf = qf_temp;
3046            qg = qg_temp;
3047        }
3048        let ec = pl_instance[ip as usize].value4 + qd;
3049        let am = ap[ip as usize] + qe;
3050        let at = true_anomaly(am, ec);
3051        let pvv =
3052            (pl_instance[ip as usize].value7 + qf) * (1.0 - ec * ec) / (1.0 + ec * (at).cos());
3053        let lp = degrees(at) + pl_instance[ip as usize].value3 + degrees(qc - qe);
3054        let lp = lp.to_radians();
3055        let om = (pl_instance[ip as usize].value6).to_radians();
3056        let lo = lp - om;
3057        let so = (lo).sin();
3058        let co = (lo).cos();
3059        let inn = (pl_instance[ip as usize].value5).to_radians();
3060        let pvv = pvv + qb;
3061        sp = so * (inn).sin();
3062        let y = so * (inn).cos();
3063        let ps = (sp).asin() + qg;
3064        sp = (ps).sin();
3065        pd = y.atan2(co) + om + (qa).to_radians();
3066        pd = unwind(pd);
3067        ci = (ps).cos();
3068        rd = pvv * ci;
3069        ll = pd - lg;
3070        let rh = re * re + pvv * pvv - 2.0 * re * pvv * ci * (ll).cos();
3071        let rh = (rh).sqrt();
3072        li = rh * 0.005775518;
3073
3074        if k == 1 {
3075            l0 = pd;
3076            // v0 = rh;
3077            s0 = ps;
3078            p0 = pvv;
3079            vo = rh;
3080            lp1 = lp;
3081        }
3082    }
3083
3084    let l1 = (ll).sin();
3085    let l2 = (ll).cos();
3086
3087    // let mut ep = 0.0;
3088    let ep: f64;
3089    if ip < 3 {
3090        ep = (-1.0 * rd * l1 / (re - rd * l2)).atan() + lg + std::f64::consts::PI;
3091    } else {
3092        ep = (re * l1 / (rd - re * l2)).atan() + pd
3093    }
3094
3095    let ep = unwind(ep);
3096    let bp = (rd * sp * (ep - pd).sin() / (ci * re * l1)).atan();
3097
3098    let planet_longitude = degrees(unwind(ep));
3099    let planet_latitude = degrees(unwind(bp));
3100    let planet_distance_au = vo;
3101    let planet_h_long1 = degrees(lp1);
3102    let planet_h_long2 = degrees(l0);
3103    let planet_h_lat = degrees(s0);
3104    let planet_r_vect = p0;
3105
3106    return (
3107        planet_longitude,
3108        planet_latitude,
3109        planet_distance_au,
3110        planet_h_long1,
3111        planet_h_long2,
3112        planet_h_lat,
3113        planet_r_vect,
3114    );
3115}
3116
3117/// Helper function for planet_long_lat().
3118pub fn planet_long_l4685(ap: Vec<f64>) -> (f64, f64) {
3119    let qa = 0.00204 * (5.0 * ap[2] - 2.0 * ap[1] + 0.21328).cos();
3120    let qa = qa + 0.00103 * (2.0 * ap[2] - ap[1] - 2.8046).cos();
3121    let qa = qa + 0.00091 * (2.0 * ap[4] - ap[1] - 0.64582).cos();
3122    let qa = qa + 0.00078 * (5.0 * ap[2] - 3.0 * ap[1] + 0.17692).cos();
3123
3124    let qb = 0.000007525 * (2.0 * ap[4] - ap[1] + 0.925251).cos();
3125    let qb = qb + 0.000006802 * (5.0 * ap[2] - 3.0 * ap[1] - 4.53642).cos();
3126    let qb = qb + 0.000005457 * (2.0 * ap[2] - 2.0 * ap[1] - 1.24246).cos();
3127    let qb = qb + 0.000003569 * (5.0 * ap[2] - ap[1] - 1.35699).cos();
3128
3129    return (qa, qb);
3130}
3131
3132/// Helper function for planet_long_lat().
3133pub fn planet_long_l4735(ap: Vec<f64>, ms: f64, t: f64) -> (f64, f64, f64, f64) {
3134    let qc = 0.00077 * (4.1406 + t * 2.6227).sin();
3135    let qc = qc.to_radians();
3136    let qe = qc;
3137
3138    let qa = 0.00313 * (2.0 * ms - 2.0 * ap[2] - 2.587).cos();
3139    let qa = qa + 0.00198 * (3.0 * ms - 3.0 * ap[2] + 0.044768).cos();
3140    let qa = qa + 0.00136 * (ms - ap[2] - 2.0788).cos();
3141    let qa = qa + 0.00096 * (3.0 * ms - 2.0 * ap[2] - 2.3721).cos();
3142    let qa = qa + 0.00082 * (ap[4] - ap[2] - 3.6318).cos();
3143
3144    let qb = 0.000022501 * (2.0 * ms - 2.0 * ap[2] - 1.01592).cos();
3145    let qb = qb + 0.000019045 * (3.0 * ms - 3.0 * ap[2] + 1.61577).cos();
3146    let qb = qb + 0.000006887 * (ap[4] - ap[2] - 2.06106).cos();
3147    let qb = qb + 0.000005172 * (ms - ap[2] - 0.508065).cos();
3148    let qb = qb + 0.00000362 * (5.0 * ms - 4.0 * ap[2] - 1.81877).cos();
3149    let qb = qb + 0.000003283 * (4.0 * ms - 4.0 * ap[2] + 1.10851).cos();
3150    let qb = qb + 0.000003074 * (2.0 * ap[4] - 2.0 * ap[2] - 0.962846).cos();
3151
3152    return (qa, qb, qc, qe);
3153}
3154
3155/// Helper function for planet_long_lat().
3156pub fn planet_long_l4810(ap: Vec<f64>, ms: f64) -> (f64, f64, f64, f64, f64, f64, f64) {
3157    let a = 3.0 * ap[4] - 8.0 * ap[3] + 4.0 * ms;
3158    let sa = a.sin();
3159    let ca = a.cos();
3160    let qc = -(0.01133 * sa + 0.00933 * ca);
3161    let qc = qc.to_radians();
3162    let qe = qc;
3163
3164    let qa = 0.00705 * (ap[4] - ap[3] - 0.85448).cos();
3165    let qa = qa + 0.00607 * (2.0 * ap[4] - ap[3] - 3.2873).cos();
3166    let qa = qa + 0.00445 * (2.0 * ap[4] - 2.0 * ap[3] - 3.3492).cos();
3167    let qa = qa + 0.00388 * (ms - 2.0 * ap[3] + 0.35771).cos();
3168    let qa = qa + 0.00238 * (ms - ap[3] + 0.61256).cos();
3169    let qa = qa + 0.00204 * (2.0 * ms - 3.0 * ap[3] + 2.7688).cos();
3170    let qa = qa + 0.00177 * (3.0 * ap[3] - ap[2] - 1.0053).cos();
3171    let qa = qa + 0.00136 * (2.0 * ms - 4.0 * ap[3] + 2.6894).cos();
3172    let qa = qa + 0.00104 * (ap[4] + 0.30749).cos();
3173
3174    let qb = 0.000053227 * (ap[4] - ap[3] + 0.717864).cos();
3175    let qb = qb + 0.000050989 * (2.0 * ap[4] - 2.0 * ap[3] - 1.77997).cos();
3176    let qb = qb + 0.000038278 * (2.0 * ap[4] - ap[3] - 1.71617).cos();
3177    let qb = qb + 0.000015996 * (ms - ap[3] - 0.969618).cos();
3178    let qb = qb + 0.000014764 * (2.0 * ms - 3.0 * ap[3] + 1.19768).cos();
3179    let qb = qb + 0.000008966 * (ap[4] - 2.0 * ap[3] + 0.761225).cos();
3180    let qb = qb + 0.000007914 * (3.0 * ap[4] - 2.0 * ap[3] - 2.43887).cos();
3181    let qb = qb + 0.000007004 * (2.0 * ap[4] - 3.0 * ap[3] - 1.79573).cos();
3182    let qb = qb + 0.00000662 * (ms - 2.0 * ap[3] + 1.97575).cos();
3183    let qb = qb + 0.00000493 * (3.0 * ap[4] - 3.0 * ap[3] - 1.33069).cos();
3184    let qb = qb + 0.000004693 * (3.0 * ms - 5.0 * ap[3] + 3.32665).cos();
3185    let qb = qb + 0.000004571 * (2.0 * ms - 4.0 * ap[3] + 4.27086).cos();
3186    let qb = qb + 0.000004409 * (3.0 * ap[4] - ap[3] - 2.02158).cos();
3187
3188    return (a, sa, ca, qc, qe, qa, qb);
3189}
3190
3191/// Helper function for planet_long_lat().
3192pub fn planet_long_l4945(
3193    t: f64,
3194    ip: i32,
3195    pl: Vec<PlDataStruct>,
3196) -> (f64, f64, f64, f64, f64, f64, f64) {
3197    let qa = 0.0;
3198    let qb = 0.0;
3199    let qc = 0.0;
3200    let qd = 0.0;
3201    let qe = 0.0;
3202    let qf = 0.0;
3203    let qg = 0.0;
3204
3205    let j1 = t / 5.0 + 0.1;
3206    let j2 = unwind(4.14473 + 52.9691 * t);
3207    let j3 = unwind(4.641118 + 21.32991 * t);
3208    let j4 = unwind(4.250177 + 7.478172 * t);
3209    let j5 = 5.0 * j3 - 2.0 * j2;
3210    let j6 = 2.0 * j2 - 6.0 * j3 + 3.0 * j4;
3211
3212    if [1, 2, 3, 8].contains(&ip) {
3213        return (qa, qb, qc, qd, qe, qf, qg);
3214    }
3215    if [4, 5].contains(&ip) {
3216        let j7 = j3 - j2;
3217        let u1 = (j3).sin();
3218        let u2 = (j3).cos();
3219        let u3 = (2.0 * j3).sin();
3220        let u4 = (2.0 * j3).cos();
3221        let u5 = (j5).sin();
3222        let u6 = (j5).cos();
3223        let u7 = (2.0 * j5).sin();
3224        let u8a = (j6).sin();
3225        let u9 = (j7).sin();
3226        let ua = (j7).cos();
3227        let ub = (2.0 * j7).sin();
3228        let uc = (2.0 * j7).cos();
3229        let ud = (3.0 * j7).sin();
3230        let ue = (3.0 * j7).cos();
3231        let uf = (4.0 * j7).sin();
3232        let ug = (4.0 * j7).cos();
3233        let vh = (5.0 * j7).cos();
3234
3235        if ip == 5 {
3236            let ui = (3.0 * j3).sin();
3237            let uj = (3.0 * j3).cos();
3238            let uk = (4.0 * j3).sin();
3239            let ul = (4.0 * j3).cos();
3240            let vi = (2.0 * j5).cos();
3241            let un = (5.0 * j7).sin();
3242            let j8 = j4 - j3;
3243            let uo = (2.0 * j8).sin();
3244            let up = (2.0 * j8).cos();
3245            let uq = (3.0 * j8).sin();
3246            let ur = (3.0 * j8).cos();
3247
3248            let qc = 0.007581 * u7 - 0.007986 * u8a - 0.148811 * u9;
3249            let qc = qc - (0.814181 - (0.01815 - 0.016714 * j1) * j1) * u5;
3250            let qc = qc - (0.010497 - (0.160906 - 0.0041 * j1) * j1) * u6;
3251            let qc = qc - 0.015208 * ud - 0.006339 * uf - 0.006244 * u1;
3252            let qc = qc - 0.0165 * ub * u1 - 0.040786 * ub;
3253            let qc = qc + (0.008931 + 0.002728 * j1) * u9 * u1 - 0.005775 * ud * u1;
3254            let qc = qc + (0.081344 + 0.003206 * j1) * ua * u1 + 0.015019 * uc * u1;
3255            let qc = qc + (0.085581 + 0.002494 * j1) * u9 * u2 + 0.014394 * uc * u2;
3256            let qc = qc + (0.025328 - 0.003117 * j1) * ua * u2 + 0.006319 * ue * u2;
3257            let qc = qc + 0.006369 * u9 * u3 + 0.009156 * ub * u3 + 0.007525 * uq * u3;
3258            let qc = qc - 0.005236 * ua * u4 - 0.007736 * uc * u4 - 0.007528 * ur * u4;
3259            let qc = qc.to_radians();
3260
3261            let qd = (-7927.0 + (2548.0 + 91.0 * j1) * j1) * u5;
3262            let qd = qd + (13381.0 + (1226.0 - 253.0 * j1) * j1) * u6 + (248.0 - 121.0 * j1) * u7;
3263            let qd = qd - (305.0 + 91.0 * j1) * vi + 412.0 * ub + 12415.0 * u1;
3264            let qd = qd + (390.0 - 617.0 * j1) * u9 * u1 + (165.0 - 204.0 * j1) * ub * u1;
3265            let qd = qd + 26599.0 * ua * u1 - 4687.0 * uc * u1 - 1870.0 * ue * u1 - 821.0 * ug * u1;
3266            let qd = qd - 377.0 * vh * u1 + 497.0 * up * u1 + (163.0 - 611.0 * j1) * u2;
3267            let qd = qd - 12696.0 * u9 * u2 - 4200.0 * ub * u2 - 1503.0 * ud * u2 - 619.0 * uf * u2;
3268            let qd = qd - 268.0 * un * u2 - (282.0 + 1306.0 * j1) * ua * u2;
3269            let qd = qd + (-86.0 + 230.0 * j1) * uc * u2 + 461.0 * uo * u2 - 350.0 * u3;
3270            let qd = qd + (2211.0 - 286.0 * j1) * u9 * u3 - 2208.0 * ub * u3 - 568.0 * ud * u3;
3271            let qd = qd - 346.0 * uf * u3 - (2780.0 + 222.0 * j1) * ua * u3;
3272            let qd = qd + (2022.0 + 263.0 * j1) * uc * u3 + 248.0 * ue * u3 + 242.0 * uq * u3;
3273            let qd = qd + 467.0 * ur * u3 - 490.0 * u4 - (2842.0 + 279.0 * j1) * u9 * u4;
3274            let qd = qd + (128.0 + 226.0 * j1) * ub * u4 + 224.0 * ud * u4;
3275            let qd = qd + (-1594.0 + 282.0 * j1) * ua * u4 + (2162.0 - 207.0 * j1) * uc * u4;
3276            let qd = qd + 561.0 * ue * u4 + 343.0 * ug * u4 + 469.0 * uq * u4 - 242.0 * ur * u4;
3277            let qd = qd - 205.0 * u9 * ui + 262.0 * ud * ui + 208.0 * ua * uj - 271.0 * ue * uj;
3278            let qd = qd - 382.0 * ue * uk - 376.0 * ud * ul;
3279            let qd = qd * 0.0000001;
3280
3281            let vk = (0.077108 + (0.007186 - 0.001533 * j1) * j1) * u5;
3282            let vk = vk - 0.007075 * u9;
3283            let vk = vk + (0.045803 - (0.014766 + 0.000536 * j1) * j1) * u6;
3284            let vk = vk - 0.072586 * u2 - 0.075825 * u9 * u1 - 0.024839 * ub * u1;
3285            let vk = vk - 0.008631 * ud * u1 - 0.150383 * ua * u2;
3286            let vk = vk + 0.026897 * uc * u2 + 0.010053 * ue * u2;
3287            let vk = vk - (0.013597 + 0.001719 * j1) * u9 * u3 + 0.011981 * ub * u4;
3288            let vk = vk - (0.007742 - 0.001517 * j1) * ua * u3;
3289            let vk = vk + (0.013586 - 0.001375 * j1) * uc * u3;
3290            let vk = vk - (0.013667 - 0.001239 * j1) * u9 * u4;
3291            let vk = vk + (0.014861 + 0.001136 * j1) * ua * u4;
3292            let vk = vk - (0.013064 + 0.001628 * j1) * uc * u4;
3293            let qe = qc - ((vk).to_radians() / pl[ip as usize].value4);
3294
3295            let qf = 572.0 * u5 - 1590.0 * ub * u2 + 2933.0 * u6 - 647.0 * ud * u2;
3296            let qf = qf + 33629.0 * ua - 344.0 * uf * u2 - 3081.0 * uc + 2885.0 * ua * u2;
3297            let qf = qf - 1423.0 * ue + (2172.0 + 102.0 * j1) * uc * u2 - 671.0 * ug;
3298            let qf = qf + 296.0 * ue * u2 - 320.0 * vh - 267.0 * ub * u3 + 1098.0 * u1;
3299            let qf = qf - 778.0 * ua * u3 - 2812.0 * u9 * u1 + 495.0 * uc * u3 + 688.0 * ub * u1;
3300            let qf = qf + 250.0 * ue * u3 - 393.0 * ud * u1 - 856.0 * u9 * u4 - 228.0 * uf * u1;
3301            let qf = qf + 441.0 * ub * u4 + 2138.0 * ua * u1 + 296.0 * uc * u4 - 999.0 * uc * u1;
3302            let qf = qf + 211.0 * ue * u4 - 642.0 * ue * u1 - 427.0 * u9 * ui - 325.0 * ug * u1;
3303            let qf = qf + 398.0 * ud * ui - 890.0 * u2 + 344.0 * ua * uj + 2206.0 * u9 * u2;
3304            let qf = qf - 427.0 * ue * uj;
3305            let qf = qf * 0.000001;
3306
3307            let qg = 0.000747 * ua * u1 + 0.001069 * ua * u2 + 0.002108 * ub * u3;
3308            let qg = qg + 0.001261 * uc * u3 + 0.001236 * ub * u4 - 0.002075 * uc * u4;
3309            let qg = qg.to_radians();
3310
3311            return (qa, qb, qc, qd, qe, qf, qg);
3312        }
3313
3314        let qc = (0.331364 - (0.010281 + 0.004692 * j1) * j1) * u5;
3315        let qc = qc + (0.003228 - (0.064436 - 0.002075 * j1) * j1) * u6;
3316        let qc = qc - (0.003083 + (0.000275 - 0.000489 * j1) * j1) * u7;
3317        let qc = qc + 0.002472 * u8a + 0.013619 * u9 + 0.018472 * ub;
3318        let qc = qc + 0.006717 * ud + 0.002775 * uf + 0.006417 * ub * u1;
3319        let qc = qc + (0.007275 - 0.001253 * j1) * u9 * u1 + 0.002439 * ud * u1;
3320        let qc = qc - (0.035681 + 0.001208 * j1) * u9 * u2 - 0.003767 * uc * u1;
3321        let qc = qc - (0.033839 + 0.001125 * j1) * ua * u1 - 0.004261 * ub * u2;
3322        let qc = qc + (0.001161 * j1 - 0.006333) * ua * u2 + 0.002178 * u2;
3323        let qc = qc - 0.006675 * uc * u2 - 0.002664 * ue * u2 - 0.002572 * u9 * u3;
3324        let qc = qc - 0.003567 * ub * u3 + 0.002094 * ua * u4 + 0.003342 * uc * u4;
3325        let qc = qc.to_radians();
3326
3327        let qd = (3606.0 + (130.0 - 43.0 * j1) * j1) * u5 + (1289.0 - 580.0 * j1) * u6;
3328        let qd = qd - 6764.0 * u9 * u1 - 1110.0 * ub * u1 - 224.0 * ud * u1 - 204.0 * u1;
3329        let qd = qd + (1284.0 + 116.0 * j1) * ua * u1 + 188.0 * uc * u1;
3330        let qd = qd + (1460.0 + 130.0 * j1) * u9 * u2 + 224.0 * ub * u2 - 817.0 * u2;
3331        let qd = qd + 6074.0 * u2 * ua + 992.0 * uc * u2 + 508.0 * ue * u2 + 230.0 * ug * u2;
3332        let qd = qd + 108.0 * vh * u2 - (956.0 + 73.0 * j1) * u9 * u3 + 448.0 * ub * u3;
3333        let qd = qd + 137.0 * ud * u3 + (108.0 * j1 - 997.0) * ua * u3 + 480.0 * uc * u3;
3334        let qd = qd + 148.0 * ue * u3 + (99.0 * j1 - 956.0) * u9 * u4 + 490.0 * ub * u4;
3335        let qd = qd + 158.0 * ud * u4 + 179.0 * u4 + (1024.0 + 75.0 * j1) * ua * u4;
3336        let qd = qd - 437.0 * uc * u4 - 132.0 * ue * u4;
3337        let qd = qd * 0.0000001;
3338
3339        let vk = (0.007192 - 0.003147 * j1) * u5 - 0.004344 * u1;
3340        let vk = vk + (j1 * (0.000197 * j1 - 0.000675) - 0.020428) * u6;
3341        let vk = vk + 0.034036 * ua * u1 + (0.007269 + 0.000672 * j1) * u9 * u1;
3342        let vk = vk + 0.005614 * uc * u1 + 0.002964 * ue * u1 + 0.037761 * u9 * u2;
3343        let vk = vk + 0.006158 * ub * u2 - 0.006603 * ua * u2 - 0.005356 * u9 * u3;
3344        let vk = vk + 0.002722 * ub * u3 + 0.004483 * ua * u3;
3345        let vk = vk - 0.002642 * uc * u3 + 0.004403 * u9 * u4;
3346        let vk = vk - 0.002536 * ub * u4 + 0.005547 * ua * u4 - 0.002689 * uc * u4;
3347        let qe = qc - (vk.to_radians() / pl[ip as usize].value4);
3348
3349        let qf = 205.0 * ua - 263.0 * u6 + 693.0 * uc + 312.0 * ue + 147.0 * ug + 299.0 * u9 * u1;
3350        let qf = qf + 181.0 * uc * u1 + 204.0 * ub * u2 + 111.0 * ud * u2 - 337.0 * ua * u2;
3351        let qf = qf - 111.0 * uc * u2;
3352        let qf = qf * 0.000001;
3353
3354        return (qa, qb, qc, qd, qe, qf, qg);
3355    }
3356
3357    if [6, 7].contains(&ip) {
3358        let j8 = unwind(1.46205 + 3.81337 * t);
3359        let j9 = 2.0 * j8 - j4;
3360        let vj = (j9).sin();
3361        let uu = (j9).cos();
3362        let uv = (2.0 * j9).sin();
3363        let uw = (2.0 * j9).cos();
3364
3365        if ip == 7 {
3366            let ja = j8 - j2;
3367            let jb = j8 - j3;
3368            let jc = j8 - j4;
3369            let qc = (0.001089 * j1 - 0.589833) * vj;
3370            let qc = qc + (0.004658 * j1 - 0.056094) * uu - 0.024286 * uv;
3371            let qc = qc.to_radians();
3372
3373            let vk = 0.024039 * vj - 0.025303 * uu + 0.006206 * uv;
3374            let vk = vk - 0.005992 * uw;
3375            let qe = qc - (vk.to_radians() / pl[ip as usize].value4);
3376
3377            let qd = 4389.0 * vj + 1129.0 * uv + 4262.0 * uu + 1089.0 * uw;
3378            let qd = qd * 0.0000001;
3379
3380            let qf = 8189.0 * uu - 817.0 * vj + 781.0 * uw;
3381            let qf = qf * 0.000001;
3382
3383            let vd = (2.0 * jc).sin();
3384            let ve = (2.0 * jc).cos();
3385            let vf = (j8).sin();
3386            let vg = (j8).cos();
3387            let qa = -0.009556 * (ja).sin() - 0.005178 * (jb).sin();
3388            let qa = qa + 0.002572 * vd - 0.002972 * ve * vf - 0.002833 * vd * vg;
3389
3390            let qg = 0.000336 * ve * vf + 0.000364 * vd * vg;
3391            let qg = qg.to_radians();
3392
3393            let qb = -40596.0 + 4992.0 * (ja).cos() + 2744.0 * (jb).cos();
3394            let qb = qb + 2044.0 * (jc).cos() + 1051.0 * ve;
3395            let qb = qb * 0.000001;
3396
3397            return (qa, qb, qc, qd, qe, qf, qg);
3398        }
3399
3400        let ja = j4 - j2;
3401        let jb = j4 - j3;
3402        let jc = j8 - j4;
3403        let qc = (0.864319 - 0.001583 * j1) * vj;
3404        let qc = qc + (0.082222 - 0.006833 * j1) * uu + 0.036017 * uv;
3405        let qc = qc - 0.003019 * uw + 0.008122 * (j6).sin();
3406        let qc = qc.to_radians();
3407
3408        let vk = 0.120303 * vj + 0.006197 * uv;
3409        let vk = vk + (0.019472 - 0.000947 * j1) * uu;
3410        let qe = qc - ((vk).to_radians() / pl[ip as usize].value4);
3411
3412        let qd = (163.0 * j1 - 3349.0) * vj + 20981.0 * uu + 1311.0 * uw;
3413        let qd = qd * 0.0000001;
3414
3415        let qf = -0.003825 * uu;
3416
3417        let qa = (-0.038581 + (0.002031 - 0.00191 * j1) * j1) * (j4 + jb).cos();
3418        let qa = qa + (0.010122 - 0.000988 * j1) * (j4 + jb).sin();
3419        let a = (0.034964 - (0.001038 - 0.000868 * j1) * j1) * (2.0 * j4 + jb).cos();
3420        let qa = a + qa + 0.005594 * (j4 + 3.0 * jc).sin() - 0.014808 * (ja).sin();
3421        let qa = qa - 0.005794 * (jb).sin() + 0.002347 * (jb).cos();
3422        let qa = qa + 0.009872 * (jc).sin() + 0.008803 * (2.0 * jc).sin();
3423        let qa = qa - 0.004308 * (3.0 * jc).sin();
3424
3425        let ux = jb.sin();
3426        let uy = jb.cos();
3427        let uz = j4.sin();
3428        let va = j4.cos();
3429        let vb = (2.0 * j4).sin();
3430        let vc = (2.0 * j4).cos();
3431        let qg = (0.000458 * ux - 0.000642 * uy - 0.000517 * (4.0 * jc).cos()) * uz;
3432        let qg = qg - (0.000347 * ux + 0.000853 * uy + 0.000517 * (4.0 * jb).sin()) * va;
3433        let qg = qg + 0.000403 * ((2.0 * jc).cos() * vb + (2.0 * jc).sin() * vc);
3434        let qg = qg.to_radians();
3435
3436        let qb = -25948.0 + 4985.0 * (ja).cos() - 1230.0 * va + 3354.0 * uy;
3437        let qb = qb + 904.0 * (2.0 * jc).cos() + 894.0 * ((jc).cos() - (3.0 * jc).cos());
3438        let qb = qb + (5795.0 * va - 1165.0 * uz + 1388.0 * vc) * ux;
3439        let qb = qb + (1351.0 * va + 5702.0 * uz + 1388.0 * vb) * uy;
3440        let qb = qb * 0.000001;
3441
3442        return (qa, qb, qc, qd, qe, qf, qg);
3443    }
3444
3445    return (qa, qb, qc, qd, qe, qf, qg);
3446}
3447
3448/// For W, in radians, return S, also in radians.
3449///
3450/// Original macro name: SolveCubic
3451pub fn solve_cubic(w: f64) -> f64 {
3452    let mut s = w / 3.0;
3453
3454    while 1 == 1 {
3455        let s2 = s * s;
3456        let d = (s2 + 3.0) * s - w;
3457
3458        if d.abs() < 0.000001 {
3459            return s;
3460        }
3461
3462        s = ((2.0 * s * s2) + w) / (3.0 * (s2 + 1.0));
3463    }
3464
3465    return s;
3466}
3467
3468/// Calculate longitude, latitude, and distance of parabolic-orbit comet.
3469///
3470/// Original macro names: PcometLong, PcometLat, PcometDist
3471///
3472/// ## Arguments
3473/// * `lh` -- Local civil time, hour part
3474/// * `lm` -- Local civil time, minutes part
3475/// * `ls` -- Local civil time, seconds part
3476/// * `ds` -- Daylight Savings offset
3477/// * `zc` -- Time zone correction, in hours
3478/// * `dy` -- Local date, day part
3479/// * `mn` -- Local date, month part
3480/// * `yr` -- Local date, year part
3481/// * `td` -- Perihelion epoch (day)
3482/// * `tm` -- Perihelion epoch (month)
3483/// * `ty` -- Perihelion epoch (year)
3484/// * `q` -- q (AU)
3485/// * `i` -- Inclination (degrees)
3486/// * `p` -- Perihelion (degrees)
3487/// * `n` -- Node (degrees)
3488///
3489/// ## Returns
3490/// * `comet_long_deg` -- Comet longitude (degrees)
3491/// * `comet_lat_deg` -- Comet lat (degrees)
3492/// * `comet_dist_au` -- Comet distance from Earth (AU)
3493pub fn p_comet_long_lat_dist(
3494    lh: f64,
3495    lm: f64,
3496    ls: f64,
3497    ds: i32,
3498    zc: i32,
3499    dy: f64,
3500    mn: u32,
3501    yr: u32,
3502    td: f64,
3503    tm: u32,
3504    ty: u32,
3505    q: f64,
3506    i: f64,
3507    p: f64,
3508    n: f64,
3509) -> (f64, f64, f64) {
3510    let gd = lct_gday(lh, lm, ls, ds, zc, dy, mn, yr);
3511    let gm = lct_gmonth(lh, lm, ls, ds, zc, dy, mn, yr);
3512    let gy = lct_gyear(lh, lm, ls, ds, zc, dy, mn, yr);
3513    let ut = lct_ut(lh, lm, ls, ds, zc, dy, mn, yr);
3514    let tpe = (ut / 365.242191) + cd_jd(gd, gm, gy) - cd_jd(td, tm, ty);
3515    let lg = (sun_long(lh, lm, ls, ds, zc, dy, mn, yr) + 180.0).to_radians();
3516    let re = sun_dist(lh, lm, ls, ds, zc, dy, mn, yr);
3517
3518    let mut _li = 0.0;
3519    let mut rh2 = 0.0;
3520    let mut rd = 0.0;
3521    let mut s3 = 0.0;
3522    let mut c3 = 0.0;
3523    let mut lc = 0.0;
3524    let mut s2 = 0.0;
3525    let mut c2 = 0.0;
3526    for k in 1..3 {
3527        let s = solve_cubic(0.0364911624 * tpe / (q * (q).sqrt()));
3528        let nu = 2.0 * s.atan();
3529        let r = q * (1.0 + s * s);
3530        let l = nu + p.to_radians();
3531        let s1 = l.sin();
3532        let c1 = l.cos();
3533        let i1 = i.to_radians();
3534        s2 = s1 * i1.sin();
3535        let ps = s2.asin();
3536        let y = s1 * i1.cos();
3537        lc = y.atan2(c1) + n.to_radians();
3538        c2 = ps.cos();
3539        rd = r * c2;
3540        let ll = lc - lg;
3541        c3 = ll.cos();
3542        s3 = ll.sin();
3543        let rh = ((re * re) + (r * r) - (2.0 * re * rd * c3 * (ps).cos())).sqrt();
3544        if k == 1 {
3545            rh2 = ((re * re) + (r * r)
3546                - (2.0 * re * r * (ps).cos() * (l + (n).to_radians() - lg).cos()))
3547            .sqrt();
3548        }
3549
3550        _li = rh * 0.005775518;
3551    }
3552
3553    let mut ep: f64;
3554    if rd < re {
3555        ep = ((-rd * s3) / (re - (rd * c3))).atan() + lg + 3.141592654;
3556    } else {
3557        ep = ((re * s3) / (rd - (re * c3))).atan() + lc;
3558    }
3559
3560    ep = unwind(ep);
3561    let tb = (rd * s2 * (ep - lc).sin()) / (c2 * re * s3);
3562    let bp = (tb).atan();
3563
3564    let comet_long_deg = degrees(ep);
3565    let comet_lat_deg = degrees(bp);
3566    let comet_dist_au = rh2;
3567
3568    return (comet_long_deg, comet_lat_deg, comet_dist_au);
3569}
3570
3571/// Calculate longitude, latitude, and horizontal parallax of the Moon.
3572///
3573/// Original macro names: MoonLong, MoonLat, MoonHP
3574///
3575/// ## Arguments
3576/// * `lh` -- Local civil time, hour part
3577/// * `lm` -- Local civil time, minutes part
3578/// * `ls` -- Local civil time, seconds part
3579/// * `ds` -- Daylight Savings offset
3580/// * `zc` -- Time zone correction, in hours
3581/// * `dy` -- Local date, day part
3582/// * `mn` -- Local date, month part
3583/// * `yr` -- Local date, year part
3584///
3585/// ## Returns
3586/// * `moon_long_deg` -- Moon longitude (degrees)
3587/// * `moon_lat_deg` -- Moon latitude (degrees)
3588/// * `moon_hor_para` -- Moon horizontal parallax (degrees)
3589pub fn moon_long_lat_hp(
3590    lh: f64,
3591    lm: f64,
3592    ls: f64,
3593    ds: i32,
3594    zc: i32,
3595    dy: f64,
3596    mn: u32,
3597    yr: u32,
3598) -> (f64, f64, f64) {
3599    let ut = lct_ut(lh, lm, ls, ds, zc, dy, mn, yr);
3600    let gd = lct_gday(lh, lm, ls, ds, zc, dy, mn, yr);
3601    let gm = lct_gmonth(lh, lm, ls, ds, zc, dy, mn, yr);
3602    let gy = lct_gyear(lh, lm, ls, ds, zc, dy, mn, yr);
3603    let t = ((cd_jd(gd, gm, gy) - 2415020.0) / 36525.0) + (ut / 876600.0);
3604    let t2 = t * t;
3605
3606    let m1 = 27.32158213;
3607    let m2 = 365.2596407;
3608    let m3 = 27.55455094;
3609    let m4 = 29.53058868;
3610    let m5 = 27.21222039;
3611    let m6 = 6798.363307;
3612    let q = cd_jd(gd, gm, gy) - 2415020.0 + (ut / 24.0);
3613    let m1 = q / m1;
3614    let m2 = q / m2;
3615    let m3 = q / m3;
3616    let m4 = q / m4;
3617    let m5 = q / m5;
3618    let m6 = q / m6;
3619    let m1 = 360.0 * (m1 - m1.floor());
3620    let m2 = 360.0 * (m2 - m2.floor());
3621    let m3 = 360.0 * (m3 - m3.floor());
3622    let m4 = 360.0 * (m4 - m4.floor());
3623    let m5 = 360.0 * (m5 - m5.floor());
3624    let m6 = 360.0 * (m6 - m6.floor());
3625
3626    let ml = 270.434164 + m1 - (0.001133 - 0.0000019 * t) * t2;
3627    let ms = 358.475833 + m2 - (0.00015 + 0.0000033 * t) * t2;
3628    let md = 296.104608 + m3 + (0.009192 + 0.0000144 * t) * t2;
3629    let me1 = 350.737486 + m4 - (0.001436 - 0.0000019 * t) * t2;
3630    let mf = 11.250889 + m5 - (0.003211 + 0.0000003 * t) * t2;
3631    let na = 259.183275 - m6 + (0.002078 + 0.0000022 * t) * t2;
3632    let a = (51.2 + 20.2 * t).to_radians();
3633    let s1 = a.sin();
3634    let s2 = na.to_radians().sin();
3635    let b = 346.56 + (132.87 - 0.0091731 * t) * t;
3636    let s3 = 0.003964 * b.to_radians().sin();
3637    let c = (na + 275.05 - 2.3 * t).to_radians();
3638    let s4 = c.sin();
3639    let ml = ml + 0.000233 * s1 + s3 + 0.001964 * s2;
3640    let ms = ms - 0.001778 * s1;
3641    let md = md + 0.000817 * s1 + s3 + 0.002541 * s2;
3642    let mf = mf + s3 - 0.024691 * s2 - 0.004328 * s4;
3643    let me1 = me1 + 0.002011 * s1 + s3 + 0.001964 * s2;
3644    let e = 1.0 - (0.002495 + 0.00000752 * t) * t;
3645    let e2 = e * e;
3646    let ml = ml.to_radians();
3647    let ms = ms.to_radians();
3648    let na = na.to_radians();
3649    let me1 = me1.to_radians();
3650    let mf = mf.to_radians();
3651    let md = md.to_radians();
3652
3653    // Longitude-specific
3654    let l = 6.28875 * md.sin() + 1.274018 * (2.0 * me1 - md).sin();
3655    let l = l + 0.658309 * (2.0 * me1).sin() + 0.213616 * (2.0 * md).sin();
3656    let l = l - e * 0.185596 * ms.sin() - 0.114336 * (2.0 * mf).sin();
3657    let l = l + 0.058793 * (2.0 * (me1 - md)).sin();
3658    let l = l + 0.057212 * e * (2.0 * me1 - ms - md).sin() + 0.05332 * (2.0 * me1 + md).sin();
3659    let l = l + 0.045874 * e * (2.0 * me1 - ms).sin() + 0.041024 * e * (md - ms).sin();
3660    let l = l - 0.034718 * me1.sin() - e * 0.030465 * (ms + md).sin();
3661    let l = l + 0.015326 * (2.0 * (me1 - mf)).sin() - 0.012528 * (2.0 * mf + md).sin();
3662    let l = l - 0.01098 * (2.0 * mf - md).sin() + 0.010674 * (4.0 * me1 - md).sin();
3663    let l = l + 0.010034 * (3.0 * md).sin() + 0.008548 * (4.0 * me1 - 2.0 * md).sin();
3664    let l = l - e * 0.00791 * (ms - md + 2.0 * me1).sin() - e * 0.006783 * (2.0 * me1 + ms).sin();
3665    let l = l + 0.005162 * (md - me1).sin() + e * 0.005 * (ms + me1).sin();
3666    let l = l + 0.003862 * (4.0 * me1).sin() + e * 0.004049 * (md - ms + 2.0 * me1).sin();
3667    let l = l + 0.003996 * (2.0 * (md + me1)).sin() + 0.003665 * (2.0 * me1 - 3.0 * md).sin();
3668    let l = l + e * 0.002695 * (2.0 * md - ms).sin() + 0.002602 * (md - 2.0 * (mf + me1)).sin();
3669    let l = l + e * 0.002396 * (2.0 * (me1 - md) - ms).sin() - 0.002349 * (md + me1).sin();
3670    let l = l + e2 * 0.002249 * (2.0 * (me1 - ms)).sin() - e * 0.002125 * (2.0 * md + ms).sin();
3671    let l = l - e2 * 0.002079 * (2.0 * ms).sin() + e2 * 0.002059 * (2.0 * (me1 - ms) - md).sin();
3672    let l = l - 0.001773 * (md + 2.0 * (me1 - mf)).sin() - 0.001595 * (2.0 * (mf + me1)).sin();
3673    let l = l + e * 0.00122 * (4.0 * me1 - ms - md).sin() - 0.00111 * (2.0 * (md + mf)).sin();
3674    let l = l + 0.000892 * (md - 3.0 * me1).sin() - e * 0.000811 * (ms + md + 2.0 * me1).sin();
3675    let l = l + e * 0.000761 * (4.0 * me1 - ms - 2.0 * md).sin();
3676    let l = l + e2 * 0.000704 * (md - 2.0 * (ms + me1)).sin();
3677    let l = l + e * 0.000693 * (ms - 2.0 * (md - me1)).sin();
3678    let l = l + e * 0.000598 * (2.0 * (me1 - mf) - ms).sin();
3679    let l = l + 0.00055 * (md + 4.0 * me1).sin() + 0.000538 * (4.0 * md).sin();
3680    let l = l + e * 0.000521 * (4.0 * me1 - ms).sin() + 0.000486 * (2.0 * md - me1).sin();
3681    let l = l + e2 * 0.000717 * (md - 2.0 * ms).sin();
3682    let mm = unwind(ml + l.to_radians());
3683
3684    // Latitude-specific
3685    let g = 5.128189 * mf.sin() + 0.280606 * (md + mf).sin();
3686    let g = g + 0.277693 * (md - mf).sin() + 0.173238 * (2.0 * me1 - mf).sin();
3687    let g = g + 0.055413 * (2.0 * me1 + mf - md).sin() + 0.046272 * (2.0 * me1 - mf - md).sin();
3688    let g = g + 0.032573 * (2.0 * me1 + mf).sin() + 0.017198 * (2.0 * md + mf).sin();
3689    let g = g + 0.009267 * (2.0 * me1 + md - mf).sin() + 0.008823 * (2.0 * md - mf).sin();
3690    let g =
3691        g + e * 0.008247 * (2.0 * me1 - ms - mf).sin() + 0.004323 * (2.0 * (me1 - md) - mf).sin();
3692    let g = g + 0.0042 * (2.0 * me1 + mf + md).sin() + e * 0.003372 * (mf - ms - 2.0 * me1).sin();
3693    let g = g + e * 0.002472 * (2.0 * me1 + mf - ms - md).sin();
3694    let g = g + e * 0.002222 * (2.0 * me1 + mf - ms).sin();
3695    let g = g + e * 0.002072 * (2.0 * me1 - mf - ms - md).sin();
3696    let g = g + e * 0.001877 * (mf - ms + md).sin() + 0.001828 * (4.0 * me1 - mf - md).sin();
3697    let g = g - e * 0.001803 * (mf + ms).sin() - 0.00175 * (3.0 * mf).sin();
3698    let g = g + e * 0.00157 * (md - ms - mf).sin() - 0.001487 * (mf + me1).sin();
3699    let g = g - e * 0.001481 * (mf + ms + md).sin() + e * 0.001417 * (mf - ms - md).sin();
3700    let g = g + e * 0.00135 * (mf - ms).sin() + 0.00133 * (mf - me1).sin();
3701    let g = g + 0.001106 * (mf + 3.0 * md).sin() + 0.00102 * (4.0 * me1 - mf).sin();
3702    let g = g + 0.000833 * (mf + 4.0 * me1 - md).sin() + 0.000781 * (md - 3.0 * mf).sin();
3703    let g =
3704        g + 0.00067 * (mf + 4.0 * me1 - 2.0 * md).sin() + 0.000606 * (2.0 * me1 - 3.0 * mf).sin();
3705    let g = g + 0.000597 * (2.0 * (me1 + md) - mf).sin();
3706    let g = g
3707        + e * 0.000492 * (2.0 * me1 + md - ms - mf).sin()
3708        + 0.00045 * (2.0 * (md - me1) - mf).sin();
3709    let g = g + 0.000439 * (3.0 * md - mf).sin() + 0.000423 * (mf + 2.0 * (me1 + md)).sin();
3710    let g = g + 0.000422 * (2.0 * me1 - mf - 3.0 * md).sin()
3711        - e * 0.000367 * (ms + mf + 2.0 * me1 - md).sin();
3712    let g = g - e * 0.000353 * (ms + mf + 2.0 * me1).sin() + 0.000331 * (mf + 4.0 * me1).sin();
3713    let g = g + e * 0.000317 * (2.0 * me1 + mf - ms + md).sin();
3714    let g = g + e2 * 0.000306 * (2.0 * (me1 - ms) - mf).sin() - 0.000283 * (md + 3.0 * mf).sin();
3715    let w1 = 0.0004664 * na.cos();
3716    let w2 = 0.0000754 * c.cos();
3717    let bm = g.to_radians() * (1.0 - w1 - w2);
3718
3719    // Horizontal parallax-specific
3720    let pm = 0.950724 + 0.051818 * md.cos() + 0.009531 * (2.0 * me1 - md).cos();
3721    let pm = pm + 0.007843 * (2.0 * me1).cos() + 0.002824 * (2.0 * md).cos();
3722    let pm = pm + 0.000857 * (2.0 * me1 + md).cos() + e * 0.000533 * (2.0 * me1 - ms).cos();
3723    let pm = pm + e * 0.000401 * (2.0 * me1 - md - ms).cos();
3724    let pm = pm + e * 0.00032 * (md - ms).cos() - 0.000271 * me1.cos();
3725    let pm = pm - e * 0.000264 * (ms + md).cos() - 0.000198 * (2.0 * mf - md).cos();
3726    let pm = pm + 0.000173 * (3.0 * md).cos() + 0.000167 * (4.0 * me1 - md).cos();
3727    let pm = pm - e * 0.000111 * ms.cos() + 0.000103 * (4.0 * me1 - 2.0 * md).cos();
3728    let pm = pm - 0.000084 * (2.0 * md - 2.0 * me1).cos() - e * 0.000083 * (2.0 * me1 + ms).cos();
3729    let pm = pm + 0.000079 * (2.0 * me1 + 2.0 * md).cos() + 0.000072 * (4.0 * me1).cos();
3730    let pm = pm + e * 0.000064 * (2.0 * me1 - ms + md).cos()
3731        - e * 0.000063 * (2.0 * me1 + ms - md).cos();
3732    let pm = pm + e * 0.000041 * (ms + me1).cos() + e * 0.000035 * (2.0 * md - ms).cos();
3733    let pm = pm - 0.000033 * (3.0 * md - 2.0 * me1).cos() - 0.00003 * (md + me1).cos();
3734    let pm = pm - 0.000029 * (2.0 * (mf - me1)).cos() - e * 0.000029 * (2.0 * md + ms).cos();
3735    let pm =
3736        pm + e2 * 0.000026 * (2.0 * (me1 - ms)).cos() - 0.000023 * (2.0 * (mf - me1) + md).cos();
3737    let pm = pm + e * 0.000019 * (4.0 * me1 - ms - md).cos();
3738
3739    let moon_long_deg = degrees(mm);
3740    let moon_lat_deg = degrees(bm);
3741    let moon_hor_para = pm;
3742
3743    return (moon_long_deg, moon_lat_deg, moon_hor_para);
3744}
3745
3746/// Calculate current phase of Moon.
3747///
3748/// Original macro name: MoonPhase
3749pub fn moon_phase(lh: f64, lm: f64, ls: f64, ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
3750    let (moon_long_deg, moon_lat_deg, _moon_hor_para) =
3751        moon_long_lat_hp(lh, lm, ls, ds, zc, dy, mn, yr);
3752
3753    let cd = ((moon_long_deg - sun_long(lh, lm, ls, ds, zc, dy, mn, yr)).to_radians()).cos()
3754        * ((moon_lat_deg).to_radians()).cos();
3755    let d = cd.acos();
3756    let sd = d.sin();
3757    let i =
3758        0.1468 * sd * (1.0 - 0.0549 * (moon_mean_anomaly(lh, lm, ls, ds, zc, dy, mn, yr)).sin());
3759    let i = i / (1.0 - 0.0167 * (sun_mean_anomaly(lh, lm, ls, ds, zc, dy, mn, yr)).sin());
3760    let i = 3.141592654 - d - i.to_radians();
3761    let k = (1.0 + (i).cos()) / 2.0;
3762
3763    return pa_u::round_f64(k, 2);
3764}
3765
3766/// Calculate the Moon's mean anomaly.
3767///
3768/// Original macro name: MoonMeanAnomaly
3769pub fn moon_mean_anomaly(
3770    lh: f64,
3771    lm: f64,
3772    ls: f64,
3773    ds: i32,
3774    zc: i32,
3775    dy: f64,
3776    mn: u32,
3777    yr: u32,
3778) -> f64 {
3779    let ut = lct_ut(lh, lm, ls, ds, zc, dy, mn, yr);
3780    let gd = lct_gday(lh, lm, ls, ds, zc, dy, mn, yr);
3781    let gm = lct_gmonth(lh, lm, ls, ds, zc, dy, mn, yr);
3782    let gy = lct_gyear(lh, lm, ls, ds, zc, dy, mn, yr);
3783    let t = ((cd_jd(gd, gm, gy) - 2415020.0) / 36525.0) + (ut / 876600.0);
3784    let t2 = t * t;
3785
3786    let m1 = 27.32158213;
3787    let m2 = 365.2596407;
3788    let m3 = 27.55455094;
3789    let m4 = 29.53058868;
3790    let m5 = 27.21222039;
3791    let m6 = 6798.363307;
3792    let q = cd_jd(gd, gm, gy) - 2415020.0 + (ut / 24.0);
3793    let m1 = q / m1;
3794    let m2 = q / m2;
3795    let m3 = q / m3;
3796    let m4 = q / m4;
3797    let m5 = q / m5;
3798    let m6 = q / m6;
3799    let m1 = 360.0 * (m1 - m1.floor());
3800    let m2 = 360.0 * (m2 - m2.floor());
3801    let m3 = 360.0 * (m3 - m3.floor());
3802    let m4 = 360.0 * (m4 - m4.floor());
3803    let m5 = 360.0 * (m5 - m5.floor());
3804    let m6 = 360.0 * (m6 - m6.floor());
3805
3806    let ml = 270.434164 + m1 - (0.001133 - 0.0000019 * t) * t2;
3807    let ms = 358.475833 + m2 - (0.00015 + 0.0000033 * t) * t2;
3808    let md = 296.104608 + m3 + (0.009192 + 0.0000144 * t) * t2;
3809    let _me1 = 350.737486 + m4 - (0.001436 - 0.0000019 * t) * t2;
3810    let _mf = 11.250889 + m5 - (0.003211 + 0.0000003 * t) * t2;
3811    let na = 259.183275 - m6 + (0.002078 + 0.0000022 * t) * t2;
3812    let a = (51.2 + 20.2 * t).to_radians();
3813    let s1 = a.sin();
3814    let s2 = na.to_radians().sin();
3815    let b = 346.56 + (132.87 - 0.0091731 * t) * t;
3816    let s3 = 0.003964 * b.to_radians().sin();
3817    let c = (na + 275.05 - 2.3 * t).to_radians();
3818    let _s4 = c.sin();
3819    let _ml = ml + 0.000233 * s1 + s3 + 0.001964 * s2;
3820    let _ms = ms - 0.001778 * s1;
3821    let md = md + 0.000817 * s1 + s3 + 0.002541 * s2;
3822
3823    return md.to_radians();
3824}
3825
3826/// Calculate Julian date of New Moon.
3827///
3828/// Original macro name: NewMoon
3829///
3830/// ## Arguments
3831/// * `ds` -- Daylight Savings offset
3832/// * `zc` -- Time zone correction, in hours
3833/// * `dy` -- Local date, day part
3834/// * `mn` -- Local date, month part
3835/// * `yr` -- Local date, year part
3836pub fn new_moon(ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
3837    let d0 = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
3838    let m0 = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
3839    let y0 = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
3840
3841    /*  Irrelevant, because of the typing on y0
3842    if y0 < 0 {
3843        y0 = y0 + 1;
3844    }
3845    */
3846
3847    let j0 = cd_jd(0.0, 1, y0) - 2415020.0;
3848    let dj = cd_jd(d0, m0, y0) - 2415020.0;
3849    let k = lint(((y0 as f64 - 1900.0 + ((dj - j0) / 365.0)) * 12.3685) + 0.5);
3850    let tn = k / 1236.85;
3851    let tf = (k + 0.5) / 1236.85;
3852    let t = tn;
3853    let (a, b, f) = new_moon_full_moon_l6855(k, t);
3854    let ni = a;
3855    let nf = b;
3856    let _nb = f;
3857    let t = tf;
3858    let k = k + 0.5;
3859    let (a, b, f) = new_moon_full_moon_l6855(k, t);
3860    let _fi = a;
3861    let _ff = b;
3862    let _fb = f;
3863
3864    return ni + 2415020.0 + nf;
3865}
3866
3867/// Calculate Julian date of Full Moon.
3868///
3869/// Original macro name: FullMoon
3870///
3871/// ## Arguments
3872/// * `ds` -- Daylight Savings offset
3873/// * `zc` -- Time zone correction, in hours
3874/// * `dy` -- Local date, day part
3875/// * `mn` -- Local date, month part
3876/// * `yr` -- Local date, year part
3877pub fn full_moon(ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> f64 {
3878    let d0 = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
3879    let m0 = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
3880    let y0 = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
3881
3882    /*  Irrelevant, because of the typing on y0
3883    if y0 < 0 {
3884        y0 = y0 + 1;
3885    }
3886    */
3887
3888    let j0 = cd_jd(0.0, 1, y0) - 2415020.0;
3889    let dj = cd_jd(d0, m0, y0) - 2415020.0;
3890    let k = lint(((y0 as f64 - 1900.0 + ((dj - j0) / 365.0)) * 12.3685) + 0.5);
3891    let tn = k / 1236.85;
3892    let tf = (k + 0.5) / 1236.85;
3893    let t = tn;
3894    let (a, b, f) = new_moon_full_moon_l6855(k, t);
3895    let _ni = a;
3896    let _nf = b;
3897    let _nb = f;
3898    let t = tf;
3899    let k = k + 0.5;
3900    let (a, b, f) = new_moon_full_moon_l6855(k, t);
3901    let fi = a;
3902    let ff = b;
3903    let _fb = f;
3904
3905    return fi + 2415020.0 + ff;
3906}
3907
3908/// Helper function for new_moon() and full_moon()
3909pub fn new_moon_full_moon_l6855(k: f64, t: f64) -> (f64, f64, f64) {
3910    let t2 = t * t;
3911    let e = 29.53 * k;
3912    let c = 166.56 + (132.87 - 0.009173 * t) * t;
3913    let c = c.to_radians();
3914    let b = 0.00058868 * k + (0.0001178 - 0.000000155 * t) * t2;
3915    let b = b + 0.00033 * c.sin() + 0.75933;
3916    let a = k / 12.36886;
3917    let a1 = 359.2242 + 360.0 * fract(a) - (0.0000333 + 0.00000347 * t) * t2;
3918    let a2 = 306.0253 + 360.0 * fract(k / 0.9330851);
3919    let a2 = a2 + (0.0107306 + 0.00001236 * t) * t2;
3920    let a = k / 0.9214926;
3921    let f = 21.2964 + 360.0 * fract(a) - (0.0016528 + 0.00000239 * t) * t2;
3922    let a1 = unwind_deg(a1);
3923    let a2 = unwind_deg(a2);
3924    let f = unwind_deg(f);
3925    let a1 = a1.to_radians();
3926    let a2 = a2.to_radians();
3927    let f = f.to_radians();
3928
3929    let dd = (0.1734 - 0.000393 * t) * a1.sin() + 0.0021 * (2.0 * a1).sin();
3930    let dd = dd - 0.4068 * a2.sin() + 0.0161 * (2.0 * a2).sin() - 0.0004 * (3.0 * a2).sin();
3931    let dd = dd + 0.0104 * (2.0 * f).sin() - 0.0051 * (a1 + a2).sin();
3932    let dd = dd - 0.0074 * (a1 - a2).sin() + 0.0004 * (2.0 * f + a1).sin();
3933    let dd = dd - 0.0004 * (2.0 * f - a1).sin() - 0.0006 * (2.0 * f + a2).sin()
3934        + 0.001 * (2.0 * f - a2).sin();
3935    let dd = dd + 0.0005 * (a1 + 2.0 * a2).sin();
3936    let e1 = e.floor();
3937    let b = b + dd + (e - e1);
3938    let b1 = b.floor();
3939    let a = e1 + b1;
3940    let b = b - b1;
3941
3942    return (a, b, f);
3943}
3944
3945/// Original macro name: FRACT
3946pub fn fract(w: f64) -> f64 {
3947    return w - lint(w);
3948}
3949
3950/// Original macro name: LINT
3951pub fn lint(w: f64) -> f64 {
3952    return iint(w) + iint(((1.0 * sgn(w)) - 1.0) / 2.0);
3953}
3954
3955/// Original macro name: IINT
3956pub fn iint(w: f64) -> f64 {
3957    return sgn(w) * w.abs().floor();
3958}
3959
3960/// Calculate sign of number.
3961///
3962/// ## Arguments
3963/// * `number_to_check` -- Number to calculate the sign of.
3964///
3965/// ## Returns
3966/// * `sign_value` -- Sign value: -1, 0, or 1
3967pub fn sgn(number_to_check: f64) -> f64 {
3968    let mut sign_value = 0.0;
3969
3970    if number_to_check < 0.0 {
3971        sign_value = -1.0;
3972    }
3973
3974    if number_to_check > 0.0 {
3975        sign_value = 1.0;
3976    }
3977
3978    return sign_value;
3979}
3980
3981/// Original macro name: UTDayAdjust
3982pub fn ut_day_adjust(ut: f64, g1: f64) -> f64 {
3983    let mut return_value = ut;
3984
3985    if (ut - g1) < -6.0 {
3986        return_value = ut + 24.0;
3987    }
3988
3989    if (ut - g1) > 6.0 {
3990        return_value = ut - 24.0;
3991    }
3992
3993    return return_value;
3994}
3995
3996/// Original macro name: Fpart
3997pub fn f_part(w: f64) -> f64 {
3998    return w - lint(w);
3999}
4000
4001/// Original macro name: EQElat
4002pub fn eq_e_lat(
4003    rah: f64,
4004    ram: f64,
4005    ras: f64,
4006    dd: f64,
4007    dm: f64,
4008    ds: f64,
4009    gd: f64,
4010    gm: u32,
4011    gy: u32,
4012) -> f64 {
4013    let a = (dh_dd(hms_dh(rah, ram, ras))).to_radians();
4014    let b = (dms_dd(dd, dm, ds)).to_radians();
4015    let c = (obliq(gd, gm, gy)).to_radians();
4016    let d = b.sin() * c.cos() - b.cos() * c.sin() * a.sin();
4017
4018    return degrees((d).asin());
4019}
4020
4021/// Original macro name: EQElong
4022pub fn eq_e_long(
4023    rah: f64,
4024    ram: f64,
4025    ras: f64,
4026    dd: f64,
4027    dm: f64,
4028    ds: f64,
4029    gd: f64,
4030    gm: u32,
4031    gy: u32,
4032) -> f64 {
4033    let a = (dh_dd(hms_dh(rah, ram, ras))).to_radians();
4034    let b = (dms_dd(dd, dm, ds)).to_radians();
4035    let c = (obliq(gd, gm, gy)).to_radians();
4036    let d = a.sin() * c.cos() + b.tan() * c.sin();
4037    let e = a.cos();
4038    let f = degrees(d.atan2(e));
4039
4040    return f - 360.0 * (f / 360.0).floor();
4041}
4042
4043/// Local time of moonrise.
4044///
4045/// Original macro name: MoonRiseLCT
4046///
4047/// ## Returns
4048/// * `hours`
4049pub fn moon_rise_lct(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32, g_long: f64, g_lat: f64) -> f64 {
4050    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4051    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4052    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4053    let mut lct = 12.0;
4054    let mut dy1 = dy;
4055    let mut mn1 = mn;
4056    let mut yr1 = yr;
4057
4058    let (mm_temp, bm_temp, pm_temp, dp_temp, th_temp, di_temp, p_temp, q_temp, lu_temp, lct_temp) =
4059        moon_rise_lct_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4060    let _mm = mm_temp;
4061    let _bm = bm_temp;
4062    let _pm = pm_temp;
4063    let _dp = dp_temp;
4064    let _th = th_temp;
4065    let _di = di_temp;
4066    let _p = p_temp;
4067    let _q = q_temp;
4068    let mut lu = lu_temp;
4069    lct = lct_temp;
4070
4071    if lct == -99.0 {
4072        return lct;
4073    }
4074    let mut la = lu;
4075
4076    let mut x: f64;
4077    let mut ut: f64;
4078    let mut g1 = 0.0;
4079    let mut gu = 0.0;
4080    for k in 1..9 {
4081        x = lst_gst(la, 0.0, 0.0, g_long);
4082        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4083
4084        g1 = if k == 1 { ut } else { gu };
4085
4086        gu = ut;
4087        ut = gu;
4088
4089        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
4090            moon_rise_lct_l6680(x, ds, zc, gdy, gmn, gyr, g1, ut);
4091        lct = lct_temp;
4092        dy1 = dy1_temp;
4093        mn1 = mn1_temp;
4094        yr1 = yr1_temp;
4095        gdy = gdy_temp;
4096        gmn = gmn_temp;
4097        gyr = gyr_temp;
4098
4099        let (
4100            _mm_temp,
4101            _bm_temp,
4102            _pm_temp,
4103            _dp_temp,
4104            _th_temp,
4105            _di_temp,
4106            _p_temp,
4107            _q_temp,
4108            lu_temp,
4109            lct_temp,
4110        ) = moon_rise_lct_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4111        lu = lu_temp;
4112        lct = lct_temp;
4113
4114        if lct == -99.0 {
4115            return lct;
4116        }
4117        la = lu;
4118    }
4119
4120    x = lst_gst(la, 0.0, 0.0, g_long);
4121    ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4122
4123    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
4124        if (g1 - ut).abs() > 0.5 {
4125            ut = ut + 23.93447;
4126        }
4127    }
4128
4129    ut = ut_day_adjust(ut, g1);
4130    lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4131
4132    return lct;
4133}
4134
4135/// Helper function for moon_rise_lct.
4136pub fn moon_rise_lct_l6680(
4137    x: f64,
4138    ds: i32,
4139    zc: i32,
4140    mut gdy: f64,
4141    mut gmn: u32,
4142    mut gyr: u32,
4143    g1: f64,
4144    mut ut: f64,
4145) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
4146    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
4147        if (g1 - ut).abs() > 0.5 {
4148            ut = ut + 23.93447;
4149        }
4150    }
4151
4152    ut = ut_day_adjust(ut, g1);
4153    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4154    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4155    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4156    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4157    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4158    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4159    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4160    ut = ut - 24.0 * (ut / 24.0).floor();
4161
4162    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
4163}
4164
4165/// Helper function for moon_rise_lct.
4166pub fn moon_rise_lct_l6700(
4167    mut lct: f64,
4168    ds: i32,
4169    zc: i32,
4170    dy1: f64,
4171    mn1: u32,
4172    yr1: u32,
4173    gdy: f64,
4174    gmn: u32,
4175    gyr: u32,
4176    g_lat: f64,
4177) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) {
4178    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4179    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4180    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
4181    let dp = nutat_long(gdy, gmn, gyr);
4182    let th = 0.27249 * pm.sin();
4183    let di = th + 0.0098902 - pm;
4184    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
4185    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
4186    let lu = rise_set_local_sidereal_time_rise(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4187
4188    if e_rs(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat) != "OK" {
4189        lct = -99.0;
4190    }
4191
4192    return (mm, bm, pm, dp, th, di, p, q, lu, lct);
4193}
4194
4195/// Moonrise calculation status.
4196///
4197/// Original macro name: eMoonRise
4198pub fn e_moon_rise(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32, g_long: f64, g_lat: f64) -> String {
4199    let mut s4: String = "OK".to_string();
4200    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4201    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4202    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4203    let mut lct = 12.0;
4204    let mut dy1 = dy;
4205    let mut mn1 = mn;
4206    let mut yr1 = yr;
4207
4208    let (mm_temp, bm_temp, pm_temp, dp_temp, th_temp, di_temp, p_temp, q_temp, lu_temp, s1_temp) =
4209        e_moon_rise_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4210    let _mm = mm_temp;
4211    let _bm = bm_temp;
4212    let _pm = pm_temp;
4213    let _dp = dp_temp;
4214    let _th = th_temp;
4215    let _di = di_temp;
4216    let _p = p_temp;
4217    let _q = q_temp;
4218    let mut lu = lu_temp;
4219    let mut s1 = s1_temp.to_string();
4220
4221    let mut la = lu;
4222
4223    if s1 != "OK" {
4224        return s1;
4225    }
4226
4227    let mut x: f64;
4228    let mut ut: f64;
4229    let mut s3: String;
4230    let mut g1: f64;
4231    let mut gu = 0.0;
4232    for k in 1..9 {
4233        x = lst_gst(la, 0.0, 0.0, g_long);
4234        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4235        s3 = e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4236
4237        if s3 != "OK" {
4238            s4 = ["GST conversion:", &s3].join(" ");
4239        }
4240
4241        g1 = if k == 1 { ut } else { gu };
4242
4243        gu = ut;
4244        ut = gu;
4245        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
4246            e_moon_rise_l6680(s3, g1, ut, ds, zc, gdy, gmn, gyr, dy1, mn1, yr1);
4247        lct = lct_temp;
4248        dy1 = dy1_temp;
4249        mn1 = mn1_temp;
4250        yr1 = yr1_temp;
4251        gdy = gdy_temp;
4252        gmn = gmn_temp;
4253        gyr = gyr_temp;
4254
4255        let (
4256            _mm_temp,
4257            _bm_temp,
4258            _pm_temp,
4259            _dp_temp,
4260            _th_temp,
4261            _di_temp,
4262            _p_temp,
4263            _q_temp,
4264            lu_temp,
4265            s1_temp,
4266        ) = e_moon_rise_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4267        lu = lu_temp;
4268        s1 = s1_temp;
4269
4270        la = lu;
4271
4272        if s1 != "OK" {
4273            return s1;
4274        }
4275    }
4276
4277    x = lst_gst(la, 0.0, 0.0, g_long);
4278    s3 = e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4279
4280    if s3 != "OK" {
4281        s4 = ["GST conversion:", &s3].join(" ");
4282    }
4283
4284    return s4;
4285}
4286
4287/// Helper function for e_moon_rise().
4288pub fn e_moon_rise_l6680(
4289    s3: String,
4290    g1: f64,
4291    mut ut: f64,
4292    ds: i32,
4293    zc: i32,
4294    mut gdy: f64,
4295    mut gmn: u32,
4296    mut gyr: u32,
4297    _dy1: f64,
4298    _mn1: u32,
4299    _yr1: u32,
4300) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
4301    if s3 != "OK" {
4302        if (g1 - ut).abs() > 0.5 {
4303            ut = ut + 23.93447;
4304        }
4305    }
4306
4307    ut = ut_day_adjust(ut, g1);
4308    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4309    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4310    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4311    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4312    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4313    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4314    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4315    ut = ut - 24.0 * (ut / 24.0).floor();
4316
4317    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
4318}
4319
4320/// Helper function for e_moon_rise().
4321pub fn e_moon_rise_l6700(
4322    lct: f64,
4323    ds: i32,
4324    zc: i32,
4325    dy1: f64,
4326    mn1: u32,
4327    yr1: u32,
4328    gdy: f64,
4329    gmn: u32,
4330    gyr: u32,
4331    g_lat: f64,
4332) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, String) {
4333    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4334    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4335    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
4336    let dp = nutat_long(gdy, gmn, gyr);
4337    let th = 0.27249 * pm.sin();
4338    let di = th + 0.0098902 - pm;
4339    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
4340    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
4341    let lu = rise_set_local_sidereal_time_rise(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4342    let s1 = e_rs(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4343
4344    return (mm, bm, pm, dp, th, di, p, q, lu, s1);
4345}
4346
4347/// Local date of moonrise.
4348///
4349/// Original macro names: MoonRiseLcDay, MoonRiseLcMonth, MoonRiseLcYear
4350///
4351/// ## Returns
4352/// * Local date (day)
4353/// * Local date (month)
4354/// * Local date (year)
4355pub fn moon_rise_lc_dmy(
4356    dy: f64,
4357    mn: u32,
4358    yr: u32,
4359    ds: i32,
4360    zc: i32,
4361    g_long: f64,
4362    g_lat: f64,
4363) -> (f64, u32, u32) {
4364    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4365    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4366    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4367    let mut lct = 12.0;
4368    let mut dy1 = dy;
4369    let mut mn1 = mn;
4370    let mut yr1 = yr;
4371
4372    let (mm_temp, bm_temp, pm_temp, dp_temp, th_temp, di_temp, p_temp, q_temp, lu_temp, lct_temp) =
4373        moon_rise_lc_dmy_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4374    let _mm = mm_temp;
4375    let _bm = bm_temp;
4376    let _pm = pm_temp;
4377    let _dp = dp_temp;
4378    let _th = th_temp;
4379    let _di = di_temp;
4380    let _p = p_temp;
4381    let _q = q_temp;
4382    let mut lu = lu_temp;
4383    lct = lct_temp;
4384
4385    if lct == -99.0 {
4386        return (lct, lct as u32, lct as u32);
4387    }
4388    let mut la = lu;
4389
4390    let mut x: f64;
4391    let mut ut: f64;
4392    let mut g1 = 0.0;
4393    let mut gu = 0.0;
4394    for k in 1..9 {
4395        x = lst_gst(la, 0.0, 0.0, g_long);
4396        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4397
4398        g1 = if k == 1 { ut } else { gu };
4399
4400        gu = ut;
4401        ut = gu;
4402
4403        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
4404            moon_rise_lc_dmy_l6680(x, ds, zc, gdy, gmn, gyr, g1, ut);
4405        lct = lct_temp;
4406        dy1 = dy1_temp;
4407        mn1 = mn1_temp;
4408        yr1 = yr1_temp;
4409        gdy = gdy_temp;
4410        gmn = gmn_temp;
4411        gyr = gyr_temp;
4412
4413        let (
4414            _mm_temp,
4415            _bm_temp,
4416            _pm_temp,
4417            _dp_temp,
4418            _th_temp,
4419            _di_temp,
4420            _p_temp,
4421            _q_temp,
4422            lu_temp,
4423            lct_temp,
4424        ) = moon_rise_lc_dmy_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4425        lu = lu_temp;
4426        lct = lct_temp;
4427
4428        if lct == -99.0 {
4429            return (lct, lct as u32, lct as u32);
4430        }
4431        la = lu;
4432    }
4433
4434    x = lst_gst(la, 0.0, 0.0, g_long);
4435    ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4436
4437    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
4438        if (g1 - ut).abs() > 0.5 {
4439            ut = ut + 23.93447;
4440        }
4441    }
4442
4443    ut = ut_day_adjust(ut, g1);
4444    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4445    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4446    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4447
4448    return (dy1, mn1, yr1);
4449}
4450
4451/// Helper function for moon_rise_lc_dmy.
4452pub fn moon_rise_lc_dmy_l6680(
4453    x: f64,
4454    ds: i32,
4455    zc: i32,
4456    mut gdy: f64,
4457    mut gmn: u32,
4458    mut gyr: u32,
4459    g1: f64,
4460    mut ut: f64,
4461) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
4462    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
4463        if (g1 - ut).abs() > 0.5 {
4464            ut = ut + 23.93447;
4465        }
4466    }
4467
4468    ut = ut_day_adjust(ut, g1);
4469    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4470    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4471    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4472    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4473    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4474    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4475    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4476    ut = ut - 24.0 * (ut / 24.0).floor();
4477
4478    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
4479}
4480
4481/// Helper function for moon_rise_lc_dmy.
4482pub fn moon_rise_lc_dmy_l6700(
4483    lct: f64,
4484    ds: i32,
4485    zc: i32,
4486    dy1: f64,
4487    mn1: u32,
4488    yr1: u32,
4489    gdy: f64,
4490    gmn: u32,
4491    gyr: u32,
4492    g_lat: f64,
4493) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) {
4494    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4495    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4496    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
4497    let dp = nutat_long(gdy, gmn, gyr);
4498    let th = 0.27249 * pm.sin();
4499    let di = th + 0.0098902 - pm;
4500    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
4501    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
4502    let lu = rise_set_local_sidereal_time_rise(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4503
4504    return (mm, bm, pm, dp, th, di, p, q, lu, lct);
4505}
4506
4507/// Local azimuth of moonrise.
4508///
4509/// Original macro name: MoonRiseAz
4510///
4511/// ## Returns
4512/// * degrees
4513pub fn moon_rise_az(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32, g_long: f64, g_lat: f64) -> f64 {
4514    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4515    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4516    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4517    let mut lct = 12.0;
4518    let mut dy1 = dy;
4519    let mut mn1 = mn;
4520    let mut yr1 = yr;
4521
4522    let (
4523        mm_temp,
4524        bm_temp,
4525        pm_temp,
4526        dp_temp,
4527        th_temp,
4528        di_temp,
4529        p_temp,
4530        q_temp,
4531        lu_temp,
4532        lct_temp,
4533        _au_temp,
4534    ) = moon_rise_az_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4535    let _mm = mm_temp;
4536    let _bm = bm_temp;
4537    let _pm = pm_temp;
4538    let _dp = dp_temp;
4539    let _th = th_temp;
4540    let _di = di_temp;
4541    let _p = p_temp;
4542    let _q = q_temp;
4543    let mut lu = lu_temp;
4544    lct = lct_temp;
4545    let mut au: f64;
4546
4547    if lct == -99.0 {
4548        return lct;
4549    }
4550    let mut la = lu;
4551
4552    let mut x: f64;
4553    let mut ut: f64;
4554    let mut g1: f64;
4555    let mut gu = 0.0;
4556    let mut aa = 0.0;
4557    for k in 1..9 {
4558        x = lst_gst(la, 0.0, 0.0, g_long);
4559        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4560
4561        g1 = if k == 1 { ut } else { gu };
4562
4563        gu = ut;
4564        ut = gu;
4565
4566        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
4567            moon_rise_az_l6680(x, ds, zc, gdy, gmn, gyr, g1, ut);
4568        lct = lct_temp;
4569        dy1 = dy1_temp;
4570        mn1 = mn1_temp;
4571        yr1 = yr1_temp;
4572        gdy = gdy_temp;
4573        gmn = gmn_temp;
4574        gyr = gyr_temp;
4575
4576        let (
4577            _mm_temp,
4578            _bm_temp,
4579            _pm_temp,
4580            _dp_temp,
4581            _th_temp,
4582            _di_temp,
4583            _p_temp,
4584            _q_temp,
4585            lu_temp,
4586            lct_temp,
4587            au_temp,
4588        ) = moon_rise_az_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4589        lu = lu_temp;
4590        lct = lct_temp;
4591        au = au_temp;
4592
4593        if lct == -99.0 {
4594            return lct;
4595        }
4596        la = lu;
4597        aa = au;
4598    }
4599
4600    au = aa;
4601
4602    return au;
4603}
4604
4605/// Helper function for moon_rise_az.
4606pub fn moon_rise_az_l6680(
4607    x: f64,
4608    ds: i32,
4609    zc: i32,
4610    mut gdy: f64,
4611    mut gmn: u32,
4612    mut gyr: u32,
4613    g1: f64,
4614    mut ut: f64,
4615) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
4616    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
4617        if (g1 - ut).abs() > 0.5 {
4618            ut = ut + 23.93447;
4619        }
4620    }
4621
4622    ut = ut_day_adjust(ut, g1);
4623    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4624    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4625    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4626    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4627    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4628    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4629    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4630    ut = ut - 24.0 * (ut / 24.0).floor();
4631
4632    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
4633}
4634
4635/// Helper function for moon_rise_az.
4636pub fn moon_rise_az_l6700(
4637    lct: f64,
4638    ds: i32,
4639    zc: i32,
4640    dy1: f64,
4641    mn1: u32,
4642    yr1: u32,
4643    gdy: f64,
4644    gmn: u32,
4645    gyr: u32,
4646    g_lat: f64,
4647) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) {
4648    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4649    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4650    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
4651    let dp = nutat_long(gdy, gmn, gyr);
4652    let th = 0.27249 * pm.sin();
4653    let di = th + 0.0098902 - pm;
4654    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
4655    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
4656    let lu = rise_set_local_sidereal_time_rise(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4657    let au = rise_set_azimuth_rise(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4658
4659    return (mm, bm, pm, dp, th, di, p, q, lu, lct, au);
4660}
4661
4662/// Local time of moonset.
4663///
4664/// Original macro name: MoonSetLCT
4665///
4666/// ## Returns
4667/// * hours
4668pub fn moon_set_lct(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32, g_long: f64, g_lat: f64) -> f64 {
4669    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4670    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4671    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4672    let mut lct = 12.0;
4673    let mut dy1 = dy;
4674    let mut mn1 = mn;
4675    let mut yr1 = yr;
4676
4677    let (mm_temp, bm_temp, pm_temp, dp_temp, th_temp, di_temp, p_temp, q_temp, lu_temp, lct_temp) =
4678        moon_set_lct_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4679    let _mm = mm_temp;
4680    let _bm = bm_temp;
4681    let _pm = pm_temp;
4682    let _dp = dp_temp;
4683    let _th = th_temp;
4684    let _di = di_temp;
4685    let _p = p_temp;
4686    let _q = q_temp;
4687    let mut lu = lu_temp;
4688    lct = lct_temp;
4689
4690    if lct == -99.0 {
4691        return lct;
4692    }
4693    let mut la = lu;
4694
4695    let mut x: f64;
4696    let mut ut: f64;
4697    let mut g1 = 0.0;
4698    let mut gu = 0.0;
4699    for k in 1..9 {
4700        x = lst_gst(la, 0.0, 0.0, g_long);
4701        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4702
4703        g1 = if k == 1 { ut } else { gu };
4704
4705        gu = ut;
4706        ut = gu;
4707
4708        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
4709            moon_set_lct_l6680(x, ds, zc, gdy, gmn, gyr, g1, ut);
4710        lct = lct_temp;
4711        dy1 = dy1_temp;
4712        mn1 = mn1_temp;
4713        yr1 = yr1_temp;
4714        gdy = gdy_temp;
4715        gmn = gmn_temp;
4716        gyr = gyr_temp;
4717
4718        let (
4719            _mm_temp,
4720            _bm_temp,
4721            _pm_temp,
4722            _dp_temp,
4723            _th_temp,
4724            _di_temp,
4725            _p_temp,
4726            _q_temp,
4727            lu_temp,
4728            lct_temp,
4729        ) = moon_set_lct_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4730        lu = lu_temp;
4731        lct = lct_temp;
4732
4733        if lct == -99.0 {
4734            return lct;
4735        }
4736        la = lu;
4737    }
4738
4739    x = lst_gst(la, 0.0, 0.0, g_long);
4740    ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4741
4742    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "ok" {
4743        if (g1 - ut).abs() > 0.5 {
4744            ut = ut + 23.93447;
4745        }
4746    }
4747
4748    ut = ut_day_adjust(ut, g1);
4749    lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4750
4751    return lct;
4752}
4753
4754/// Helper function for moon_set_lct.
4755pub fn moon_set_lct_l6680(
4756    x: f64,
4757    ds: i32,
4758    zc: i32,
4759    mut gdy: f64,
4760    mut gmn: u32,
4761    mut gyr: u32,
4762    g1: f64,
4763    mut ut: f64,
4764) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
4765    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
4766        if (g1 - ut).abs() > 0.5 {
4767            ut = ut + 23.93447;
4768        }
4769    }
4770
4771    ut = ut_day_adjust(ut, g1);
4772    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4773    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4774    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4775    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4776    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4777    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4778    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4779    ut = ut - 24.0 * (ut / 24.0).floor();
4780
4781    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
4782}
4783
4784/// Helper function for moon_set_lct.
4785pub fn moon_set_lct_l6700(
4786    mut lct: f64,
4787    ds: i32,
4788    zc: i32,
4789    dy1: f64,
4790    mn1: u32,
4791    yr1: u32,
4792    gdy: f64,
4793    gmn: u32,
4794    gyr: u32,
4795    g_lat: f64,
4796) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) {
4797    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4798    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4799    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
4800    let dp = nutat_long(gdy, gmn, gyr);
4801    let th = 0.27249 * pm.sin();
4802    let di = th + 0.0098902 - pm;
4803    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
4804    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
4805    let lu = rise_set_local_sidereal_time_set(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4806
4807    if e_rs(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat) != "OK" {
4808        lct = -99.0;
4809    }
4810
4811    return (mm, bm, pm, dp, th, di, p, q, lu, lct);
4812}
4813
4814/// Moonset calculation status.
4815///
4816/// Original macro name: eMoonSet
4817pub fn e_moon_set(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32, g_long: f64, g_lat: f64) -> String {
4818    let mut s4: String = "OK".to_string();
4819    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4820    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4821    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4822    let mut lct = 12.0;
4823    let mut dy1 = dy;
4824    let mut mn1 = mn;
4825    let mut yr1 = yr;
4826
4827    let (mm_temp, bm_temp, pm_temp, dp_temp, th_temp, di_temp, p_temp, q_temp, lu_temp, s1_temp) =
4828        e_moon_rise_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4829    let _mm = mm_temp;
4830    let _bm = bm_temp;
4831    let _pm = pm_temp;
4832    let _dp = dp_temp;
4833    let _th = th_temp;
4834    let _di = di_temp;
4835    let _p = p_temp;
4836    let _q = q_temp;
4837    let mut lu = lu_temp;
4838    let mut s1 = s1_temp.to_string();
4839
4840    let mut la = lu;
4841
4842    if s1 != "OK" {
4843        return s1;
4844    }
4845
4846    let mut x: f64;
4847    let mut ut: f64;
4848    let mut s3: String;
4849    let mut g1: f64;
4850    let mut gu = 0.0;
4851    for k in 1..9 {
4852        x = lst_gst(la, 0.0, 0.0, g_long);
4853        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4854        s3 = e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4855
4856        if s3 != "OK" {
4857            s4 = ["GST conversion:", &s3].join(" ");
4858        }
4859
4860        g1 = if k == 1 { ut } else { gu };
4861
4862        gu = ut;
4863        ut = gu;
4864
4865        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
4866            e_moon_set_l6680(x, g1, ut, ds, zc, gdy, gmn, gyr, dy1, mn1, yr1);
4867        lct = lct_temp;
4868        dy1 = dy1_temp;
4869        mn1 = mn1_temp;
4870        yr1 = yr1_temp;
4871        gdy = gdy_temp;
4872        gmn = gmn_temp;
4873        gyr = gyr_temp;
4874
4875        let (
4876            _mm_temp,
4877            _bm_temp,
4878            _pm_temp,
4879            _dp_temp,
4880            _th_temp,
4881            _di_temp,
4882            _p_temp,
4883            _q_temp,
4884            lu_temp,
4885            s1_temp,
4886        ) = e_moon_set_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4887        lu = lu_temp;
4888        s1 = s1_temp;
4889
4890        la = lu;
4891
4892        if s1 != "OK" {
4893            return s1;
4894        }
4895    }
4896
4897    x = lst_gst(la, 0.0, 0.0, g_long);
4898    s3 = e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
4899
4900    if s3 != "OK" {
4901        s4 = ["GST conversion:", &s3].join(" ");
4902    }
4903
4904    return s4;
4905}
4906
4907/// Helper function for e_moon_set().
4908pub fn e_moon_set_l6680(
4909    x: f64,
4910    g1: f64,
4911    mut ut: f64,
4912    ds: i32,
4913    zc: i32,
4914    mut gdy: f64,
4915    mut gmn: u32,
4916    mut gyr: u32,
4917    _dy1: f64,
4918    _mn1: u32,
4919    _yr1: u32,
4920) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
4921    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
4922        if (g1 - ut).abs() > 0.5 {
4923            ut = ut + 23.93447;
4924        }
4925    }
4926
4927    ut = ut_day_adjust(ut, g1);
4928    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4929    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4930    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4931    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
4932    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4933    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4934    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4935    ut = ut - 24.0 * (ut / 24.0).floor();
4936
4937    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
4938}
4939
4940/// Helper function for e_moon_set().
4941pub fn e_moon_set_l6700(
4942    lct: f64,
4943    ds: i32,
4944    zc: i32,
4945    dy1: f64,
4946    mn1: u32,
4947    yr1: u32,
4948    gdy: f64,
4949    gmn: u32,
4950    gyr: u32,
4951    g_lat: f64,
4952) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, String) {
4953    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4954    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
4955    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
4956    let dp = nutat_long(gdy, gmn, gyr);
4957    let th = 0.27249 * pm.sin();
4958    let di = th + 0.0098902 - pm;
4959    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
4960    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
4961    let lu = rise_set_local_sidereal_time_set(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4962    let s1 = e_rs(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
4963
4964    return (mm, bm, pm, dp, th, di, p, q, lu, s1);
4965}
4966
4967/// Local date of moonset.
4968///
4969/// Original macro names: MoonSetLcDay, MoonSetLcMonth, MoonSetLcYear
4970///
4971/// ## Returns
4972/// * Local date (day)
4973/// * Local date (month)
4974/// * Local date (year)
4975pub fn moon_set_lc_dmy(
4976    dy: f64,
4977    mn: u32,
4978    yr: u32,
4979    ds: i32,
4980    zc: i32,
4981    g_long: f64,
4982    g_lat: f64,
4983) -> (f64, u32, u32) {
4984    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4985    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4986    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
4987    let mut lct = 12.0;
4988    let mut dy1 = dy;
4989    let mut mn1 = mn;
4990    let mut yr1 = yr;
4991
4992    let (mm_temp, bm_temp, pm_temp, dp_temp, th_temp, di_temp, p_temp, q_temp, lu_temp, lct_temp) =
4993        moon_set_lc_dmy_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
4994    let _mm = mm_temp;
4995    let _bm = bm_temp;
4996    let _pm = pm_temp;
4997    let _dp = dp_temp;
4998    let _th = th_temp;
4999    let _di = di_temp;
5000    let _p = p_temp;
5001    let _q = q_temp;
5002    let mut lu = lu_temp;
5003    lct = lct_temp;
5004
5005    if lct == -99.0 {
5006        return (lct, lct as u32, lct as u32);
5007    }
5008    let mut la = lu;
5009
5010    let mut x: f64;
5011    let mut ut: f64;
5012    let mut g1 = 0.0;
5013    let mut gu = 0.0;
5014    for k in 1..9 {
5015        x = lst_gst(la, 0.0, 0.0, g_long);
5016        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
5017
5018        g1 = if k == 1 { ut } else { gu };
5019
5020        gu = ut;
5021        ut = gu;
5022
5023        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
5024            moon_set_lc_dmy_l6680(x, ds, zc, gdy, gmn, gyr, g1, ut);
5025        lct = lct_temp;
5026        dy1 = dy1_temp;
5027        mn1 = mn1_temp;
5028        yr1 = yr1_temp;
5029        gdy = gdy_temp;
5030        gmn = gmn_temp;
5031        gyr = gyr_temp;
5032
5033        let (
5034            _mm_temp,
5035            _bm_temp,
5036            _pm_temp,
5037            _dp_temp,
5038            _th_temp,
5039            _di_temp,
5040            _p_temp,
5041            _q_temp,
5042            lu_temp,
5043            lct_temp,
5044        ) = moon_set_lc_dmy_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
5045        lu = lu_temp;
5046        lct = lct_temp;
5047
5048        if lct == -99.0 {
5049            return (lct, lct as u32, lct as u32);
5050        }
5051        la = lu;
5052    }
5053
5054    x = lst_gst(la, 0.0, 0.0, g_long);
5055    ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
5056
5057    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
5058        if (g1 - ut).abs() > 0.5 {
5059            ut = ut + 23.93447;
5060        }
5061    }
5062
5063    ut = ut_day_adjust(ut, g1);
5064    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5065    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5066    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5067
5068    return (dy1, mn1, yr1);
5069}
5070
5071/// Helper function for moon_set_lc_dmy.
5072pub fn moon_set_lc_dmy_l6680(
5073    x: f64,
5074    ds: i32,
5075    zc: i32,
5076    mut gdy: f64,
5077    mut gmn: u32,
5078    mut gyr: u32,
5079    g1: f64,
5080    mut ut: f64,
5081) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
5082    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
5083        if (g1 - ut).abs() > 0.5 {
5084            ut = ut + 23.93447;
5085        }
5086    }
5087
5088    ut = ut_day_adjust(ut, g1);
5089    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5090    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5091    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5092    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5093    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5094    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5095    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5096    ut = ut - 24.0 * (ut / 24.0).floor();
5097
5098    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
5099}
5100
5101/// Helper function for moon_set_lc_dmy.
5102pub fn moon_set_lc_dmy_l6700(
5103    lct: f64,
5104    ds: i32,
5105    zc: i32,
5106    dy1: f64,
5107    mn1: u32,
5108    yr1: u32,
5109    gdy: f64,
5110    gmn: u32,
5111    gyr: u32,
5112    g_lat: f64,
5113) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) {
5114    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5115    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5116    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
5117    let dp = nutat_long(gdy, gmn, gyr);
5118    let th = 0.27249 * pm.sin();
5119    let di = th + 0.0098902 - pm;
5120    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
5121    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
5122    let lu = rise_set_local_sidereal_time_set(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
5123
5124    return (mm, bm, pm, dp, th, di, p, q, lu, lct);
5125}
5126
5127/// Local azimuth of moonset.
5128///
5129/// Original macro name: MoonSetAz
5130///
5131/// ## Returns
5132/// * degrees
5133pub fn moon_set_az(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32, g_long: f64, g_lat: f64) -> f64 {
5134    let mut gdy = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
5135    let mut gmn = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
5136    let mut gyr = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
5137    let mut lct = 12.0;
5138    let mut dy1 = dy;
5139    let mut mn1 = mn;
5140    let mut yr1 = yr;
5141
5142    let (
5143        mm_temp,
5144        bm_temp,
5145        pm_temp,
5146        dp_temp,
5147        th_temp,
5148        di_temp,
5149        p_temp,
5150        q_temp,
5151        lu_temp,
5152        lct_temp,
5153        _au_temp,
5154    ) = moon_set_az_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
5155    let _mm = mm_temp;
5156    let _bm = bm_temp;
5157    let _pm = pm_temp;
5158    let _dp = dp_temp;
5159    let _th = th_temp;
5160    let _di = di_temp;
5161    let _p = p_temp;
5162    let _q = q_temp;
5163    let mut lu = lu_temp;
5164    lct = lct_temp;
5165    let mut au: f64;
5166
5167    if lct == -99.0 {
5168        return lct;
5169    }
5170    let mut la = lu;
5171
5172    let mut x: f64;
5173    let mut ut: f64;
5174    let mut g1: f64;
5175    let mut gu = 0.0;
5176    let mut aa = 0.0;
5177    for k in 1..9 {
5178        x = lst_gst(la, 0.0, 0.0, g_long);
5179        ut = gst_ut(x, 0.0, 0.0, gdy, gmn, gyr);
5180
5181        g1 = if k == 1 { ut } else { gu };
5182
5183        gu = ut;
5184        ut = gu;
5185
5186        let (_ut_temp, lct_temp, dy1_temp, mn1_temp, yr1_temp, gdy_temp, gmn_temp, gyr_temp) =
5187            moon_set_az_l6680(x, ds, zc, gdy, gmn, gyr, g1, ut);
5188        lct = lct_temp;
5189        dy1 = dy1_temp;
5190        mn1 = mn1_temp;
5191        yr1 = yr1_temp;
5192        gdy = gdy_temp;
5193        gmn = gmn_temp;
5194        gyr = gyr_temp;
5195
5196        let (
5197            _mm_temp,
5198            _bm_temp,
5199            _pm_temp,
5200            _dp_temp,
5201            _th_temp,
5202            _di_temp,
5203            _p_temp,
5204            _q_temp,
5205            lu_temp,
5206            lct_temp,
5207            au_temp,
5208        ) = moon_set_az_l6700(lct, ds, zc, dy1, mn1, yr1, gdy, gmn, gyr, g_lat);
5209        lu = lu_temp;
5210        lct = lct_temp;
5211        au = au_temp;
5212
5213        if lct == -99.0 {
5214            return lct;
5215        }
5216        la = lu;
5217        aa = au;
5218    }
5219
5220    au = aa;
5221
5222    return au;
5223}
5224
5225/// Helper function for moon_set_az.
5226pub fn moon_set_az_l6680(
5227    x: f64,
5228    ds: i32,
5229    zc: i32,
5230    mut gdy: f64,
5231    mut gmn: u32,
5232    mut gyr: u32,
5233    g1: f64,
5234    mut ut: f64,
5235) -> (f64, f64, f64, u32, u32, f64, u32, u32) {
5236    if e_gst_ut(x, 0.0, 0.0, gdy, gmn, gyr) != "OK" {
5237        if (g1 - ut).abs() > 0.5 {
5238            ut = ut + 23.93447;
5239        }
5240    }
5241
5242    ut = ut_day_adjust(ut, g1);
5243    let lct = ut_lct(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5244    let dy1 = ut_lc_day(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5245    let mn1 = ut_lc_month(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5246    let yr1 = ut_lc_year(ut, 0.0, 0.0, ds, zc, gdy, gmn, gyr);
5247    gdy = lct_gday(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5248    gmn = lct_gmonth(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5249    gyr = lct_gyear(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5250    ut = ut - 24.0 * (ut / 24.0).floor();
5251
5252    return (ut, lct, dy1, mn1, yr1, gdy, gmn, gyr);
5253}
5254
5255/// Helper function for moon_set_az.
5256pub fn moon_set_az_l6700(
5257    lct: f64,
5258    ds: i32,
5259    zc: i32,
5260    dy1: f64,
5261    mn1: u32,
5262    yr1: u32,
5263    gdy: f64,
5264    gmn: u32,
5265    gyr: u32,
5266    g_lat: f64,
5267) -> (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) {
5268    let mm = moon_long(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5269    let bm = moon_lat(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1);
5270    let pm = (moon_hp(lct, 0.0, 0.0, ds, zc, dy1, mn1, yr1)).to_radians();
5271    let dp = nutat_long(gdy, gmn, gyr);
5272    let th = 0.27249 * pm.sin();
5273    let di = th + 0.0098902 - pm;
5274    let p = dd_dh(ec_ra(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr));
5275    let q = ec_dec(mm + dp, 0.0, 0.0, bm, 0.0, 0.0, gdy, gmn, gyr);
5276    let lu = rise_set_local_sidereal_time_set(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
5277    let au = rise_set_azimuth_set(p, 0.0, 0.0, q, 0.0, 0.0, degrees(di), g_lat);
5278
5279    return (mm, bm, pm, dp, th, di, p, q, lu, lct, au);
5280}
5281
5282/// Determine if a lunar eclipse is likely to occur.
5283///
5284/// Original macro name: LEOccurrence
5285pub fn lunar_eclipse_occurrence(ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> String {
5286    let d0 = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
5287    let m0 = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
5288    let y0 = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
5289
5290    /* Comparison is impossible because of type limits
5291    if y0 < 0 {
5292        y0 = y0 + 1;
5293    }
5294    */
5295
5296    let j0 = cd_jd(0.0, 1, y0);
5297    let dj = cd_jd(d0, m0, y0);
5298    let mut k = (y0 as f64 - 1900.0 + ((dj - j0) * 1.0 / 365.0)) * 12.3685;
5299    k = lint(k + 0.5);
5300    let tn = k / 1236.85;
5301    let tf = (k + 0.5) / 1236.85;
5302    let mut t = tn;
5303    let (f, _dd, _e1, _b1, a, b) = lunar_eclipse_occurrence_l6855(t, k);
5304    let _ni = a;
5305    let _nf = b;
5306    let _nb = f;
5307    t = tf;
5308    k = k + 0.5;
5309    let (f, _dd, _e1, _b1, a, b) = lunar_eclipse_occurrence_l6855(t, k);
5310    let _fi = a;
5311    let _ff = b;
5312    let fb = f;
5313
5314    let mut df = (fb - 3.141592654 * lint(fb / 3.141592654)).abs();
5315
5316    if df > 0.37 {
5317        df = 3.141592654 - df;
5318    }
5319
5320    let mut s = "Lunar eclipse certain";
5321    if df >= 0.242600766 {
5322        s = "Lunar eclipse possible";
5323        if df > 0.37 {
5324            s = "No lunar eclipse"
5325        }
5326    }
5327
5328    return s.to_string();
5329}
5330
5331/// Helper function for lunar_eclipse_occurrence.
5332pub fn lunar_eclipse_occurrence_l6855(t: f64, k: f64) -> (f64, f64, f64, f64, f64, f64) {
5333    let t2 = t * t;
5334    let e = 29.53 * k;
5335    let c = 166.56 + (132.87 - 0.009173 * t) * t;
5336    let c = c.to_radians();
5337    let b = 0.00058868 * k + (0.0001178 - 0.000000155 * t) * t2;
5338    let b = b + 0.00033 * c.sin() + 0.75933;
5339    let a = k / 12.36886;
5340    let a1 = 359.2242 + 360.0 * f_part(a) - (0.0000333 + 0.00000347 * t) * t2;
5341    let a2 = 306.0253 + 360.0 * f_part(k / 0.9330851);
5342    let a2 = a2 + (0.0107306 + 0.00001236 * t) * t2;
5343    let a = k / 0.9214926;
5344    let f = 21.2964 + 360.0 * f_part(a) - (0.0016528 + 0.00000239 * t) * t2;
5345    let a1 = unwind_deg(a1);
5346    let a2 = unwind_deg(a2);
5347    let f = unwind_deg(f);
5348    let a1 = a1.to_radians();
5349    let a2 = a2.to_radians();
5350    let f = f.to_radians();
5351
5352    let dd = (0.1734 - 0.000393 * t) * a1.sin() + 0.0021 * (2.0 * a1).sin();
5353    let dd = dd - 0.4068 * a2.sin() + 0.0161 * (2.0 * a2).sin() - 0.0004 * (3.0 * a2).sin();
5354    let dd = dd + 0.0104 * (2.0 * f).sin() - 0.0051 * (a1 + a2).sin();
5355    let dd = dd - 0.0074 * (a1 - a2).sin() + 0.0004 * (2.0 * f + a1).sin();
5356    let dd = dd - 0.0004 * (2.0 * f - a1).sin() - 0.0006 * (2.0 * f + a2).sin()
5357        + 0.001 * (2.0 * f - a2).sin();
5358    let dd = dd + 0.0005 * (a1 + 2.0 * a2).sin();
5359    let e1 = e.floor();
5360    let b = b + dd + (e - e1);
5361    let b1 = b.floor();
5362    let a = e1 + b1;
5363    let b = b - b1;
5364
5365    return (f, dd, e1, b1, a, b);
5366}
5367
5368/// Calculate time of maximum shadow for lunar eclipse (UT).
5369///
5370/// Original macro name: UTMaxLunarEclipse
5371pub fn ut_max_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
5372    let tp = 2.0 * std::f64::consts::PI;
5373
5374    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
5375        return -99.0;
5376    }
5377
5378    let dj = full_moon(ds, zc, dy, mn, yr);
5379    let _dp = 0.0;
5380    let gday = jdc_day(dj);
5381    let gmonth = jdc_month(dj);
5382    let gyear = jdc_year(dj);
5383    let igday = gday.floor();
5384    let xi = gday - igday;
5385    let utfm = xi * 24.0;
5386    let ut = utfm - 1.0;
5387    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5388    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5389    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5390    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5391    let ut = utfm + 1.0;
5392    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
5393    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5394    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5395    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5396
5397    if sb < 0.0 {
5398        sb = sb + tp;
5399    }
5400
5401    let xh = utfm;
5402    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
5403    let mut dm = mz - my;
5404
5405    if dm < 0.0 {
5406        dm = dm + tp;
5407    }
5408
5409    let lj = (dm - sb) / 2.0;
5410    let q = 0.0;
5411    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
5412    let ut = x0 - 0.13851852;
5413    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
5414    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5415    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
5416    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
5417    let by = by - q;
5418    let bz = bz - q;
5419    let p3 = 0.00004263;
5420    let zh = (sr - mr) / lj;
5421    let tc = x0 + zh;
5422    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
5423    let s2 = sh * sh;
5424    let z2 = zh * zh;
5425    let ps = p3 / (rr * lj);
5426    let z1 = (zh * z2 / (z2 + s2)) + x0;
5427    let h0 = (hy + hz) / (2.0 * lj);
5428    let rm = 0.272446 * h0;
5429    let rn = 0.00465242 / (lj * rr);
5430    let hd = h0 * 0.99834;
5431    let _ru = (hd - rn + ps) * 1.02;
5432    let rp = (hd + rn + ps) * 1.02;
5433    let _pj = (sh * zh / (s2 + z2).sqrt()).abs();
5434    let r = rm + rp;
5435    let mut dd = z1 - x0;
5436    dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5437
5438    if dd < 0.0 {
5439        return -99.0;
5440    }
5441
5442    return z1;
5443}
5444
5445/// Calculate time of first shadow contact for lunar eclipse (UT).
5446///
5447/// Original macro name: UTFirstContactLunarEclipse
5448pub fn ut_first_contact_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
5449    let tp = 2.0 * std::f64::consts::PI;
5450
5451    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
5452        return -99.0;
5453    }
5454
5455    let dj = full_moon(ds, zc, dy, mn, yr);
5456    let _dp = 0.0;
5457    let gday = jdc_day(dj);
5458    let gmonth = jdc_month(dj);
5459    let gyear = jdc_year(dj);
5460    let igday = gday.floor();
5461    let xi = gday - igday;
5462    let utfm = xi * 24.0;
5463    let ut = utfm - 1.0;
5464    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5465    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5466    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5467    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5468    let ut = utfm + 1.0;
5469    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
5470    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5471    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5472    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5473
5474    if sb < 0.0 {
5475        sb = sb + tp;
5476    }
5477
5478    let xh = utfm;
5479    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
5480    let mut dm = mz - my;
5481
5482    if dm < 0.0 {
5483        dm = dm + tp;
5484    }
5485
5486    let lj = (dm - sb) / 2.0;
5487    let q = 0.0;
5488    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
5489    let ut = x0 - 0.13851852;
5490    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
5491    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5492    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
5493    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
5494    let by = by - q;
5495    let bz = bz - q;
5496    let p3 = 0.00004263;
5497    let zh = (sr - mr) / lj;
5498    let tc = x0 + zh;
5499    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
5500    let s2 = sh * sh;
5501    let z2 = zh * zh;
5502    let ps = p3 / (rr * lj);
5503    let z1 = (zh * z2 / (z2 + s2)) + x0;
5504    let h0 = (hy + hz) / (2.0 * lj);
5505    let rm = 0.272446 * h0;
5506    let rn = 0.00465242 / (lj * rr);
5507    let hd = h0 * 0.99834;
5508    let _ru = (hd - rn + ps) * 1.02;
5509    let rp = (hd + rn + ps) * 1.02;
5510    let _pj = (sh * zh / (s2 + z2).sqrt()).abs();
5511    let r = rm + rp;
5512    let mut dd = z1 - x0;
5513    dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5514
5515    if dd < 0.0 {
5516        return -99.0;
5517    }
5518
5519    let zd = dd.sqrt();
5520    let mut z6 = z1 - zd;
5521
5522    if z6 < 0.0 {
5523        z6 = z6 + 24.0;
5524    }
5525
5526    return z6;
5527}
5528
5529/// Calculate time of last shadow contact for lunar eclipse (UT).
5530///
5531/// Original macro name: UTLastContactLunarEclipse
5532pub fn ut_last_contact_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
5533    let tp = 2.0 * std::f64::consts::PI;
5534
5535    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
5536        return -99.0;
5537    }
5538
5539    let dj = full_moon(ds, zc, dy, mn, yr);
5540    let _dp = 0.0;
5541    let gday = jdc_day(dj);
5542    let gmonth = jdc_month(dj);
5543    let gyear = jdc_year(dj);
5544    let igday = gday.floor();
5545    let xi = gday - igday;
5546    let utfm = xi * 24.0;
5547    let ut = utfm - 1.0;
5548    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5549    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5550    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5551    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5552    let ut = utfm + 1.0;
5553    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
5554    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5555    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5556    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5557
5558    if sb < 0.0 {
5559        sb = sb + tp;
5560    }
5561
5562    let xh = utfm;
5563    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
5564    let mut dm = mz - my;
5565
5566    if dm < 0.0 {
5567        dm = dm + tp;
5568    }
5569
5570    let lj = (dm - sb) / 2.0;
5571    let q = 0.0;
5572    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
5573    let ut = x0 - 0.13851852;
5574    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
5575    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5576    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
5577    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
5578    let by = by - q;
5579    let bz = bz - q;
5580    let p3 = 0.00004263;
5581    let zh = (sr - mr) / lj;
5582    let tc = x0 + zh;
5583    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
5584    let s2 = sh * sh;
5585    let z2 = zh * zh;
5586    let ps = p3 / (rr * lj);
5587    let z1 = (zh * z2 / (z2 + s2)) + x0;
5588    let h0 = (hy + hz) / (2.0 * lj);
5589    let rm = 0.272446 * h0;
5590    let rn = 0.00465242 / (lj * rr);
5591    let hd = h0 * 0.99834;
5592    let _ru = (hd - rn + ps) * 1.02;
5593    let rp = (hd + rn + ps) * 1.02;
5594    let _pj = (sh * zh / (s2 + z2).sqrt()).abs();
5595    let r = rm + rp;
5596    let dd = z1 - x0;
5597    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5598
5599    if dd < 0.0 {
5600        return -99.0;
5601    }
5602
5603    let zd = dd.sqrt();
5604    let _z6 = z1 - zd;
5605    let z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5606
5607    return z7;
5608}
5609
5610/// Calculate start time of umbra phase of lunar eclipse (UT).
5611///
5612/// Original macro name: UTStartUmbraLunarEclipse
5613pub fn ut_start_umbra_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
5614    let tp = 2.0 * std::f64::consts::PI;
5615
5616    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
5617        return -99.0;
5618    }
5619
5620    let dj = full_moon(ds, zc, dy, mn, yr);
5621    let _dp = 0.0;
5622    let gday = jdc_day(dj);
5623    let gmonth = jdc_month(dj);
5624    let gyear = jdc_year(dj);
5625    let igday = gday.floor();
5626    let xi = gday - igday;
5627    let utfm = xi * 24.0;
5628    let ut = utfm - 1.0;
5629    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5630    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5631    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5632    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5633    let ut = utfm + 1.0;
5634    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
5635    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5636    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5637    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5638
5639    if sb < 0.0 {
5640        sb = sb + tp;
5641    }
5642
5643    let xh = utfm;
5644    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
5645    let mut dm = mz - my;
5646
5647    if dm < 0.0 {
5648        dm = dm + tp;
5649    }
5650
5651    let lj = (dm - sb) / 2.0;
5652    let q = 0.0;
5653    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
5654    let ut = x0 - 0.13851852;
5655    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
5656    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5657    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
5658    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
5659    let by = by - q;
5660    let bz = bz - q;
5661    let p3 = 0.00004263;
5662    let zh = (sr - mr) / lj;
5663    let tc = x0 + zh;
5664    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
5665    let s2 = sh * sh;
5666    let z2 = zh * zh;
5667    let ps = p3 / (rr * lj);
5668    let z1 = (zh * z2 / (z2 + s2)) + x0;
5669    let h0 = (hy + hz) / (2.0 * lj);
5670    let rm = 0.272446 * h0;
5671    let rn = 0.00465242 / (lj * rr);
5672    let hd = h0 * 0.99834;
5673    let ru = (hd - rn + ps) * 1.02;
5674    let rp = (hd + rn + ps) * 1.02;
5675    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
5676    let r = rm + rp;
5677    let mut dd = z1 - x0;
5678    dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5679
5680    if dd < 0.0 {
5681        return -99.0;
5682    }
5683
5684    let zd = dd.sqrt();
5685    let z6 = z1 - zd;
5686    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5687
5688    if z6 < 0.0 {
5689        let _z6 = z6 + 24.0;
5690    }
5691
5692    let r = rm + ru;
5693    dd = z1 - x0;
5694    dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5695    let _mg = (rm + rp - pj) / (2.0 * rm);
5696
5697    if dd < 0.0 {
5698        return -99.0;
5699    }
5700
5701    let zd = dd.sqrt();
5702    let mut z8 = z1 - zd;
5703    let _z9 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5704
5705    if z8 < 0.0 {
5706        z8 = z8 + 24.0;
5707    }
5708
5709    return z8;
5710}
5711
5712/// Calculate end time of umbra phase of lunar eclipse (UT).
5713///
5714/// Original macro name: UTEndUmbraLunarEclipse
5715pub fn ut_end_umbra_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
5716    let tp = 2.0 * std::f64::consts::PI;
5717
5718    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
5719        return -99.0;
5720    }
5721
5722    let dj = full_moon(ds, zc, dy, mn, yr);
5723    let _dp = 0.0;
5724    let gday = jdc_day(dj);
5725    let gmonth = jdc_month(dj);
5726    let gyear = jdc_year(dj);
5727    let igday = gday.floor();
5728    let xi = gday - igday;
5729    let utfm = xi * 24.0;
5730    let ut = utfm - 1.0;
5731    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5732    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5733    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5734    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5735    let ut = utfm + 1.0;
5736    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
5737    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5738    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5739    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5740
5741    if sb < 0.0 {
5742        sb = sb + tp;
5743    }
5744
5745    let xh = utfm;
5746    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
5747    let mut dm = mz - my;
5748
5749    if dm < 0.0 {
5750        dm = dm + tp;
5751    }
5752
5753    let lj = (dm - sb) / 2.0;
5754    let q = 0.0;
5755    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
5756    let ut = x0 - 0.13851852;
5757    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
5758    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5759    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
5760    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
5761    let by = by - q;
5762    let bz = bz - q;
5763    let p3 = 0.00004263;
5764    let zh = (sr - mr) / lj;
5765    let tc = x0 + zh;
5766    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
5767    let s2 = sh * sh;
5768    let z2 = zh * zh;
5769    let ps = p3 / (rr * lj);
5770    let z1 = (zh * z2 / (z2 + s2)) + x0;
5771    let h0 = (hy + hz) / (2.0 * lj);
5772    let rm = 0.272446 * h0;
5773    let rn = 0.00465242 / (lj * rr);
5774    let hd = h0 * 0.99834;
5775    let ru = (hd - rn + ps) * 1.02;
5776    let rp = (hd + rn + ps) * 1.02;
5777    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
5778    let r = rm + rp;
5779    let dd = z1 - x0;
5780    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5781
5782    if dd < 0.0 {
5783        return -99.0;
5784    }
5785
5786    let zd = dd.sqrt();
5787    let z6 = z1 - zd;
5788    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5789
5790    if z6 < 0.0 {
5791        let _z6 = z6 + 24.0;
5792    }
5793
5794    let r = rm + ru;
5795    let dd = z1 - x0;
5796    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5797    let _mg = (rm + rp - pj) / (2.0 * rm);
5798
5799    if dd < 0.0 {
5800        return -99.0;
5801    }
5802
5803    let zd = dd.sqrt();
5804    let _z8 = z1 - zd;
5805    let z9 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5806
5807    return z9;
5808}
5809
5810/// Calculate start time of total phase of lunar eclipse (UT).
5811///
5812/// Original macro name: UTStartTotalLunarEclipse
5813pub fn ut_start_total_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
5814    let tp = 2.0 * std::f64::consts::PI;
5815
5816    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
5817        return -99.0;
5818    }
5819
5820    let dj = full_moon(ds, zc, dy, mn, yr);
5821    let _dp = 0.0;
5822    let gday = jdc_day(dj);
5823    let gmonth = jdc_month(dj);
5824    let gyear = jdc_year(dj);
5825    let igday = gday.floor();
5826    let xi = gday - igday;
5827    let utfm = xi * 24.0;
5828    let ut = utfm - 1.0;
5829    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5830    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5831    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5832    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5833    let ut = utfm + 1.0;
5834    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
5835    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5836    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5837    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5838
5839    if sb < 0.0 {
5840        sb = sb + tp;
5841    }
5842
5843    let xh = utfm;
5844    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
5845    let mut dm = mz - my;
5846
5847    if dm < 0.0 {
5848        dm = dm + tp;
5849    }
5850
5851    let lj = (dm - sb) / 2.0;
5852    let q = 0.0;
5853    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
5854    let ut = x0 - 0.13851852;
5855    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
5856    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5857    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
5858    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
5859    let by = by - q;
5860    let bz = bz - q;
5861    let p3 = 0.00004263;
5862    let zh = (sr - mr) / lj;
5863    let tc = x0 + zh;
5864    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
5865    let s2 = sh * sh;
5866    let z2 = zh * zh;
5867    let ps = p3 / (rr * lj);
5868    let z1 = (zh * z2 / (z2 + s2)) + x0;
5869    let h0 = (hy + hz) / (2.0 * lj);
5870    let rm = 0.272446 * h0;
5871    let rn = 0.00465242 / (lj * rr);
5872    let hd = h0 * 0.99834;
5873    let ru = (hd - rn + ps) * 1.02;
5874    let rp = (hd + rn + ps) * 1.02;
5875    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
5876    let r = rm + rp;
5877    let dd = z1 - x0;
5878    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5879
5880    if dd < 0.0 {
5881        return -99.0;
5882    }
5883
5884    let zd = (dd).sqrt();
5885    let z6 = z1 - zd;
5886    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5887
5888    if z6 < 0.0 {
5889        let _z6 = z6 + 24.0;
5890    }
5891
5892    let r = rm + ru;
5893    let dd = z1 - x0;
5894    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5895    let _mg = (rm + rp - pj) / (2.0 * rm);
5896
5897    if dd < 0.0 {
5898        return -99.0;
5899    }
5900
5901    let zd = (dd).sqrt();
5902    let z8 = z1 - zd;
5903    let _z9 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5904
5905    if z8 < 0.0 {
5906        let _z8 = z8 + 24.0;
5907    }
5908
5909    let r = ru - rm;
5910    let dd = z1 - x0;
5911    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5912    let _mg = (rm + ru - pj) / (2.0 * rm);
5913
5914    if dd < 0.0 {
5915        return -99.0;
5916    }
5917
5918    let zd = (dd).sqrt();
5919    let mut zcc = z1 - zd;
5920    let _zb = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
5921
5922    if zcc < 0.0 {
5923        zcc = zc as f64 + 24.0;
5924    }
5925
5926    return zcc;
5927}
5928
5929/// Calculate end time of total phase of lunar eclipse (UT).
5930///
5931/// Original macro name: UTEndTotalLunarEclipse
5932pub fn ut_end_total_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
5933    let tp = 2.0 * std::f64::consts::PI;
5934
5935    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
5936        return -99.0;
5937    }
5938
5939    let dj = full_moon(ds, zc, dy, mn, yr);
5940    let _dp = 0.0;
5941    let gday = jdc_day(dj);
5942    let gmonth = jdc_month(dj);
5943    let gyear = jdc_year(dj);
5944    let igday = gday.floor();
5945    let xi = gday - igday;
5946    let utfm = xi * 24.0;
5947    let ut = utfm - 1.0;
5948    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5949    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5950    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5951    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5952    let ut = utfm + 1.0;
5953    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
5954    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5955    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5956    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5957
5958    if sb < 0.0 {
5959        sb = sb + tp;
5960    }
5961
5962    let xh = utfm;
5963    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
5964    let mut dm = mz - my;
5965
5966    if dm < 0.0 {
5967        dm = dm + tp;
5968    }
5969
5970    let lj = (dm - sb) / 2.0;
5971    let q = 0.0;
5972    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
5973    let ut = x0 - 0.13851852;
5974    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
5975    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
5976    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
5977    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
5978    let by = by - q;
5979    let bz = bz - q;
5980    let p3 = 0.00004263;
5981    let zh = (sr - mr) / lj;
5982    let tc = x0 + zh;
5983    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
5984    let s2 = sh * sh;
5985    let z2 = zh * zh;
5986    let ps = p3 / (rr * lj);
5987    let z1 = (zh * z2 / (z2 + s2)) + x0;
5988    let h0 = (hy + hz) / (2.0 * lj);
5989    let rm = 0.272446 * h0;
5990    let rn = 0.00465242 / (lj * rr);
5991    let hd = h0 * 0.99834;
5992    let ru = (hd - rn + ps) * 1.02;
5993    let rp = (hd + rn + ps) * 1.02;
5994    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
5995    let r = rm + rp;
5996    let dd = z1 - x0;
5997    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
5998
5999    if dd < 0.0 {
6000        return -99.0;
6001    }
6002
6003    let zd = dd.sqrt();
6004    let z6 = z1 - zd;
6005    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6006
6007    if z6 < 0.0 {
6008        let _z6 = z6 + 24.0;
6009    }
6010
6011    let r = rm + ru;
6012    let dd = z1 - x0;
6013    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6014    let _mg = (rm + rp - pj) / (2.0 * rm);
6015
6016    if dd < 0.0 {
6017        return -99.0;
6018    }
6019
6020    let zd = dd.sqrt();
6021    let z8 = z1 - zd;
6022    let _z9 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6023
6024    if z8 < 0.0 {
6025        let _z8 = z8 + 24.0;
6026    }
6027
6028    let r = ru - rm;
6029    let dd = z1 - x0;
6030    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6031    let _mg = (rm + ru - pj) / (2.0 * rm);
6032
6033    if dd < 0.0 {
6034        return -99.0;
6035    }
6036
6037    let zd = dd.sqrt();
6038    let zb = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6039
6040    return zb;
6041}
6042
6043/// Calculate magnitude of lunar eclipse.
6044///
6045/// Original macro name: MagLunarEclipse
6046pub fn mag_lunar_eclipse(dy: f64, mn: u32, yr: u32, ds: i32, zc: i32) -> f64 {
6047    let tp = 2.0 * std::f64::consts::PI;
6048
6049    if lunar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No lunar eclipse" {
6050        return -99.0;
6051    }
6052
6053    let dj = full_moon(ds, zc, dy, mn, yr);
6054    let _dp = 0.0;
6055    let gday = jdc_day(dj);
6056    let gmonth = jdc_month(dj);
6057    let gyear = jdc_year(dj);
6058    let igday = gday.floor();
6059    let xi = gday - igday;
6060    let utfm = xi * 24.0;
6061    let ut = utfm - 1.0;
6062    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6063    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6064    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6065    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6066    let ut = utfm + 1.0;
6067    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
6068    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6069    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6070    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6071
6072    if sb < 0.0 {
6073        sb = sb + tp;
6074    }
6075
6076    let xh = utfm;
6077    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
6078    let mut dm = mz - my;
6079
6080    if dm < 0.0 {
6081        dm = dm + tp;
6082    }
6083
6084    let lj = (dm - sb) / 2.0;
6085    let q = 0.0;
6086    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
6087    let ut = x0 - 0.13851852;
6088    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
6089    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6090    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
6091    let sr = sr + std::f64::consts::PI - lint((sr + std::f64::consts::PI) / tp) * tp;
6092    let by = by - q;
6093    let bz = bz - q;
6094    let p3 = 0.00004263;
6095    let zh = (sr - mr) / lj;
6096    let tc = x0 + zh;
6097    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
6098    let s2 = sh * sh;
6099    let z2 = zh * zh;
6100    let ps = p3 / (rr * lj);
6101    let z1 = (zh * z2 / (z2 + s2)) + x0;
6102    let h0 = (hy + hz) / (2.0 * lj);
6103    let rm = 0.272446 * h0;
6104    let rn = 0.00465242 / (lj * rr);
6105    let hd = h0 * 0.99834;
6106    let ru = (hd - rn + ps) * 1.02;
6107    let rp = (hd + rn + ps) * 1.02;
6108    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
6109    let r = rm + rp;
6110    let dd = z1 - x0;
6111    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6112
6113    if dd < 0.0 {
6114        return -99.0;
6115    }
6116
6117    let zd = dd.sqrt();
6118    let z6 = z1 - zd;
6119    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6120
6121    if z6 < 0.0 {
6122        let _z6 = z6 + 24.0;
6123    }
6124
6125    let r = rm + ru;
6126    let dd = z1 - x0;
6127    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6128    let mg = (rm + rp - pj) / (2.0 * rm);
6129
6130    if dd < 0.0 {
6131        return mg;
6132    }
6133
6134    let zd = dd.sqrt();
6135    let z8 = z1 - zd;
6136    let _z9 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6137
6138    if z8 < 0.0 {
6139        let _z8 = z8 + 24.0;
6140    }
6141
6142    let r = ru - rm;
6143    let dd = z1 - x0;
6144    let _dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6145    let mg = (rm + ru - pj) / (2.0 * rm);
6146
6147    return mg;
6148}
6149
6150/// Determine if a solar eclipse is likely to occur.
6151///
6152/// Original macro name: SEOccurrence
6153pub fn solar_eclipse_occurrence(ds: i32, zc: i32, dy: f64, mn: u32, yr: u32) -> String {
6154    let d0 = lct_gday(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
6155    let m0 = lct_gmonth(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
6156    let y0 = lct_gyear(12.0, 0.0, 0.0, ds, zc, dy, mn, yr);
6157
6158    let j0 = cd_jd(0.0, 1, y0);
6159    let dj = cd_jd(d0, m0, y0);
6160    let k = (y0 as f64 - 1900.0 + ((dj - j0) * 1.0 / 365.0)) * 12.3685;
6161    let k = lint(k + 0.5);
6162    let tn = k / 1236.85;
6163    let tf = (k + 0.5) / 1236.85;
6164    let t = tn;
6165    let (f, _dd, _e1, _b1, a, b) = solar_eclipse_occurrence_l6855(t, k);
6166    let _ni = a;
6167    let _nf = b;
6168    let nb = f;
6169    let t = tf;
6170    let k = k + 0.5;
6171    let (f, _dd, _e1, _b1, a, b) = solar_eclipse_occurrence_l6855(t, k);
6172    let _fi = a;
6173    let _ff = b;
6174    let _fb = f;
6175
6176    let mut df = (nb - 3.141592654 * lint(nb / 3.141592654)).abs();
6177
6178    if df > 0.37 {
6179        df = 3.141592654 - df;
6180    }
6181
6182    let mut s = "Solar eclipse certain";
6183    if df >= 0.242600766 {
6184        s = "Solar eclipse possible";
6185        if df > 0.37 {
6186            s = "No solar eclipse";
6187        }
6188    }
6189
6190    return s.to_string();
6191}
6192
6193/// Helper function for solar_eclipse_occurrence.
6194pub fn solar_eclipse_occurrence_l6855(t: f64, k: f64) -> (f64, f64, f64, f64, f64, f64) {
6195    let t2 = t * t;
6196    let e = 29.53 * k;
6197    let c = 166.56 + (132.87 - 0.009173 * t) * t;
6198    let c = c.to_radians();
6199    let b = 0.00058868 * k + (0.0001178 - 0.000000155 * t) * t2;
6200    let b = b + 0.00033 * c.sin() + 0.75933;
6201    let a = k / 12.36886;
6202    let a1 = 359.2242 + 360.0 * f_part(a) - (0.0000333 + 0.00000347 * t) * t2;
6203    let a2 = 306.0253 + 360.0 * f_part(k / 0.9330851);
6204    let a2 = a2 + (0.0107306 + 0.00001236 * t) * t2;
6205    let a = k / 0.9214926;
6206    let f = 21.2964 + 360.0 * f_part(a) - (0.0016528 + 0.00000239 * t) * t2;
6207    let a1 = unwind_deg(a1);
6208    let a2 = unwind_deg(a2);
6209    let f = unwind_deg(f);
6210    let a1 = a1.to_radians();
6211    let a2 = a2.to_radians();
6212    let f = f.to_radians();
6213
6214    let dd = (0.1734 - 0.000393 * t) * (a1).sin() + 0.0021 * (2.0 * a1).sin();
6215    let dd = dd - 0.4068 * (a2).sin() + 0.0161 * (2.0 * a2).sin() - 0.0004 * (3.0 * a2).sin();
6216    let dd = dd + 0.0104 * (2.0 * f).sin() - 0.0051 * (a1 + a2).sin();
6217    let dd = dd - 0.0074 * (a1 - a2).sin() + 0.0004 * (2.0 * f + a1).sin();
6218    let dd = dd - 0.0004 * (2.0 * f - a1).sin() - 0.0006 * (2.0 * f + a2).sin()
6219        + 0.001 * (2.0 * f - a2).sin();
6220    let dd = dd + 0.0005 * (a1 + 2.0 * a2).sin();
6221    let e1 = e.floor();
6222    let b = b + dd + (e - e1);
6223    let b1 = b.floor();
6224    let a = e1 + b1;
6225    let b = b - b1;
6226
6227    return (f, dd, e1, b1, a, b);
6228}
6229
6230/// Calculate time of maximum shadow for solar eclipse (UT).
6231///
6232/// Original macro name: UTMaxSolarEclipse
6233pub fn ut_max_solar_eclipse(
6234    dy: f64,
6235    mn: u32,
6236    yr: u32,
6237    ds: i32,
6238    zc: i32,
6239    glong: f64,
6240    glat: f64,
6241) -> f64 {
6242    let tp = 2.0 * std::f64::consts::PI;
6243
6244    if solar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No solar eclipse" {
6245        return -99.0;
6246    }
6247
6248    let dj = new_moon(ds, zc, dy, mn, yr);
6249    let _dp = 0.0;
6250    let gday = jdc_day(dj);
6251    let gmonth = jdc_month(dj);
6252    let gyear = jdc_year(dj);
6253    let igday = gday.floor();
6254    let xi = gday - igday;
6255    let utnm = xi * 24.0;
6256    let ut = utnm - 1.0;
6257    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6258    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6259    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6260    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6261    let ut = utnm + 1.0;
6262    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
6263    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6264    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6265    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6266
6267    if sb < 0.0 {
6268        sb = sb + tp;
6269    }
6270
6271    let xh = utnm;
6272    let x = my;
6273    let y = by;
6274    let tm = xh - 1.0;
6275    let hp = hy;
6276    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6277        ut_max_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6278    let my = p;
6279    let by = q;
6280    let x = mz;
6281    let y = bz;
6282    let tm = xh + 1.0;
6283    let hp = hz;
6284    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6285        ut_max_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6286    let mz = p;
6287    let bz = q;
6288
6289    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
6290    let mut dm = mz - my;
6291
6292    if dm < 0.0 {
6293        dm = dm + tp;
6294    }
6295
6296    let lj = (dm - sb) / 2.0;
6297    let _q = 0.0;
6298    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
6299    let ut = x0 - 0.13851852;
6300    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
6301    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6302    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
6303    let x = sr;
6304    let y = 0.0;
6305    let tm = ut;
6306    let hp = 0.00004263452 / rr;
6307    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6308        ut_max_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6309    let sr = p;
6310    let by = by - q;
6311    let bz = bz - q;
6312    let p3 = 0.00004263;
6313    let zh = (sr - mr) / lj;
6314    let tc = x0 + zh;
6315    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
6316    let s2 = sh * sh;
6317    let z2 = zh * zh;
6318    let ps = p3 / (rr * lj);
6319    let z1 = (zh * z2 / (z2 + s2)) + x0;
6320    let h0 = (hy + hz) / (2.0 * lj);
6321    let rm = 0.272446 * h0;
6322    let rn = 0.00465242 / (lj * rr);
6323    let hd = h0 * 0.99834;
6324    let _ru = (hd - rn + ps) * 1.02;
6325    let _rp = (hd + rn + ps) * 1.02;
6326    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
6327    let r = rm + rn;
6328    let dd = z1 - x0;
6329    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6330
6331    if dd < 0.0 {
6332        return -99.0;
6333    }
6334
6335    let zd = dd.sqrt();
6336    let _z6 = z1 - zd;
6337    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6338
6339    /*
6340    if z6 < 0.0 {
6341        z6 = z6 + 24.0;
6342    }
6343    */
6344
6345    let _mg = (rm + rn - pj) / (2.0 * rn);
6346
6347    return z1;
6348}
6349
6350/// Helper function for ut_max_solar_eclipse.
6351pub fn ut_max_solar_eclipse_l7390(
6352    x: f64,
6353    y: f64,
6354    igday: f64,
6355    gmonth: u32,
6356    gyear: u32,
6357    tm: f64,
6358    glong: f64,
6359    glat: f64,
6360    hp: f64,
6361) -> (f64, f64, f64, f64, f64, f64, f64, f64) {
6362    let paa = ec_ra(
6363        degrees(x),
6364        0.0,
6365        0.0,
6366        degrees(y),
6367        0.0,
6368        0.0,
6369        igday,
6370        gmonth,
6371        gyear,
6372    );
6373    let qaa = ec_dec(
6374        degrees(x),
6375        0.0,
6376        0.0,
6377        degrees(y),
6378        0.0,
6379        0.0,
6380        igday,
6381        gmonth,
6382        gyear,
6383    );
6384    let xaa = ra_ha(
6385        dd_dh(paa),
6386        0.0,
6387        0.0,
6388        tm,
6389        0.0,
6390        0.0,
6391        0,
6392        0,
6393        igday,
6394        gmonth,
6395        gyear,
6396        glong,
6397    );
6398    let pbb = parallax_ha(
6399        xaa,
6400        0.0,
6401        0.0,
6402        qaa,
6403        0.0,
6404        0.0,
6405        "true".to_string(),
6406        glat,
6407        0.0,
6408        degrees(hp),
6409    );
6410    let qbb = parallax_dec(
6411        xaa,
6412        0.0,
6413        0.0,
6414        qaa,
6415        0.0,
6416        0.0,
6417        "true".to_string(),
6418        glat,
6419        0.0,
6420        degrees(hp),
6421    );
6422    let xbb = ha_ra(
6423        pbb, 0.0, 0.0, tm, 0.0, 0.0, 0, 0, igday, gmonth, gyear, glong,
6424    );
6425    let p = (eq_e_long(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
6426    let q = (eq_e_lat(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
6427
6428    return (paa, qaa, xaa, pbb, qbb, xbb, p, q);
6429}
6430
6431/// Calculate time of first contact for solar eclipse (UT).
6432///
6433/// Original macro name: UTFirstContactSolarEclipse
6434pub fn ut_first_contact_solar_eclipse(
6435    dy: f64,
6436    mn: u32,
6437    yr: u32,
6438    ds: i32,
6439    zc: i32,
6440    glong: f64,
6441    glat: f64,
6442) -> f64 {
6443    let tp = 2.0 * std::f64::consts::PI;
6444
6445    if solar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No solar eclipse" {
6446        return -99.0;
6447    }
6448
6449    let dj = new_moon(ds, zc, dy, mn, yr);
6450    let _dp = 0.0;
6451    let gday = jdc_day(dj);
6452    let gmonth = jdc_month(dj);
6453    let gyear = jdc_year(dj);
6454    let igday = gday.floor();
6455    let xi = gday - igday;
6456    let utnm = xi * 24.0;
6457    let ut = utnm - 1.0;
6458    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6459    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6460    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6461    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6462    let ut = utnm + 1.0;
6463    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
6464    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6465    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6466    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6467
6468    if sb < 0.0 {
6469        sb = sb + tp;
6470    }
6471
6472    let xh = utnm;
6473    let x = my;
6474    let y = by;
6475    let tm = xh - 1.0;
6476    let hp = hy;
6477    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6478        ut_first_contact_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6479    let my = p;
6480    let by = q;
6481    let x = mz;
6482    let y = bz;
6483    let tm = xh + 1.0;
6484    let hp = hz;
6485    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6486        ut_first_contact_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6487    let mz = p;
6488    let bz = q;
6489
6490    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
6491    let mut dm = mz - my;
6492
6493    if dm < 0.0 {
6494        dm = dm + tp;
6495    }
6496
6497    let lj = (dm - sb) / 2.0;
6498    let _q = 0.0;
6499    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
6500    let ut = x0 - 0.13851852;
6501    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
6502    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6503    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
6504    let x = sr;
6505    let y = 0.0;
6506    let tm = ut;
6507    let hp = 0.00004263452 / rr;
6508    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6509        ut_first_contact_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6510    let sr = p;
6511    let by = by - q;
6512    let bz = bz - q;
6513    let p3 = 0.00004263;
6514    let zh = (sr - mr) / lj;
6515    let tc = x0 + zh;
6516    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
6517    let s2 = sh * sh;
6518    let z2 = zh * zh;
6519    let ps = p3 / (rr * lj);
6520    let z1 = (zh * z2 / (z2 + s2)) + x0;
6521    let h0 = (hy + hz) / (2.0 * lj);
6522    let rm = 0.272446 * h0;
6523    let rn = 0.00465242 / (lj * rr);
6524    let hd = h0 * 0.99834;
6525    let _ru = (hd - rn + ps) * 1.02;
6526    let _rp = (hd + rn + ps) * 1.02;
6527    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
6528    let r = rm + rn;
6529    let dd = z1 - x0;
6530    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6531
6532    if dd < 0.0 {
6533        return -99.0;
6534    }
6535
6536    let zd = dd.sqrt();
6537    let mut z6 = z1 - zd;
6538    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6539
6540    if z6 < 0.0 {
6541        z6 = z6 + 24.0;
6542    }
6543
6544    let _mg = (rm + rn - pj) / (2.0 * rn);
6545
6546    return z6;
6547}
6548
6549/// Helper function for ut_first_contact_solar_eclipse.
6550pub fn ut_first_contact_solar_eclipse_l7390(
6551    x: f64,
6552    y: f64,
6553    igday: f64,
6554    gmonth: u32,
6555    gyear: u32,
6556    tm: f64,
6557    glong: f64,
6558    glat: f64,
6559    hp: f64,
6560) -> (f64, f64, f64, f64, f64, f64, f64, f64) {
6561    let paa = ec_ra(
6562        degrees(x),
6563        0.0,
6564        0.0,
6565        degrees(y),
6566        0.0,
6567        0.0,
6568        igday,
6569        gmonth,
6570        gyear,
6571    );
6572    let qaa = ec_dec(
6573        degrees(x),
6574        0.0,
6575        0.0,
6576        degrees(y),
6577        0.0,
6578        0.0,
6579        igday,
6580        gmonth,
6581        gyear,
6582    );
6583    let xaa = ra_ha(
6584        dd_dh(paa),
6585        0.0,
6586        0.0,
6587        tm,
6588        0.0,
6589        0.0,
6590        0,
6591        0,
6592        igday,
6593        gmonth,
6594        gyear,
6595        glong,
6596    );
6597    let pbb = parallax_ha(
6598        xaa,
6599        0.0,
6600        0.0,
6601        qaa,
6602        0.0,
6603        0.0,
6604        "true".to_string(),
6605        glat,
6606        0.0,
6607        degrees(hp),
6608    );
6609    let qbb = parallax_dec(
6610        xaa,
6611        0.0,
6612        0.0,
6613        qaa,
6614        0.0,
6615        0.0,
6616        "true".to_string(),
6617        glat,
6618        0.0,
6619        degrees(hp),
6620    );
6621    let xbb = ha_ra(
6622        pbb, 0.0, 0.0, tm, 0.0, 0.0, 0, 0, igday, gmonth, gyear, glong,
6623    );
6624    let p = (eq_e_long(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
6625    let q = (eq_e_lat(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
6626
6627    return (paa, qaa, xaa, pbb, qbb, xbb, p, q);
6628}
6629
6630/// Calculate time of last contact for solar eclipse (UT).
6631///
6632/// Original macro name: UTLastContactSolarEclipse
6633pub fn ut_last_contact_solar_eclipse(
6634    dy: f64,
6635    mn: u32,
6636    yr: u32,
6637    ds: i32,
6638    zc: i32,
6639    glong: f64,
6640    glat: f64,
6641) -> f64 {
6642    let tp = 2.0 * std::f64::consts::PI;
6643
6644    if solar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No solar eclipse" {
6645        return -99.0;
6646    }
6647
6648    let dj = new_moon(ds, zc, dy, mn, yr);
6649    let _dp = 0.0;
6650    let gday = jdc_day(dj);
6651    let gmonth = jdc_month(dj);
6652    let gyear = jdc_year(dj);
6653    let igday = gday.floor();
6654    let xi = gday - igday;
6655    let utnm = xi * 24.0;
6656    let ut = utnm - 1.0;
6657    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6658    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6659    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6660    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6661    let ut = utnm + 1.0;
6662    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
6663    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6664    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6665    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6666
6667    if sb < 0.0 {
6668        sb = sb + tp;
6669    }
6670
6671    let xh = utnm;
6672    let x = my;
6673    let y = by;
6674    let tm = xh - 1.0;
6675    let hp = hy;
6676    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6677        ut_last_contact_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6678    let my = p;
6679    let by = q;
6680    let x = mz;
6681    let y = bz;
6682    let tm = xh + 1.0;
6683    let hp = hz;
6684    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6685        ut_last_contact_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6686    let mz = p;
6687    let bz = q;
6688
6689    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
6690    let mut dm = mz - my;
6691
6692    if dm < 0.0 {
6693        dm = dm + tp;
6694    }
6695
6696    let lj = (dm - sb) / 2.0;
6697    let _q = 0.0;
6698    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
6699    let ut = x0 - 0.13851852;
6700    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
6701    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6702    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
6703    let x = sr;
6704    let y = 0.0;
6705    let tm = ut;
6706    let hp = 0.00004263452 / rr;
6707    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6708        ut_last_contact_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6709    let sr = p;
6710    let by = by - q;
6711    let bz = bz - q;
6712    let p3 = 0.00004263;
6713    let zh = (sr - mr) / lj;
6714    let tc = x0 + zh;
6715    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
6716    let s2 = sh * sh;
6717    let z2 = zh * zh;
6718    let ps = p3 / (rr * lj);
6719    let z1 = (zh * z2 / (z2 + s2)) + x0;
6720    let h0 = (hy + hz) / (2.0 * lj);
6721    let rm = 0.272446 * h0;
6722    let rn = 0.00465242 / (lj * rr);
6723    let hd = h0 * 0.99834;
6724    let _ru = (hd - rn + ps) * 1.02;
6725    let _rp = (hd + rn + ps) * 1.02;
6726    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
6727    let r = rm + rn;
6728    let dd = z1 - x0;
6729    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6730
6731    if dd < 0.0 {
6732        return -99.0;
6733    }
6734
6735    let zd = dd.sqrt();
6736    let _z6 = z1 - zd;
6737    let z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6738
6739    /*
6740    if z6 < 0.0 {
6741        z6 = z6 + 24.0;
6742    }
6743    */
6744
6745    let _mg = (rm + rn - pj) / (2.0 * rn);
6746
6747    return z7;
6748}
6749
6750/// Helper function for ut_last_contact_solar_eclipse.
6751pub fn ut_last_contact_solar_eclipse_l7390(
6752    x: f64,
6753    y: f64,
6754    igday: f64,
6755    gmonth: u32,
6756    gyear: u32,
6757    tm: f64,
6758    glong: f64,
6759    glat: f64,
6760    hp: f64,
6761) -> (f64, f64, f64, f64, f64, f64, f64, f64) {
6762    let paa = ec_ra(
6763        degrees(x),
6764        0.0,
6765        0.0,
6766        degrees(y),
6767        0.0,
6768        0.0,
6769        igday,
6770        gmonth,
6771        gyear,
6772    );
6773    let qaa = ec_dec(
6774        degrees(x),
6775        0.0,
6776        0.0,
6777        degrees(y),
6778        0.0,
6779        0.0,
6780        igday,
6781        gmonth,
6782        gyear,
6783    );
6784    let xaa = ra_ha(
6785        dd_dh(paa),
6786        0.0,
6787        0.0,
6788        tm,
6789        0.0,
6790        0.0,
6791        0,
6792        0,
6793        igday,
6794        gmonth,
6795        gyear,
6796        glong,
6797    );
6798    let pbb = parallax_ha(
6799        xaa,
6800        0.0,
6801        0.0,
6802        qaa,
6803        0.0,
6804        0.0,
6805        "true".to_string(),
6806        glat,
6807        0.0,
6808        degrees(hp),
6809    );
6810    let qbb = parallax_dec(
6811        xaa,
6812        0.0,
6813        0.0,
6814        qaa,
6815        0.0,
6816        0.0,
6817        "true".to_string(),
6818        glat,
6819        0.0,
6820        degrees(hp),
6821    );
6822    let xbb = ha_ra(
6823        pbb, 0.0, 0.0, tm, 0.0, 0.0, 0, 0, igday, gmonth, gyear, glong,
6824    );
6825    let p = (eq_e_long(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
6826    let q = (eq_e_lat(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
6827
6828    return (paa, qaa, xaa, pbb, qbb, xbb, p, q);
6829}
6830
6831/// Calculate magnitude of solar eclipse.
6832///
6833/// Original macro name: MagSolarEclipse
6834pub fn mag_solar_eclipse(
6835    dy: f64,
6836    mn: u32,
6837    yr: u32,
6838    ds: i32,
6839    zc: i32,
6840    glong: f64,
6841    glat: f64,
6842) -> f64 {
6843    let tp = 2.0 * std::f64::consts::PI;
6844
6845    if solar_eclipse_occurrence(ds, zc, dy, mn, yr) == "No solar eclipse" {
6846        return -99.0;
6847    }
6848
6849    let dj = new_moon(ds, zc, dy, mn, yr);
6850    let _dp = 0.0;
6851    let gday = jdc_day(dj);
6852    let gmonth = jdc_month(dj);
6853    let gyear = jdc_year(dj);
6854    let igday = gday.floor();
6855    let xi = gday - igday;
6856    let utnm = xi * 24.0;
6857    let ut = utnm - 1.0;
6858    let ly = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6859    let my = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6860    let by = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6861    let hy = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6862    let ut = utnm + 1.0;
6863    let mut sb = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians() - ly;
6864    let mz = (moon_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6865    let bz = (moon_lat(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6866    let hz = (moon_hp(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6867
6868    if sb < 0.0 {
6869        sb = sb + tp;
6870    }
6871
6872    let xh = utnm;
6873    let x = my;
6874    let y = by;
6875    let tm = xh - 1.0;
6876    let hp = hy;
6877    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6878        mag_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6879    let my = p;
6880    let by = q;
6881    let x = mz;
6882    let y = bz;
6883    let tm = xh + 1.0;
6884    let hp = hz;
6885    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6886        mag_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6887    let mz = p;
6888    let bz = q;
6889
6890    let x0 = xh + 1.0 - (2.0 * bz / (bz - by));
6891    let mut dm = mz - my;
6892
6893    if dm < 0.0 {
6894        dm = dm + tp;
6895    }
6896
6897    let lj = (dm - sb) / 2.0;
6898    let _q = 0.0;
6899    let mr = my + (dm * (x0 - xh + 1.0) / 2.0);
6900    let ut = x0 - 0.13851852;
6901    let rr = sun_dist(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear);
6902    let sr = (sun_long(ut, 0.0, 0.0, 0, 0, igday, gmonth, gyear)).to_radians();
6903    let sr = sr + (nutat_long(igday, gmonth, gyear) - 0.00569).to_radians();
6904    let x = sr;
6905    let y = 0.0;
6906    let tm = ut;
6907    let hp = 0.00004263452 / rr;
6908    let (_paa, _qaa, _xaa, _pbb, _qbb, _xbb, p, q) =
6909        mag_solar_eclipse_l7390(x, y, igday, gmonth, gyear, tm, glong, glat, hp);
6910    let sr = p;
6911    let by = by - q;
6912    let bz = bz - q;
6913    let p3 = 0.00004263;
6914    let zh = (sr - mr) / lj;
6915    let tc = x0 + zh;
6916    let sh = (((bz - by) * (tc - xh - 1.0) / 2.0) + bz) / lj;
6917    let s2 = sh * sh;
6918    let z2 = zh * zh;
6919    let ps = p3 / (rr * lj);
6920    let z1 = (zh * z2 / (z2 + s2)) + x0;
6921    let h0 = (hy + hz) / (2.0 * lj);
6922    let rm = 0.272446 * h0;
6923    let rn = 0.00465242 / (lj * rr);
6924    let hd = h0 * 0.99834;
6925    let _ru = (hd - rn + ps) * 1.02;
6926    let _rp = (hd + rn + ps) * 1.02;
6927    let pj = (sh * zh / (s2 + z2).sqrt()).abs();
6928    let r = rm + rn;
6929    let dd = z1 - x0;
6930    let dd = dd * dd - ((z2 - (r * r)) * dd / zh);
6931
6932    if dd < 0.0 {
6933        return -99.0;
6934    }
6935
6936    let zd = dd.sqrt();
6937    let _z6 = z1 - zd;
6938    let _z7 = z1 + zd - lint((z1 + zd) / 24.0) * 24.0;
6939
6940    /*
6941    if z6 < 0.0 {
6942        z6 = z6 + 24.0;
6943    }
6944    */
6945
6946    let mg = (rm + rn - pj) / (2.0 * rn);
6947
6948    return mg;
6949}
6950
6951/// Helper function for mag_solar_eclipse.
6952pub fn mag_solar_eclipse_l7390(
6953    x: f64,
6954    y: f64,
6955    igday: f64,
6956    gmonth: u32,
6957    gyear: u32,
6958    tm: f64,
6959    glong: f64,
6960    glat: f64,
6961    hp: f64,
6962) -> (f64, f64, f64, f64, f64, f64, f64, f64) {
6963    let paa = ec_ra(
6964        degrees(x),
6965        0.0,
6966        0.0,
6967        degrees(y),
6968        0.0,
6969        0.0,
6970        igday,
6971        gmonth,
6972        gyear,
6973    );
6974    let qaa = ec_dec(
6975        degrees(x),
6976        0.0,
6977        0.0,
6978        degrees(y),
6979        0.0,
6980        0.0,
6981        igday,
6982        gmonth,
6983        gyear,
6984    );
6985    let xaa = ra_ha(
6986        dd_dh(paa),
6987        0.0,
6988        0.0,
6989        tm,
6990        0.0,
6991        0.0,
6992        0,
6993        0,
6994        igday,
6995        gmonth,
6996        gyear,
6997        glong,
6998    );
6999    let pbb = parallax_ha(
7000        xaa,
7001        0.0,
7002        0.0,
7003        qaa,
7004        0.0,
7005        0.0,
7006        "true".to_string(),
7007        glat,
7008        0.0,
7009        degrees(hp),
7010    );
7011    let qbb = parallax_dec(
7012        xaa,
7013        0.0,
7014        0.0,
7015        qaa,
7016        0.0,
7017        0.0,
7018        "true".to_string(),
7019        glat,
7020        0.0,
7021        degrees(hp),
7022    );
7023    let xbb = ha_ra(
7024        pbb, 0.0, 0.0, tm, 0.0, 0.0, 0, 0, igday, gmonth, gyear, glong,
7025    );
7026    let p = (eq_e_long(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
7027    let q = (eq_e_lat(xbb, 0.0, 0.0, qbb, 0.0, 0.0, igday, gmonth, gyear)).to_radians();
7028
7029    return (paa, qaa, xaa, pbb, qbb, xbb, p, q);
7030}