@@ -36,10 +36,12 @@ struct GPSPoint {
36
36
double time;
37
37
double lat;
38
38
double lon;
39
- double heading; // True North
39
+ double heading; // True North (degrees)
40
40
};
41
41
42
42
struct GPSTranslator {
43
+ GPSTranslator () : is_origin_set(false ) {}
44
+
43
45
string GetMapFileFromName (const string& maps_dir, const string& map) {
44
46
return maps_dir + " /" + map + " /" + map + " .gpsmap.txt" ;
45
47
}
@@ -54,16 +56,19 @@ struct GPSTranslator {
54
56
}
55
57
printf (" Map origin: %12.8lf, %12.8lf\n " , gps_origin_latitude,
56
58
gps_origin_longitude);
59
+ is_origin_set = true ;
57
60
return true ;
58
61
}
59
62
60
63
void SetOrigin (double latitude, double longitude, double orientation) {
61
64
gps_origin_latitude = latitude;
62
65
gps_origin_longitude = longitude;
63
66
map_orientation = orientation;
67
+ is_origin_set = true ;
64
68
}
65
69
66
70
Vector2d GPSToMetric (const double latitude, const double longitude) {
71
+ CHECK (is_origin_set);
67
72
const double theta = DegToRad (latitude);
68
73
const double c = std::cos (theta);
69
74
const double s = std::sin (theta);
@@ -78,6 +83,7 @@ struct GPSTranslator {
78
83
}
79
84
80
85
void MetricToGPS (const Vector2d& loc, double * longitude, double * latitude) {
86
+ CHECK (is_origin_set);
81
87
const double theta = DegToRad (gps_origin_latitude);
82
88
const double c = std::cos (theta);
83
89
const double s = std::sin (theta);
@@ -93,6 +99,7 @@ struct GPSTranslator {
93
99
double gps_origin_longitude;
94
100
double gps_origin_latitude;
95
101
double map_orientation;
102
+ bool is_origin_set;
96
103
97
104
// Earth geoid parameters from WGS 84 system
98
105
// https://en.wikipedia.org/wiki/World_Geodetic_System#A_new_World_Geodetic_System:_WGS_84
@@ -156,6 +163,8 @@ inline std::tuple<double, double, int> gpsToUTM(double lat, double lon) {
156
163
}
157
164
158
165
inline double gpsDistance (const GPSPoint& p0, const GPSPoint& p1) {
166
+ const auto & [lat0, lon0] = std::make_tuple (p0.lat , p0.lon );
167
+ const auto & [lat1, lon1] = std::make_tuple (p1.lat , p1.lon );
159
168
// Convert latitude and longitude to radians
160
169
double lat0_rad = p0.lat * M_PI / 180.0 ;
161
170
double lon0_rad = p0.lon * M_PI / 180.0 ;
@@ -171,50 +180,48 @@ inline double gpsDistance(const GPSPoint& p0, const GPSPoint& p1) {
171
180
return 6371000 * c; // Radius of Earth in meters
172
181
}
173
182
174
- inline Vector2d gpsToGlobalCoord (const GPSPoint& p0, const GPSPoint& p1) {
183
+ inline Eigen::Vector2d gpsToGlobalCoord (const GPSPoint& p0,
184
+ const GPSPoint& p1) {
185
+ const auto & [lat0, lon0] = std::make_tuple (p0.lat , p0.lon );
186
+ const auto & [lat1, lon1] = std::make_tuple (p1.lat , p1.lon );
187
+
175
188
// Convert latitude and longitude to utm coordinates
176
- const auto & [e0 , n0, zone0] = gpsToUTM (p0.lat , p0.lon );
177
- const auto & [e1 , n1, zone1] = gpsToUTM (p1.lat , p1.lon );
178
- return {e1 - e0 , n1 - n0};
179
- }
189
+ const auto & [e0 , n0, zone0] = gpsToUTM (lat0, lon0);
190
+ const auto & [e1 , n1, zone1] = gpsToUTM (lat1, lon1);
180
191
181
- inline Eigen::Affine2f gpsToLocal (const GPSPoint& p0, const GPSPoint& p1) {
182
- // Step 1: Convert current and goal GPS coordinates to UTM
183
- const auto & [curr_easting, curr_northing, curr_zone] =
184
- gpsToUTM (p0.lat , p0.lon );
185
- const auto & [goal_easting, goal_northing, goal_zone] =
186
- gpsToUTM (p1.lat , p1.lon );
187
- // Ensure that both coordinates are in the same UTM zone
188
- if (goal_zone != curr_zone) {
192
+ if (zone0 != zone1) {
189
193
throw std::runtime_error (" GPS points are in different UTM zones." );
190
194
}
191
195
192
- // Step 2: Calculate the translation vector from the current position to the
193
- // goal in UTM
194
- double dx = goal_easting - curr_easting;
195
- double dy = goal_northing - curr_northing;
196
+ return {e1 - e0 , n1 - n0}; // x y
197
+ }
198
+
199
+ inline Eigen::Affine2f gpsToLocal (const GPSPoint& current,
200
+ const GPSPoint& goal) {
201
+ // Step 1: Convert the GPS coordinates to global coordinates
202
+ const auto & dvec = gpsToGlobalCoord (current, goal);
196
203
197
- // Step 3 : Convert the current heading to radians and adjust for x-axis
204
+ // Step 2 : Convert the current heading to radians and adjust for x-axis
198
205
// reference Since 0 degrees points along the y-axis and rotates
199
206
// counter-clockwise, convert to radians with 0 degrees aligned along the
200
207
// x-axis
201
- double current_heading_rad = (90.0 - p0 .heading ) * M_PI / 180.0 ;
208
+ double current_heading_rad = (90.0 - current .heading ) * M_PI / 180.0 ;
202
209
203
- // Step 4 : Rotate the translation vector to the robot's local frame
204
- double local_x =
205
- dx * cos (-current_heading_rad) - dy * sin (-current_heading_rad);
206
- double local_y =
207
- dx * sin (-current_heading_rad) + dy * cos (-current_heading_rad);
210
+ // Step 3 : Rotate the translation vector to the robot's local frame
211
+ double local_x = dvec. x () * cos (-current_heading_rad) -
212
+ dvec. y () * sin (-current_heading_rad);
213
+ double local_y = dvec. x () * sin (-current_heading_rad) +
214
+ dvec. y () * cos (-current_heading_rad);
208
215
209
- // Step 5 : Convert the goal heading to the local frame
210
- double goal_heading_rad = (90.0 - p1 .heading ) * M_PI / 180.0 ;
216
+ // Step 4 : Convert the goal heading to the local frame
217
+ double goal_heading_rad = (90.0 - goal .heading ) * M_PI / 180.0 ;
211
218
double local_heading = goal_heading_rad - current_heading_rad;
212
219
213
220
// Normalize local heading to the range [-pi, pi]
214
221
while (local_heading > M_PI) local_heading -= 2 * M_PI;
215
222
while (local_heading < -M_PI) local_heading += 2 * M_PI;
216
223
217
- // Step 6 : Create the affine transformation for the local pose of the goal
224
+ // Step 5 : Create the affine transformation for the local pose of the goal
218
225
Eigen::Affine2f transform = Eigen::Translation2f (local_x, local_y) *
219
226
Eigen::Rotation2Df (local_heading);
220
227
0 commit comments