1use core::f64::consts::{FRAC_PI_2, TAU};
2
3use crate::consts::{EARTH_RADIUS_KM_WGS84, FLATTENING_FACTOR, JULIAN_TIME_DIFF};
4use crate::julian_date::theta_g_jd;
5use crate::math::{fmod2p, Vec3};
6
7#[derive(Debug)]
8pub struct Geodetic {
9 pub lat: f64,
10 pub lon: f64,
11 pub alt: f64,
12 pub theta: f64,
13}
14
15#[must_use]
18pub fn calculate_lat_lon_alt(time: f64, pos: Vec3) -> Geodetic {
19 let newtime = time + JULIAN_TIME_DIFF;
29 let theta = pos.1.atan2(pos.0); let lon = fmod2p(theta - theta_g_jd(newtime)); let r = (pos.0.powf(2.0) + pos.1.powf(2.0)).sqrt();
32 let e2 = FLATTENING_FACTOR * (2.0 - FLATTENING_FACTOR);
33 let mut lat = pos.2.atan2(r); let mut phi;
35 let mut c;
36 loop {
37 phi = lat;
38 c = 1.0 / (1.0 - e2 * phi.sin().powf(2.0)).sqrt();
39 lat = (pos.2 + EARTH_RADIUS_KM_WGS84 * c * e2 * phi.sin()).atan2(r);
40 if (lat - phi).abs() < 1E-10 {
42 break;
43 }
44 }
45
46 let alt = r / lat.cos() - EARTH_RADIUS_KM_WGS84 * c; if lat > FRAC_PI_2 {
49 lat -= TAU;
50 }
51 Geodetic {
52 lat,
53 lon,
54 alt,
55 theta,
56 }
57}