JaiaBot 2.3.0
JaiaBot micro-AUV software
 
Loading...
Searching...
No Matches
mission_manager_utils.h
Go to the documentation of this file.
1#ifndef JAIABOT_UTILS_MISSION_MANAGER_UTILS_H
2#define JAIABOT_UTILS_MISSION_MANAGER_UTILS_H
3
4#include <cmath>
5#include <goby/util/geodesy.h>
7
8namespace jaiabot
9{
10namespace utils
11{
12
14{
15 double radius;
16 double heading;
17};
18
19// Calculate new geographic position from a starting point, distance, and heading
20// distance: meters, heading: compass degrees (0=North)
22 const goby::util::UTMGeodesy& geodesy,
23 const jaiabot::protobuf::GeographicCoordinate& start_location,
24 double distance_meters,
25 double heading_degrees)
26{
27 // Convert start position to Cartesian
28 auto start_xy = geodesy.convert({start_location.lat_with_units(), start_location.lon_with_units()});
29
30 // Convert heading to math angle (0=East, 90=North, counterclockwise)
31 double math_angle = 90.0 - heading_degrees;
32 if (math_angle < 0) math_angle += 360.0;
33 double angle_radians = math_angle * M_PI / 180.0;
34
35 // Calculate offset in meters
36 double dx = distance_meters * std::cos(angle_radians);
37 double dy = distance_meters * std::sin(angle_radians);
38
39 // Add offset to start position
40 auto end_xy = goby::util::UTMGeodesy::XYPoint{
41 start_xy.x + dx * boost::units::si::meters,
42 start_xy.y + dy * boost::units::si::meters
43 };
44
45 // Convert back to lat/lon
46 auto end_latlon = geodesy.convert(end_xy);
47
49 result.set_lat_with_units(end_latlon.lat);
50 result.set_lon_with_units(end_latlon.lon);
51
52 return result;
53}
54
55// Converts a cartesian coordinate (x, y) to a polar coordinate (r, θ)
56// Output: heading in compass degrees (0° = North)
57inline PolarCoordinate convert_cartesian_to_polar(double start_x, double start_y, double end_x, double end_y)
58{
59 double delta_x = end_x - start_x;
60 double delta_y = end_y - start_y;
61
62 double radius = std::sqrt(delta_x * delta_x + delta_y * delta_y);
63
64 // atan2(dy, dx) returns math angle in radians from -π to π (-180° to 180°)
65 // Math angle: 0° = East, 90° = North (counterclockwise from positive X-axis)
66 // Convert to compass heading: 0° = North, 90° = East (clockwise from North)
67 double math_angle = std::atan2(delta_y, delta_x) * 180.0 / M_PI;
68 double compass_heading = 90.0 - math_angle;
69 if (compass_heading < 0)
70 {
71 compass_heading += 360.0;
72 }
73
74 PolarCoordinate polar_coordinate;
75 polar_coordinate.radius = radius;
76 polar_coordinate.heading = compass_heading;
77
78 return polar_coordinate;
79}
80
81// Calculate where the dive ended by going backwards from where drift started
82// This accounts for the drift that happened during GPS reacquisition
84 const goby::util::UTMGeodesy& geodesy,
85 double duration_to_acquire_gps,
86 const jaiabot::protobuf::GeographicCoordinate& drift_start_location,
87 double drift_speed,
88 double drift_heading)
89{
90 double gps_acquire_distance = duration_to_acquire_gps * drift_speed;
91
92 // Get opposite heading (where we drifted FROM, not where we drifted TO)
93 double opposite_heading = std::fmod(drift_heading + 180.0, 360.0);
94
95 return calculate_position_from_offset(geodesy, drift_start_location, gps_acquire_distance, opposite_heading);
96}
97
98// Function from GeeksForGeeks: https://www.geeksforgeeks.org/dsa/haversine-formula-to-find-distance-between-two-points-on-a-sphere/
99inline float haversine(float lat1, float lon1,
100 float lat2, float lon2)
101{
102 // distance between latitudes
103 // and longitudes
104 float dLat = (lat2 - lat1) *
105 M_PI / 180.0;
106 float dLon = (lon2 - lon1) *
107 M_PI / 180.0;
108
109 // convert to radians
110 float lat1_rad = (lat1) * M_PI / 180.0;
111 float lat2_rad = (lat2) * M_PI / 180.0;
112
113 // apply formulae
114 float a = pow(sin(dLat / 2), 2) +
115 pow(sin(dLon / 2), 2) *
116 cos(lat1_rad) * cos(lat2_rad);
117 float rad = 6371.0;
118 float c = 2 * asin(sqrt(a));
119
120 return rad * c * 1000.0; // Convert to meters
121}
122
123inline float calculateHeading(double sx, double sy, double ex, double ey) {
124 auto dx = ex - sx, dy = ey - sy;
125
126 // atan2(dy, dx) returns math angle in radians from -π to π (-180° to 180°)
127 // Math angle: 0° = East, 90° = North (counterclockwise from positive X-axis)
128 // Convert to compass heading: 0° = North, 90° = East (clockwise from North)
129 double math_angle_rad = std::atan2(dy, dx);
130 double heading_rad = M_PI / 2.0 - math_angle_rad;
131
132 if (heading_rad < 0)
133 heading_rad = heading_rad + (2.0 * M_PI);
134
135 // Convert to degrees
136 return heading_rad * 180.0 / M_PI;
137}
138
139} // namespace utils
140} // namespace jaiabot
141
142#endif // JAIABOT_UTILS_MISSION_MANAGER_UTILS_H
PolarCoordinate convert_cartesian_to_polar(double start_x, double start_y, double end_x, double end_y)
float calculateHeading(double sx, double sy, double ex, double ey)
float haversine(float lat1, float lon1, float lat2, float lon2)
jaiabot::protobuf::GeographicCoordinate find_dive_end_location(const goby::util::UTMGeodesy &geodesy, double duration_to_acquire_gps, const jaiabot::protobuf::GeographicCoordinate &drift_start_location, double drift_speed, double drift_heading)
jaiabot::protobuf::GeographicCoordinate calculate_position_from_offset(const goby::util::UTMGeodesy &geodesy, const jaiabot::protobuf::GeographicCoordinate &start_location, double distance_meters, double heading_degrees)