1use geographiclib_rs::{DirectGeodesic, Geodesic};
4
5pub fn resolve_gps_location(
15 camera_coords: (f64, f64),
17 altitude: f64,
18 heading: f64,
19 target_position: (i32, i32),
20) -> (f64, f64) {
21 let h_fov_deg = constants::CAMERA_H_FOV;
22 let resolution = (
23 constants::CAMERA_RESOLUTION_H,
24 constants::CAMERA_RESOLUTION_V,
25 );
26
27 let mpp = meters_per_pixel(altitude, h_fov_deg, resolution);
29 let camera_center_pixels = (resolution.0 / 2, resolution.1 / 2);
30
31 let pixel_distance = (((target_position.0 - camera_center_pixels.0).pow(2)
32 + (target_position.1 - camera_center_pixels.1).pow(2)) as f64)
33 .sqrt();
34
35 let meters_distance = pixel_distance * mpp;
36
37 if meters_distance < 1e-6 {
38 return camera_coords;
39 }
40
41 let dx = (target_position.0 - camera_center_pixels.0) as f64;
43 let dy = (target_position.1 - camera_center_pixels.1) as f64;
44 let inverted_dy = -dy;
45
46 let math_angle_rad = inverted_dy.atan2(dx);
47 let math_angle_deg = math_angle_rad.to_degrees();
48
49 let relative_bearing = (450.0 - math_angle_deg).rem_euclid(360.0);
50 let true_bearing = (heading + relative_bearing).rem_euclid(360.0);
51
52 let geodesic = Geodesic::wgs84();
54 let (target_lat, target_lon, _) = geodesic.direct(
55 camera_coords.0,
56 camera_coords.1,
57 true_bearing,
58 meters_distance,
59 );
60 (target_lat, target_lon)
61} fn meters_per_pixel(altitude: f64, h_fov_deg: f64, resolution: (i32, i32)) -> f64 {
65 let h_fov_rad = h_fov_deg.to_radians();
66
67 let aspect_ratio = resolution.1 as f64 / resolution.0 as f64;
69 let v_fov_rad = 2.0 * (aspect_ratio * (h_fov_rad / 2.0).tan()).atan();
70
71 let ground_width = 2.0 * altitude * (h_fov_rad / 2.0).tan();
72 let ground_height = 2.0 * altitude * (v_fov_rad / 2.0).tan();
73
74 let mpp_h = ground_width / resolution.0 as f64;
75 let mpp_v = ground_height / resolution.1 as f64;
76
77 (mpp_h + mpp_v) / 2.0
78}