10 #include <mrpt/core/format.h> 11 #include <mrpt/core/get_env.h> 12 #include <mrpt/core/lock_helper.h> 13 #include <mrpt/core/round.h> 14 #include <mrpt/math/TLine3D.h> 15 #include <mrpt/math/TObject3D.h> 16 #include <mrpt/math/geometry.h> 17 #include <mrpt/obs/CObservation3DRangeScan.h> 18 #include <mrpt/obs/CObservationImage.h> 19 #include <mrpt/opengl/COpenGLScene.h> 20 #include <mrpt/version.h> 27 #if MRPT_VERSION >= 0x204 28 #include <mrpt/system/thread_name.h> 31 using namespace mvsim;
38 node, params, {},
"[World::TGUI_Options]", &logger);
45 node, params, {},
"[World::LightOptions]", &logger);
57 #if MRPT_VERSION >= 0x211 58 nanogui::Window* w = gui_win->createManagedSubWindow(
"Control");
60 nanogui::Window* w =
new nanogui::Window(gui_win.get(),
"Control");
64 gui_win->getSubWindowsUI()->setPosition({1, 1});
66 w->setPosition({1, 80});
67 w->setLayout(
new nanogui::BoxLayout(
68 nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 5));
71 ->setCallback([
this]() {
72 parent_.simulator_must_close(
true);
73 gui_win->setVisible(
false);
77 std::vector<std::string> lstVehicles;
78 lstVehicles.reserve(parent_.vehicles_.size() + 1);
80 lstVehicles.push_back(
"[none]");
81 for (
const auto& v : parent_.vehicles_) lstVehicles.push_back(v.first);
83 w->add<nanogui::Label>(
"Camera follows:");
84 auto cbFollowVeh = w->add<nanogui::ComboBox>(lstVehicles);
85 cbFollowVeh->setSelectedIndex(0);
86 cbFollowVeh->setCallback([
this, lstVehicles](
int idx) {
88 parent_.guiOptions_.follow_vehicle.clear();
89 else if (idx <= static_cast<int>(parent_.vehicles_.size()))
90 parent_.guiOptions_.follow_vehicle = lstVehicles[idx];
93 w->add<nanogui::CheckBox>(
"Orthogonal view", [&](
bool b) {
94 gui_win->camera().setCameraProjective(!b);
95 })->setChecked(parent_.guiOptions_.ortho);
97 #if MRPT_VERSION >= 0x270 98 w->add<nanogui::CheckBox>(
"Enable shadows", [&](
bool b) {
99 auto vv = parent_.worldVisual_->getViewport();
100 auto vp = parent_.worldPhysical_.getViewport();
101 vv->enableShadowCasting(b);
102 vp->enableShadowCasting(b);
103 parent_.lightOptions_.enable_shadows = b;
104 })->setChecked(parent_.lightOptions_.enable_shadows);
107 w->add<nanogui::Label>(
"Light azimuth:");
109 auto sl = w->add<nanogui::Slider>();
111 sl->setValue(parent_.lightOptions_.light_azimuth);
112 sl->setCallback([
this](
float v) {
113 parent_.lightOptions_.light_azimuth = v;
114 parent_.setLightDirectionFromAzimuthElevation(
115 parent_.lightOptions_.light_azimuth,
116 parent_.lightOptions_.light_elevation);
119 w->add<nanogui::Label>(
"Light elevation:");
121 auto sl = w->add<nanogui::Slider>();
122 sl->setRange({0,
M_PI * 0.5});
123 sl->setValue(parent_.lightOptions_.light_elevation);
124 sl->setCallback([
this](
float v) {
125 parent_.lightOptions_.light_elevation = v;
126 parent_.setLightDirectionFromAzimuthElevation(
127 parent_.lightOptions_.light_azimuth,
128 parent_.lightOptions_.light_elevation);
132 w->add<nanogui::CheckBox>(
"View forces", [&](
bool b) {
133 parent_.guiOptions_.show_forces = b;
134 })->setChecked(parent_.guiOptions_.show_forces);
136 w->add<nanogui::CheckBox>(
"View sensor pointclouds", [&](
bool b) {
137 std::lock_guard<std::mutex> lck(gui_win->background_scene_mtx);
140 std::dynamic_pointer_cast<mrpt::opengl::CSetOfObjects>(
141 gui_win->background_scene->getByName(
"group_sensors_viz"));
142 ASSERT_(glVizSensors);
144 glVizSensors->setVisibility(b);
145 })->setChecked(parent_.guiOptions_.show_sensor_points);
147 w->add<nanogui::CheckBox>(
"View sensor poses", [&](
bool b) {
149 for (
const auto& o : *objs) o->setVisibility(b);
150 })->setChecked(
false);
152 w->add<nanogui::CheckBox>(
"View sensor FOVs", [&](
bool b) {
154 for (
const auto& o : *objs) o->setVisibility(b);
155 })->setChecked(
false);
157 w->add<nanogui::CheckBox>(
"View collision shapes", [&](
bool b) {
158 auto lck = mrpt::lockHelper(parent_.simulableObjectsMtx_);
159 for (
auto&
s : parent_.simulableObjects_)
165 })->setChecked(
false);
171 #if MRPT_VERSION >= 0x211 172 nanogui::Window* w = gui_win->createManagedSubWindow(
"Status");
174 nanogui::Window* w =
new nanogui::Window(gui_win.get(),
"Status");
177 w->setPosition({5, 455});
178 w->setLayout(
new nanogui::BoxLayout(
179 nanogui::Orientation::Vertical, nanogui::Alignment::Fill));
180 w->setFixedWidth(320);
182 #if MRPT_VERSION < 0x211 185 ->setCallback([w]() { w->setVisible(
false); });
188 lbCpuUsage = w->add<nanogui::Label>(
" ");
189 lbStatuses.resize(12);
190 for (
size_t i = 0; i < lbStatuses.size(); i++)
191 lbStatuses[i] = w->add<nanogui::Label>(
" ");
197 #if MRPT_VERSION >= 0x211 198 #if MRPT_VERSION >= 0x231 199 const auto subwinIdx = gui_win->getSubwindowCount();
201 nanogui::Window* w = gui_win->createManagedSubWindow(
"Editor");
203 nanogui::Window* w =
new nanogui::Window(gui_win.get(),
"Editor");
206 const int pnWidth = 250, pnHeight = 200;
208 w->setPosition({1, 230});
209 w->setLayout(
new nanogui::BoxLayout(
210 nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 3, 3));
211 w->setFixedWidth(pnWidth);
213 #if MRPT_VERSION < 0x211 216 ->setCallback([w]() { w->setVisible(
false); });
219 w->add<nanogui::Label>(
"Selected object",
"sans-bold");
221 auto lckListObjs = mrpt::lockHelper(parent_.getListOfSimulableObjectsMtx());
222 if (!parent_.getListOfSimulableObjects().empty())
224 auto tab = w->add<nanogui::TabWidget>();
226 nanogui::Widget* tabs[4] = {
227 tab->createTab(
"Vehicles"), tab->createTab(
"Blocks"),
228 tab->createTab(
"Elements"), tab->createTab(
"Misc.")};
230 tab->setActiveTab(0);
233 t->setLayout(
new nanogui::BoxLayout(
234 nanogui::Orientation::Vertical, nanogui::Alignment::Minimum, 3,
237 nanogui::VScrollPanel* vscrolls[4] = {
238 tabs[0]->add<nanogui::VScrollPanel>(),
239 tabs[1]->add<nanogui::VScrollPanel>(),
240 tabs[2]->add<nanogui::VScrollPanel>(),
241 tabs[3]->add<nanogui::VScrollPanel>()};
243 for (
auto vs : vscrolls) vs->setFixedSize({pnWidth, pnHeight});
247 nanogui::Widget* wrappers[4];
248 for (
int i = 0; i < 4; i++)
250 wrappers[i] = vscrolls[i]->add<nanogui::Widget>();
251 wrappers[i]->setFixedSize({pnWidth, pnHeight});
252 wrappers[i]->setLayout(
new nanogui::GridLayout(
253 nanogui::Orientation::Horizontal, 1 ,
254 nanogui::Alignment::Minimum, 3, 3));
257 for (
const auto& o : parent_.getListOfSimulableObjects())
261 const auto& name = o.first;
262 bool isVehicle =
false;
263 if (
auto v = dynamic_cast<VehicleBase*>(o.second.get()); v)
268 bool isBlock =
false;
269 if (
auto v = dynamic_cast<Block*>(o.second.get()); v)
275 if (
auto v = dynamic_cast<WorldElementBase*>(o.second.get()); v)
281 isVehicle ? wrappers[0] : (isBlock ? wrappers[1] : wrappers[2]);
283 std::string label = name;
284 if (label.empty()) label =
"(unnamed)";
286 auto cb = wrapper->add<nanogui::CheckBox>(label);
289 gui_cbObjects.emplace_back(ipo);
291 cb->setChecked(
false);
292 cb->setCallback([cb, ipo,
this](
bool check) {
294 if (gui_selectedObject.visual)
295 gui_selectedObject.visual->showCollisionShape(
false);
296 if (gui_selectedObject.cb)
297 gui_selectedObject.cb->setChecked(
false);
300 cb->setChecked(check);
305 gui_selectedObject = ipo;
309 const bool btnsEnabled = !!gui_selectedObject.simulable;
310 for (
auto b : btns_selectedOps) b->setEnabled(btnsEnabled);
318 ->setCallback([
this]() {
321 const std::string outFile = nanogui::file_dialog(
322 {{
"3Dscene",
"MRPT 3D scene file (*.3Dsceme)"}},
324 if (outFile.empty())
return;
326 auto lck = mrpt::lockHelper(parent_.physical_objects_mtx());
327 parent_.worldPhysical_.saveToFile(outFile);
329 std::cout <<
"[mvsim gui] Saved world scene to: " << outFile
332 catch (
const std::exception& e)
335 <<
"[mvsim gui] Exception while saving 3D scene:\n" 336 << e.what() << std::endl;
341 w->add<nanogui::Label>(
" ");
344 btnReplaceObject->setFlags(nanogui::Button::Flags::ToggleButton);
345 btns_selectedOps.push_back(btnReplaceObject);
348 auto pn = w->add<nanogui::Widget>();
349 pn->setLayout(
new nanogui::BoxLayout(
350 nanogui::Orientation::Horizontal, nanogui::Alignment::Fill, 2, 2));
351 pn->add<nanogui::Label>(
"Reorient:");
352 auto slAngle = pn->add<nanogui::Slider>();
354 slAngle->setCallback([
this](
float v) {
355 if (!gui_selectedObject.simulable)
return;
356 auto p = gui_selectedObject.simulable->getPose();
358 gui_selectedObject.simulable->setPose(p);
360 slAngle->setFixedWidth(150);
361 btns_selectedOps.push_back(slAngle);
364 auto btnPlaceCoords = w->add<
nanogui::Button>(
"Replace by coordinates...");
365 btns_selectedOps.push_back(btnPlaceCoords);
366 btnPlaceCoords->setCallback([
this]() {
368 if (!gui_selectedObject.simulable)
return;
370 auto* formPose =
new nanogui::Window(gui_win.get(),
"Enter new pose");
371 formPose->setLayout(
new nanogui::GridLayout(
372 nanogui::Orientation::Horizontal, 2, nanogui::Alignment::Fill, 5));
374 nanogui::TextBox* lbs[3];
376 formPose->add<nanogui::Label>(
"x coordinate:");
377 lbs[0] = formPose->add<nanogui::TextBox>();
378 formPose->add<nanogui::Label>(
"y coordinate:");
379 lbs[1] = formPose->add<nanogui::TextBox>();
380 formPose->add<nanogui::Label>(
"Orientation:");
381 lbs[2] = formPose->add<nanogui::TextBox>();
383 for (
int i = 0; i < 3; i++)
385 lbs[i]->setEditable(
true);
386 lbs[i]->setFixedSize({100, 20});
387 lbs[i]->setValue(
"0.0");
388 lbs[i]->setUnits(i == 2 ?
"[deg]" :
"[m]");
389 lbs[i]->setDefaultValue(
"0.0");
390 lbs[i]->setFontSize(16);
391 lbs[i]->setFormat(
"[-]?[0-9]*\\.?[0-9]+");
394 const auto pos = gui_selectedObject.simulable->getPose();
395 lbs[0]->setValue(std::to_string(pos.x));
396 lbs[1]->setValue(std::to_string(pos.y));
397 lbs[2]->setValue(std::to_string(mrpt::RAD2DEG(pos.yaw)));
399 formPose->add<nanogui::Label>(
"");
400 formPose->add<nanogui::Label>(
"");
403 [formPose]() { formPose->dispose(); });
406 [formPose,
this, lbs]() {
407 gui_selectedObject.simulable->setPose(
409 std::stod(lbs[0]->value()),
411 std::stod(lbs[1]->value()),
415 mrpt::DEG2RAD(std::stod(lbs[2]->value())),
423 formPose->setModal(
true);
425 formPose->setVisible(
true);
428 for (
auto b : btns_selectedOps) b->setEnabled(
false);
431 #if MRPT_VERSION >= 0x231 432 gui_win->subwindowMinimize(subwinIdx);
434 if (
auto btnMinimize =
435 dynamic_cast<nanogui::Button*>(w->buttonPanel()->children().at(0));
438 btnMinimize->callback()();
448 MRPT_LOG_DEBUG(
"[World::internal_GUI_thread] Started.");
453 mrpt::gui::CDisplayWindowGUI_Params cp;
454 cp.maximized = guiOptions_.start_maximized;
456 gui_.gui_win = mrpt::gui::CDisplayWindowGUI::Create(
457 "mvsim", guiOptions_.win_w, guiOptions_.win_h, cp);
460 worldVisual_->getViewport()->setViewportClipDistances(
461 guiOptions_.clip_plane_min, guiOptions_.clip_plane_max);
470 worldVisual_->insert(glUserObjsViz_);
471 worldPhysical_.insert(glUserObjsPhysical_);
473 std::lock_guard<std::mutex> lck(gui_.gui_win->background_scene_mtx);
474 gui_.gui_win->background_scene = worldVisual_;
478 if (worldElements_.empty())
481 worldElements_.push_back(we);
485 gui_.prepare_control_window();
486 gui_.prepare_status_window();
487 gui_.prepare_editor_window();
490 gui_.gui_win->performLayout();
491 auto& cam = gui_.gui_win->camera();
493 cam.setCameraPointing(0.0
f, .0
f, .0
f);
494 cam.setCameraProjective(!guiOptions_.ortho);
495 cam.setZoomDistance(guiOptions_.camera_distance);
496 cam.setAzimuthDegrees(guiOptions_.camera_azimuth_deg);
497 cam.setElevationDegrees(guiOptions_.camera_elevation_deg);
498 cam.setCameraFOV(guiOptions_.fov_deg);
499 cam.setCameraPointing(
500 guiOptions_.camera_point_to.x, guiOptions_.camera_point_to.y,
501 guiOptions_.camera_point_to.z);
503 const auto& lo = lightOptions_;
505 setLightDirectionFromAzimuthElevation(
506 lo.light_azimuth, lo.light_elevation);
508 #if MRPT_VERSION >= 0x270 509 auto vv = worldVisual_->getViewport();
510 auto vp = worldPhysical_.getViewport();
512 auto lambdaSetLightParams =
513 [&lo](
const mrpt::opengl::COpenGLViewport::Ptr& v) {
515 const int sms = lo.shadow_map_size;
516 v->enableShadowCasting(lo.enable_shadows, sms, sms);
519 const auto colf = mrpt::img::TColorf(lo.light_color);
521 auto& vlp = v->lightParameters();
525 #if MRPT_VERSION >= 0x2A0 // New in mrpt>=2.10.0 526 vlp.eyeDistance2lightShadowExtension =
527 lo.eye_distance_to_shadow_map_extension;
529 vlp.minimum_shadow_map_extension_ratio =
530 lo.minimum_shadow_map_extension_ratio;
533 v->setLightShadowClipDistances(
534 lo.light_clip_plane_min, lo.light_clip_plane_max);
537 #if MRPT_VERSION >= 0x281 538 vlp.shadow_bias = lo.shadow_bias;
539 vlp.shadow_bias_cam2frag = lo.shadow_bias_cam2frag;
540 vlp.shadow_bias_normal = lo.shadow_bias_normal;
544 lambdaSetLightParams(vv);
545 lambdaSetLightParams(vp);
550 gui_.gui_win->drawAll();
551 gui_.gui_win->setVisible(
true);
554 #if MRPT_VERSION >= 0x232 555 gui_.gui_win->addKeyboardCallback(
557 gui_.gui_win->setKeyboardCallback(
559 [&](
int key,
int ,
int action,
int modifiers) {
560 if (action != GLFW_PRESS && action != GLFW_REPEAT) return false;
562 auto lck = mrpt::lockHelper(lastKeyEventMtx_);
564 lastKeyEvent_.keycode = key;
565 lastKeyEvent_.modifierShift = (modifiers & GLFW_MOD_SHIFT) != 0;
566 lastKeyEvent_.modifierCtrl =
567 (modifiers & GLFW_MOD_CONTROL) != 0;
568 lastKeyEvent_.modifierSuper = (modifiers & GLFW_MOD_SUPER) != 0;
569 lastKeyEvent_.modifierAlt = (modifiers & GLFW_MOD_ALT) != 0;
571 lastKeyEventValid_ = true;
576 gui_thread_running_ =
true;
580 auto lambdaLoopCallback = [](
World& me) {
581 if (me.simulator_must_close()) nanogui::leave();
586 me.internalGraphicsLoopTasksForSimulation();
588 me.internal_process_pending_gui_user_tasks();
591 me.gui_.handle_mouse_operations();
593 catch (
const std::exception& e)
598 me.logStr(mrpt::system::LVL_ERROR, e.what());
599 me.simulator_must_close(
true);
600 me.gui_.gui_win->setVisible(
false);
605 #if MRPT_VERSION >= 0x232 606 gui_.gui_win->addLoopCallback(
608 gui_.gui_win->setLoopCallback(
610 [=]() { lambdaLoopCallback(*this); });
613 const auto lambdaOnObservation =
615 const Simulable& veh,
const mrpt::obs::CObservation::Ptr& obs) {
617 this->enqueue_task_to_run_in_gui_thread([
this, obs, &veh]() {
618 internal_gui_on_observation(veh, obs);
622 this->registerCallbackOnObservation(lambdaOnObservation);
625 const int refresh_ms =
626 std::max(1, mrpt::round(1000 / guiOptions_.refresh_fps));
629 "[World::internal_GUI_thread] Using GUI FPS=%i (T=%i ms)",
630 guiOptions_.refresh_fps, refresh_ms);
632 #if MRPT_VERSION >= 0x253 633 const int idleLoopTasks_ms = 10;
635 nanogui::mainloop(idleLoopTasks_ms, refresh_ms);
637 nanogui::mainloop(refresh_ms);
640 MRPT_LOG_DEBUG(
"[World::internal_GUI_thread] Mainloop ended.");
643 simulator_must_close(
true);
649 auto lck = mrpt::lockHelper(gui_.gui_win->background_scene_mtx);
650 if (gui_.gui_win->background_scene)
651 gui_.gui_win->background_scene->freeOpenGLResources();
654 auto lckListObjs = mrpt::lockHelper(getListOfSimulableObjectsMtx());
656 for (
auto& obj : getListOfSimulableObjects())
657 obj.second->freeOpenGLResources();
659 lckListObjs.unlock();
664 gui_.gui_win.reset();
668 catch (
const std::exception& e)
670 MRPT_LOG_ERROR_STREAM(
671 "[internal_GUI_init] Exception: " << mrpt::exception_to_str(e));
673 gui_thread_running_ =
false;
679 if (!gui_win)
return;
681 mrpt::opengl::COpenGLViewport::Ptr vp;
683 auto lck = mrpt::lockHelper(gui_win->background_scene_mtx);
684 if (!gui_win->background_scene)
return;
685 vp = gui_win->background_scene->getViewport();
689 const auto mousePt = gui_win->mousePos();
690 mrpt::math::TLine3D ray;
691 vp->get3DRayForPixelCoord(mousePt.x(), mousePt.y(), ray);
694 const auto ground_plane =
695 mrpt::math::TPlane::From3Points({0, 0, 0}, {1, 0, 0}, {0, 1, 0});
698 mrpt::math::TObject3D inters;
699 mrpt::math::intersect(ray, ground_plane, inters);
703 if (inters.getPoint(clickedPt))
709 #if MRPT_VERSION >= 0x211 710 const auto screen = gui_win->screen();
711 const bool leftClick = screen->mouseState() == 0x01;
714 if (btnReplaceObject && btnReplaceObject->pushed())
716 static bool isReplacing =
false;
719 if (!isReplacing && !leftClick)
723 if (gui_selectedObject.simulable)
727 mrpt::math::TPose3D p = gui_selectedObject.simulable->getPose();
731 gui_selectedObject.simulable->setPose(p);
733 if (isReplacing && leftClick)
736 btnReplaceObject->setPushed(
false);
746 guiUserPendingTasksMtx_.lock();
748 for (
const auto& task : guiUserPendingTasks_)
752 guiUserPendingTasks_.clear();
754 guiUserPendingTasksMtx_.unlock();
758 mrpt::opengl::COpenGLScene& physicalObjects)
760 auto tle = mrpt::system::CTimeLoggerEntry(
761 timlogger_,
"internalRunSensorsOn3DScene");
763 for (
auto& v : vehicles_)
764 for (
auto& sensor : v.second->getSensors())
765 if (sensor) sensor->simulateOn3DScene(physicalObjects);
768 clear_pending_running_sensors_on_3D_scene();
772 mrpt::opengl::COpenGLScene& viz, mrpt::opengl::COpenGLScene& physical)
777 mrpt::system::CTimeLoggerEntry(timlogger_,
"update_GUI.2.map-elements");
779 for (
auto& e : worldElements_) e->guiUpdate(viz, physical);
785 timlogger_.enter(
"update_GUI.3.vehicles");
787 for (
auto& v : vehicles_) v.second->guiUpdate(viz, physical);
789 timlogger_.leave(
"update_GUI.3.vehicles");
793 timlogger_.enter(
"update_GUI.4.blocks");
795 for (
auto& v : blocks_) v.second->guiUpdate(viz, physical);
797 timlogger_.leave(
"update_GUI.4.blocks");
801 timlogger_.enter(
"update_GUI.5.text-msgs");
805 double cpu_usage_ratio =
806 std::max(1e-10, timlogger_.getMeanTime(
"run_simulation.cpu_dt")) /
807 std::max(1e-10, timlogger_.getMeanTime(
"run_simulation.dt"));
809 gui_.lbCpuUsage->setCaption(mrpt::format(
810 "Time: %s (CPU usage: %.03f%%)",
811 mrpt::system::formatTimeInterval(get_simul_time()).c_str(),
812 cpu_usage_ratio * 100.0));
815 guiMsgLinesMtx_.lock();
816 const std::string msg_lines = guiMsgLines_;
817 guiMsgLinesMtx_.unlock();
819 int nextStatusLine = 0;
820 if (!msg_lines.empty())
823 std::vector<std::string> lines;
824 mrpt::system::tokenize(msg_lines,
"\r\n", lines);
825 for (
const auto& l : lines)
826 gui_.lbStatuses.at(nextStatusLine++)->setCaption(l);
828 gui_.lbStatuses.at(nextStatusLine++)
829 ->setCaption(std::string(
"Mouse: ") + gui_.clickedPt.asString());
832 timlogger_.leave(
"update_GUI.5.text-msgs");
836 if (!guiOptions_.follow_vehicle.empty())
838 if (
auto it = vehicles_.find(guiOptions_.follow_vehicle);
839 it != vehicles_.end())
841 const mrpt::poses::CPose2D pose = it->second->getCPose2D();
842 gui_.gui_win->camera().setCameraPointing(pose.x(), pose.y(), 0.0f);
846 MRPT_LOG_THROTTLE_ERROR_FMT(
848 "GUI: Camera set to follow vehicle named '%s' which can't be " 850 guiOptions_.follow_vehicle.c_str());
860 auto lock = mrpt::lockHelper(gui_thread_start_mtx_);
861 if (!gui_thread_running_ && !gui_thread_.joinable())
863 MRPT_LOG_DEBUG(
"[update_GUI] Launching GUI thread...");
866 #if MRPT_VERSION >= 0x204 867 mrpt::system::thread_name(
"guiThread", gui_thread_);
870 const int MVSIM_OPEN_GUI_TIMEOUT_MS =
871 mrpt::get_env<int>(
"MVSIM_OPEN_GUI_TIMEOUT_MS", 3000);
873 for (
int timeout = 0; timeout < MVSIM_OPEN_GUI_TIMEOUT_MS / 10;
876 std::this_thread::sleep_for(std::chrono::milliseconds(10));
877 if (gui_thread_running_)
break;
880 if (!gui_thread_running_)
882 THROW_EXCEPTION(
"Timeout waiting for GUI to open!");
886 MRPT_LOG_DEBUG(
"[update_GUI] GUI thread started.");
893 MRPT_LOG_THROTTLE_WARN(
895 "[World::update_GUI] GUI window has been closed, but note that " 896 "simulation keeps running.");
900 timlogger_.enter(
"update_GUI");
903 guiMsgLinesMtx_.lock();
905 guiMsgLinesMtx_.unlock();
907 timlogger_.leave(
"update_GUI");
911 if (guiparams && lastKeyEventValid_)
913 auto lck = mrpt::lockHelper(lastKeyEventMtx_);
915 guiparams->
keyevent = std::move(lastKeyEvent_);
916 lastKeyEventValid_ =
false;
922 const Simulable& veh,
const mrpt::obs::CObservation::Ptr& obs)
927 std::dynamic_pointer_cast<mrpt::obs::CObservation3DRangeScan>(obs);
930 internal_gui_on_observation_3Dscan(veh, obs3D);
932 else if (
auto obsIm =
933 std::dynamic_pointer_cast<mrpt::obs::CObservationImage>(obs);
936 internal_gui_on_observation_image(veh, obsIm);
942 const std::shared_ptr<mrpt::obs::CObservation3DRangeScan>& obs)
944 using namespace std::string_literals;
946 if (!gui_.gui_win || !obs)
return;
948 mrpt::math::TPoint2D rgbImageWinSize = {0, 0};
950 if (obs->hasIntensityImage)
952 rgbImageWinSize = internal_gui_on_image(
953 veh.
getName() +
"/"s + obs->sensorLabel +
"_rgb"s,
954 obs->intensityImage, 5);
956 if (obs->hasRangeImage)
958 mrpt::math::CMatrixFloat
d;
959 d = obs->rangeImage.asEigen().cast<
float>() *
960 (obs->rangeUnits / obs->maxRange);
962 mrpt::img::CImage imDepth;
963 imDepth.setFromMatrix(d,
true );
965 internal_gui_on_image(
966 veh.
getName() +
"/"s + obs->sensorLabel +
"_depth"s, imDepth,
967 5 + 5 + rgbImageWinSize.x);
973 const std::shared_ptr<mrpt::obs::CObservationImage>& obs)
975 using namespace std::string_literals;
977 if (!gui_.gui_win || !obs || obs->image.isEmpty())
return;
979 mrpt::math::TPoint2D rgbImageWinSize = {0, 0};
981 rgbImageWinSize = internal_gui_on_image(
982 veh.
getName() +
"/"s + obs->sensorLabel +
"_rgb"s, obs->image, 5);
986 const std::string& label,
const mrpt::img::CImage& im,
int winPosX)
988 mrpt::gui::MRPT2NanoguiGLCanvas* glControl;
991 if (!guiObsViz_.count(label))
993 auto& w = guiObsViz_[label] =
994 gui_.gui_win->createManagedSubWindow(label);
996 w->setLayout(
new nanogui::GridLayout(
997 nanogui::Orientation::Vertical, 1, nanogui::Alignment::Fill, 2, 2));
1000 int winW = im.getWidth(), winH = im.getHeight();
1003 while (winW >= 512 || winH >= 512)
1009 glControl = w->add<mrpt::gui::MRPT2NanoguiGLCanvas>();
1010 glControl->setSize({winW, winH});
1011 glControl->setFixedSize({winW, winH});
1013 static std::map<int, int> numGuiWindows;
1015 {winPosX, 20 + (numGuiWindows[winPosX]++) * (winH + 10)});
1017 auto lck = mrpt::lockHelper(glControl->scene_mtx);
1019 glControl->scene = mrpt::opengl::COpenGLScene::Create();
1020 gui_.gui_win->performLayout();
1024 auto& w = guiObsViz_[label];
1027 dynamic_cast<mrpt::gui::MRPT2NanoguiGLCanvas*
>(w->children().at(1));
1028 ASSERT_(glControl !=
nullptr);
1030 auto lck = mrpt::lockHelper(glControl->scene_mtx);
1031 glControl->scene->getViewport()->setImageView(im);
1033 return mrpt::math::TPoint2D(w->size().x(), w->size().y());
1041 ASSERT_(worldVisual_);
1043 auto lckPhys = mrpt::lockHelper(physical_objects_mtx());
1045 internalUpdate3DSceneObjects(*worldVisual_, worldPhysical_);
1047 internalRunSensorsOn3DScene(worldPhysical_);
1053 const auto lck = mrpt::lockHelper(guiUserObjectsMtx_);
1055 if (guiUserObjectsPhysical_)
1056 *glUserObjsPhysical_ = *guiUserObjectsPhysical_;
1057 if (guiUserObjectsViz_) *glUserObjsViz_ = *guiUserObjectsViz_;
1060 catch (
const std::exception& e)
1065 MRPT_LOG_ERROR(e.what());
1066 simulator_must_close(
true);
1071 const float azimuth,
const float elevation)
1073 const mrpt::math::TPoint3Df dir = {
1074 -
cos(azimuth) *
cos(elevation), -
sin(azimuth) *
cos(elevation),
1077 ASSERT_(worldVisual_);
1079 auto lckPhys = mrpt::lockHelper(physical_objects_mtx());
1081 auto vv = worldVisual_->getViewport();
1082 auto vp = worldPhysical_.getViewport();
1084 vv->lightParameters().direction = dir;
1085 vp->lightParameters().direction = dir;
void prepare_editor_window()
This file contains rapidxml parser and DOM implementation.
void parse_from(const rapidxml::xml_node< char > &node, COutputLogger &logger)
static Ptr factory(World *parent, const rapidxml::xml_node< char > *xml_node, const char *class_name=nullptr)
void parse_xmlnode_children_as_param(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions ¶ms, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="", mrpt::system::COutputLogger *logger=nullptr)
void setLightDirectionFromAzimuthElevation(const float azimuth, const float elevation)
mrpt::math::TPoint2D internal_gui_on_image(const std::string &label, const mrpt::img::CImage &im, int winPosX)
static std::shared_ptr< mrpt::opengl::CSetOfObjects > GetAllSensorsFOVViz()
void internalUpdate3DSceneObjects(mrpt::opengl::COpenGLScene &viz, mrpt::opengl::COpenGLScene &physical)
static std::shared_ptr< mrpt::opengl::CSetOfObjects > GetAllSensorsOriginViz()
void internal_gui_on_observation_3Dscan(const Simulable &veh, const std::shared_ptr< mrpt::obs::CObservation3DRangeScan > &obs)
geometry_msgs::TransformStamped t
TGUIKeyEvent keyevent
Keystrokes in the window are returned here.
void internal_GUI_thread()
static void FreeOpenGLResources()
void internal_gui_on_observation(const Simulable &veh, const mrpt::obs::CObservation::Ptr &obs)
std::string msg_lines
Messages to show.
void showCollisionShape(bool show)
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
bool is_GUI_open() const
Forces closing the GUI window, if any.
void prepare_control_window()
const std::string & getName() const
void internalRunSensorsOn3DScene(mrpt::opengl::COpenGLScene &physicalObjects)
void handle_mouse_operations()
void internal_gui_on_observation_image(const Simulable &veh, const std::shared_ptr< mrpt::obs::CObservationImage > &obs)
void prepare_status_window()
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
void update_GUI(TUpdateGUIParams *params=nullptr)
void parse_from(const rapidxml::xml_node< char > &node, COutputLogger &logger)
void internal_process_pending_gui_user_tasks()
void internalGraphicsLoopTasksForSimulation()
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
void close_GUI()
a previous call to update_GUI()