21 #if MRPT_HAS_WXWIDGETS
23 #include <wx/msgdlg.h>
24 #include <wx/string.h>
25 #include <wx/progdlg.h>
26 #include <wx/busyinfo.h>
28 #endif // MRPT_HAS_WXWIDGETS
59 #if MRPT_HAS_WXWIDGETS
61 std::unique_ptr<wxBusyCursor> waitCursorPtr;
63 waitCursorPtr = std::unique_ptr<wxBusyCursor>(
new wxBusyCursor());
72 set<string> lstGPSLabels;
82 if (outInfo) *outInfo = outInfoTemp;
84 map<string, map<TTimeStamp, TPoint3D>>
88 bool ref_valid =
false;
99 ref_valid = !
ref.isClear();
102 const double std_0 = memFil.
read_double(
"CONSISTENCY_TEST",
"std_0", 0);
103 bool doConsistencyCheck = std_0 > 0;
107 const bool doUncertaintyCovs = outInfoTemp.
W_star.rows() != 0;
108 if (doUncertaintyCovs &&
109 (outInfoTemp.
W_star.rows() != 6 || outInfoTemp.
W_star.cols() != 6))
111 "ERROR: W_star matrix for uncertainty estimation is provided but "
112 "it's not a 6x6 matrix.");
117 #if MRPT_HAS_WXWIDGETS
118 wxProgressDialog* progDia =
nullptr;
121 progDia =
new wxProgressDialog(
122 wxT(
"Building map"), wxT(
"Getting GPS observations..."),
123 (
int)(last -
first + 1),
125 wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_AUTO_HIDE |
126 wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);
131 using TListGPSs = std::map<
133 TListGPSs list_gps_obs;
135 map<string, size_t> GPS_RTK_reads;
136 map<string, TPoint3D>
137 GPS_local_coords_on_vehicle;
139 for (
size_t i =
first; !abort && i <= last; i++)
146 case CRawlog::etObservation:
153 std::dynamic_pointer_cast<CObservationGPS>(o);
155 if (obs->has_GGA_datum &&
160 list_gps_obs[obs->timestamp][obs->sensorLabel] = obs;
162 lstGPSLabels.insert(obs->sensorLabel);
166 if (obs->has_GGA_datum &&
172 GPS_RTK_reads[obs->sensorLabel]++;
176 if (GPS_local_coords_on_vehicle.find(
178 GPS_local_coords_on_vehicle.end())
179 GPS_local_coords_on_vehicle[obs->sensorLabel] =
180 TPoint3D(obs->sensorPose.asTPose());
185 gps_paths[obs->sensorLabel][obs->timestamp] =
TPoint3D(
199 if ((
count++ % 100) == 0)
201 #if MRPT_HAS_WXWIDGETS
204 if (!progDia->Update((
int)(i -
first))) abort =
true;
211 #if MRPT_HAS_WXWIDGETS
225 map<set<string>,
double> Ad_ij;
226 map<set<string>,
double>
230 map<size_t, string> D_cov_rev_indexes;
236 if (doConsistencyCheck && GPS_local_coords_on_vehicle.size() == 3)
238 unsigned int cnt = 0;
240 GPS_local_coords_on_vehicle.begin();
241 i != GPS_local_coords_on_vehicle.end(); ++i)
244 D_cov_indexes[i->first] = cnt;
245 D_cov_rev_indexes[cnt] = i->first;
249 j != GPS_local_coords_on_vehicle.end(); ++j)
256 phi_ij[
make_set(i->first, j->first)] =
257 atan2(pj.
y - pi.
y, pj.
x - pi.
x);
261 ASSERT_(D_cov_indexes.size() == 3 && D_cov_rev_indexes.size() == 3);
263 D_cov.setSize(D_cov_indexes.size(), D_cov_indexes.size());
264 D_mean.resize(D_cov_indexes.size());
271 square(Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[1])]);
274 square(Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[2])]);
277 square(Ad_ij[
make_set(D_cov_rev_indexes[1], D_cov_rev_indexes[2])]);
280 Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[1])] *
281 Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[2])] *
282 cos(phi_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[1])] -
283 phi_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[2])]);
284 D_cov(0, 1) = D_cov(1, 0);
287 -Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[1])] *
288 Ad_ij[
make_set(D_cov_rev_indexes[1], D_cov_rev_indexes[2])] *
289 cos(phi_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[1])] -
290 phi_ij[
make_set(D_cov_rev_indexes[1], D_cov_rev_indexes[2])]);
291 D_cov(0, 2) = D_cov(2, 0);
294 Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[2])] *
295 Ad_ij[
make_set(D_cov_rev_indexes[1], D_cov_rev_indexes[2])] *
296 cos(phi_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[2])] -
297 phi_ij[
make_set(D_cov_rev_indexes[1], D_cov_rev_indexes[2])]);
298 D_cov(1, 2) = D_cov(2, 1);
300 D_cov *= 4 *
square(std_0);
302 D_cov_1 = D_cov.inv();
307 square(Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[1])]);
309 square(Ad_ij[
make_set(D_cov_rev_indexes[0], D_cov_rev_indexes[2])]);
311 square(Ad_ij[
make_set(D_cov_rev_indexes[1], D_cov_rev_indexes[2])]);
314 doConsistencyCheck =
false;
319 int N_GPSs = list_gps_obs.size();
325 if (list_gps_obs.size() > 4)
338 std::map<std::string, CObservationGPS::Ptr>& GPS = it->second;
342 l != lstGPSLabels.end(); ++l)
345 bool fnd = (GPS.find(*l) != GPS.end());
358 if (i_b1->second.find(*l) != i_b1->second.end())
359 GPS_b1 = i_b1->second.find(*l)->second;
361 if (i_a1->second.find(*l) != i_a1->second.end())
362 GPS_a1 = i_a1->second.find(*l)->second;
364 if (!disableGPSInterp && GPS_a1 && GPS_b1)
367 GPS_b1->timestamp, GPS_a1->timestamp) < 0.5)
371 new_gps->sensorLabel = *l;
381 .fields.longitude_degrees =
386 .fields.longitude_degrees);
388 .fields.latitude_degrees =
393 .fields.latitude_degrees);
395 .fields.altitude_meters =
400 .fields.altitude_meters);
403 (GPS_a1->timestamp + GPS_b1->timestamp) / 2;
405 it->second[new_gps->sensorLabel] = new_gps;
412 #if MRPT_HAS_WXWIDGETS
413 wxProgressDialog* progDia3 =
nullptr;
416 progDia3 =
new wxProgressDialog(
417 wxT(
"Building map"), wxT(
"Estimating 6D path..."),
420 wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_AUTO_HIDE |
421 wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
422 wxPD_REMAINING_TIME);
429 i != list_gps_obs.end(); ++i, idx_in_GPSs++)
432 if (i->second.size() >= 3)
434 const size_t N = i->second.size();
435 std::map<std::string, CObservationGPS::Ptr>& GPS = i->second;
437 std::map<string, size_t>
446 .getAsStruct<TGeodeticCoords>();
454 for (k = 0, g_it = GPS.begin(); g_it != GPS.end(); ++g_it, ++k)
464 string(
"OFFSET_") + g_it->second->sensorLabel;
469 XYZidxs[g_it->second->sensorLabel] =
476 g_it->second->sensorPose.x(),
477 g_it->second->sensorPose.y(),
478 g_it->second->sensorPose
487 if (doConsistencyCheck && GPS.size() == 3)
498 X[XYZidxs[D_cov_rev_indexes[0]]],
499 Y[XYZidxs[D_cov_rev_indexes[0]]],
500 Z[XYZidxs[D_cov_rev_indexes[0]]]);
502 X[XYZidxs[D_cov_rev_indexes[1]]],
503 Y[XYZidxs[D_cov_rev_indexes[1]]],
504 Z[XYZidxs[D_cov_rev_indexes[1]]]);
506 X[XYZidxs[D_cov_rev_indexes[2]]],
507 Y[XYZidxs[D_cov_rev_indexes[2]]],
508 Z[XYZidxs[D_cov_rev_indexes[2]]]);
515 iGPSdist2, D_mean, D_cov_1);
525 double optimal_scale;
530 corrs, optimal_pose, optimal_scale,
true);
545 robot_path.
insert(i->first, veh_pose);
548 if (doUncertaintyCovs)
552 final_veh_uncert.
cov = outInfoTemp.
W_star;
558 final_veh_uncert.
cov;
563 if ((
count++ % 100) == 0)
565 #if MRPT_HAS_WXWIDGETS
568 if (!progDia3->Update(idx_in_GPSs)) abort =
true;
575 #if MRPT_HAS_WXWIDGETS
583 if (PATH_SMOOTH_FILTER > 0 && robot_path.
size() > 1)
589 const double MAX_DIST_TO_FILTER = 4.0;
591 for (
auto i = robot_path.
begin(); i != robot_path.
end(); ++i)
597 pitchs.push_back(
p.pitch);
598 rolls.push_back(
p.roll);
602 k < PATH_SMOOTH_FILTER &&
q != robot_path.
begin(); k++)
608 pitchs.push_back(
q->second.pitch);
609 rolls.push_back(
q->second.roll);
614 k < PATH_SMOOTH_FILTER &&
q != (--robot_path.
end()); k++)
620 pitchs.push_back(
q->second.pitch);
621 rolls.push_back(
q->second.roll);
629 filtered_robot_path.
insert(i->first,
p);
632 robot_path = filtered_robot_path;
645 i != GPS_RTK_reads.end(); ++i)
647 if (i->second > bestNum)
650 bestLabel = i->first;
657 const string sect =
string(
"OFFSET_") + bestLabel;
658 const double off_X = memFil.
read_double(sect,
"x", 0);
659 const double off_Y = memFil.
read_double(sect,
"y", 0);
660 const double off_Z = memFil.
read_double(sect,
"z", 0);
683 if (outInfo) *outInfo = outInfoTemp;