* This file is part of Photo-SLAM
*
* Copyright (C) 2023-2024 Longwei Li and Hui Cheng, Sun Yat-sen University.
* Copyright (C) 2023-2024 Huajian Huang and Sai-Kit Yeung, Hong Kong University of Science and Technology.
*
* Photo-SLAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Photo-SLAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Photo-SLAM.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "imgui_viewer.h"
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "[ImGuiViewer]GLFW Error %d: %s\n", error, description);
}
ImGuiViewer::ImGuiViewer(
std::shared_ptr<ORB_SLAM3::System> pSLAM,
std::shared_ptr<GaussianMapper> pGausMapper,
bool training)
: glfw_window_width_(1600),
glfw_window_height_(900),
panel_width_(372),
display_panel_height_(144),
training_panel_height_(440),
camera_panel_height_(144),
SLAM_image_viewer_scale_(1.0f),
training_(training)
{
this->pSLAM_ = pSLAM;
this->pGausMapper_ = pGausMapper;
cv::Size im_size;
if (pSLAM)
{
ORB_SLAM3::Settings* settings = pSLAM->getSettings();
im_size = settings->newImSize();
image_height_ = im_size.height;
image_width_ = im_size.width;
viewpointX_ = settings->viewPointX();
viewpointY_ = settings->viewPointY();
viewpointZ_ = settings->viewPointZ();
viewpointF_ = settings->camera1()->getParameter(1);
}
else
{
image_height_ = pGausMapper->scene_->cameras_.begin()->second.height_;
image_width_ = pGausMapper->scene_->cameras_.begin()->second.width_;
viewpointF_ = pGausMapper->scene_->cameras_.begin()->second.params_[1];
}
main_fx_ = pGausMapper->scene_->cameras_.begin()->second.params_[0];
main_fy_ = pGausMapper->scene_->cameras_.begin()->second.params_[1];
std::filesystem::path cfg_file_path = pGausMapper->config_file_path_;
readConfigFromFile(cfg_file_path);
SLAM_image_viewer_scale_ = static_cast<float>(rendered_image_width_) / image_width_;
float fovy = graphics_utils::focal2fov(viewpointF_, im_size.height);
cam_proj_ = glm::perspective(
fovy < M_PIf32 ? fovy : M_PIf32, (float)glfw_window_width_ / (float)glfw_window_height_, 0.01f, 100.0f);
up_ = glm::vec3(0.0f, -1.0f, 0.0f);
up_aligned_ = glm::vec4(up_, 1.0f);
behind_ = glm::vec4(0.0f, 0.0f, -camera_watch_dist_, 1.0f);
cam_pos_ = glm::vec3(viewpointX_, viewpointY_, viewpointZ_);
cam_target_ = glm::vec3(0.0f, 0.0f, 0.0f);
cam_view_ = glm::lookAt(cam_pos_, cam_target_, up_);
cam_trans_ = cam_proj_ * cam_view_;
if (pSLAM)
{
pSlamFrameDrawer_ = pSLAM->getFrameDrawer();
pSlamMapDrawer_ = pSLAM->getMapDrawer();
pMapDrawer_ = std::make_shared<ORB_SLAM3::ImGuiMapDrawer>(
pSLAM->getAtlas(), std::string(), pSLAM->getSettings());
}
}
void ImGuiViewer::readConfigFromFile(std::filesystem::path cfg_path)
{
cv::FileStorage settings_file(cfg_path.string().c_str(), cv::FileStorage::READ);
if(!settings_file.isOpened())
throw std::runtime_error("[ImGuiViewer]Failed to open settings file at: " + cfg_path.string());
std::cout << "[ImGuiViewer]Reading parameters from " << cfg_path << std::endl;
glfw_window_width_ =
settings_file["GaussianViewer.glfw_window_width"].operator int();
glfw_window_height_ =
settings_file["GaussianViewer.glfw_window_height"].operator int();
main_cx_ = glfw_window_width_ / 2;
main_cy_ = glfw_window_height_ / 2;
rendered_image_viewer_scale_ =
settings_file["GaussianViewer.image_scale"].operator float();
rendered_image_height_ = image_height_ * rendered_image_viewer_scale_;
rendered_image_width_ = image_width_ * rendered_image_viewer_scale_;
int temp = rendered_image_width_ % 4;
padded_sub_image_width_ = rendered_image_width_ + 4 - (temp == 0 ? 4 : temp);
rendered_image_viewer_scale_main_ =
settings_file["GaussianViewer.image_scale_main"].operator float();
rendered_image_height_main_ = image_height_ * rendered_image_viewer_scale_main_;
rendered_image_width_main_ = image_width_ * rendered_image_viewer_scale_main_;
temp = rendered_image_width_main_ % 4;
padded_main_image_width_ = rendered_image_width_main_ + 4 - (temp == 0 ? 4 : temp);
camera_watch_dist_ =
settings_file["GaussianViewer.camera_watch_dist"].operator float();
position_lr_init_ = pGausMapper_->positionLearningRateInit();
feature_lr_ = pGausMapper_->featureLearningRate();
opacity_lr_ = pGausMapper_->opacityLearningRate();
scaling_lr_ = pGausMapper_->scalingLearningRate();
rotation_lr_ = pGausMapper_->rotationLearningRate();
percent_dense_ = pGausMapper_->percentDense();
lambda_dssim_ = pGausMapper_->lambdaDssim();
opacity_reset_interval_ = pGausMapper_->opacityResetInterval();
densify_grad_th_ = pGausMapper_->densifyGradThreshold();
densify_interval_ = pGausMapper_->densifyInterval();
new_kf_times_of_use_ = pGausMapper_->newKeyframeTimesOfUse();
stable_num_iter_existence_ = pGausMapper_->stableNumIterExistence();
do_gaus_pyramid_training_ = pGausMapper_->isdoingGausPyramidTraining();
do_inactive_geo_densify_ = pGausMapper_->isdoingInactiveGeoDensify();
}
void ImGuiViewer::run()
{
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
throw std::runtime_error("[ImGuiViewer]Fails to initialize!");
const char* glsl_version = "#version 130";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window =
glfwCreateWindow(glfw_window_width_, glfw_window_height_,
"Photo-SLAM", nullptr, nullptr);
if (window == nullptr)
throw std::runtime_error("[ImGuiViewer]Fails to create window!");
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glEnable(GL_DEPTH_TEST);
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
ImGui::StyleColorsClassic();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
Sophus::SE3f Tcw, TcwInit;
cam_pos_ = glm::vec3(viewpointX_, viewpointY_, viewpointZ_);
glm::vec4 cam_pos_aligned = glm::vec4(cam_pos_, 1.0f);
cam_target_ = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cam_direction = cam_pos_ - cam_target_;
glm::vec3 cam_right = glm::normalize(glm::cross(up_, cam_direction));
glm::vec3 cam_up = glm::cross(cam_direction, cam_right);
glm::vec4 cam_up_aligned = glm::vec4(cam_up, 1.0f);
cam_view_ = glm::lookAt(cam_pos_, cam_target_, cam_up);
glm::mat4 glmTwc, Twr, glmTwcInit;
glmTwc = glm::mat4(1.0f);
glmTwcInit = glm::mat4(1.0f);
glmTwc_main_ = glm::mat4(1.0f);
glm::mat4 Ow, OwInit;
Ow = glm::mat4(1.0f);
OwInit = glm::mat4(1.0f);
cv::Rect image_rect_sub(0, 0, rendered_image_width_, rendered_image_height_);
cv::Rect image_rect_main(0, 0, rendered_image_width_main_, rendered_image_height_main_);
GLuint SLAM_img_texture, rendered_img_texture, main_img_texture;
glGenTextures(1, &SLAM_img_texture);
glBindTexture(GL_TEXTURE_2D, SLAM_img_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenTextures(1, &rendered_img_texture);
glBindTexture(GL_TEXTURE_2D, rendered_img_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenTextures(1, &main_img_texture);
glBindTexture(GL_TEXTURE_2D, main_img_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
while(!isStopped() && !glfwWindowShouldClose(window))
{
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (pSLAM_)
{
if (!pMapDrawer_->mbSetInitCamera)
{
Sophus::SE3f initTwc = pSlamMapDrawer_->GetCurrentCameraPose();
pMapDrawer_->SetInitCameraTwc(initTwc);
pMapDrawer_->SetCurrentCameraTwc(initTwc);
pMapDrawer_->mbSetInitCamera = true;
}
else
{
pMapDrawer_->SetCurrentCameraTwc(pSlamMapDrawer_->GetCurrentCameraPose());
}
pMapDrawer_->GetOpenGLCameraMatrix(true, Tcw, glmTwc, Ow);
if (!init_Twc_set_)
pMapDrawer_->GetOpenGLCameraMatrix(false, TcwInit, glmTwcInit, OwInit);
}
if (tracking_vision_)
{
glm::vec3 cam_target = glm::vec3(Ow[3][0], Ow[3][1], Ow[3][2]);
cam_pos_aligned = glmTwc * behind_;
glm::vec3 cam_pos = glm::vec3(cam_pos_aligned.x, cam_pos_aligned.y, cam_pos_aligned.z);
cam_direction = cam_pos - cam_target;
cam_up_aligned = glmTwc * up_aligned_;
cam_up = glm::normalize(glm::vec3(cam_up_aligned.x, cam_up_aligned.y, cam_up_aligned.z) - cam_target);
cam_right = glm::normalize(glm::cross(cam_up, cam_direction));
cam_up = glm::cross(cam_direction, cam_right);
cam_view_ = glm::lookAt(cam_pos, cam_target, cam_up);
cam_trans_ = cam_proj_ * cam_view_;
}
else
{
if (reset_main_to_init_ || !init_Twc_set_)
{
cam_target_ = glm::vec3(OwInit[3][0], OwInit[3][1], OwInit[3][2]);
cam_pos_aligned = glmTwcInit * behind_;
glmTwc_main_ = glmTwcInit;
Tcw_main_ = TcwInit;
Twc_main_ = Tcw_main_.inverse();
init_Twc_set_ = true;
reset_main_to_init_ = false;
}
else
{
Tcw_main_ = trans4x4glm2Sophus(glmTwc_main_).inverse();
handleUserInput();
glmTwc_main_ = trans4x4Eigen2glm(Tcw_main_.inverse().matrix());
cam_target_ = glm::vec3(glmTwc_main_[3][0], glmTwc_main_[3][1], glmTwc_main_[3][2]);
cam_pos_aligned = glmTwc_main_ * behind_;
}
cam_pos_ = glm::vec3(cam_pos_aligned.x, cam_pos_aligned.y, cam_pos_aligned.z);
cam_direction = cam_pos_ - cam_target_;
cam_up_aligned = glmTwc_main_ * up_aligned_;
cam_up = glm::normalize(glm::vec3(cam_up_aligned.x, cam_up_aligned.y, cam_up_aligned.z) - cam_target_);
cam_right = glm::normalize(glm::cross(cam_up, cam_direction));
cam_up = glm::cross(cam_direction, cam_right);
cam_view_ = glm::lookAt(cam_pos_, cam_target_, cam_up);
cam_trans_ = cam_proj_ * cam_view_;
}
if (pSLAM_)
{
cv::Mat SLAM_img_to_show;
cv::Mat SLAM_img_with_text = pSlamFrameDrawer_->DrawFrame(1.0f);
if (SLAM_image_viewer_scale_ != 1.0f)
{
int width = rendered_image_width_;
int height = static_cast<int>(SLAM_img_with_text.rows * SLAM_image_viewer_scale_);
cv::resize(SLAM_img_with_text, SLAM_img_with_text, cv::Size(width, height));
SLAM_img_to_show = cv::Mat(height, padded_sub_image_width_, CV_8UC3, cv::Vec3f(0, 0, 0));
}
else
{
SLAM_img_to_show = cv::Mat(image_height_, padded_sub_image_width_, CV_8UC3, cv::Vec3f(0, 0, 0));
}
cv::Rect SLAM_image_rect(0, 0, SLAM_img_with_text.cols, SLAM_img_with_text.rows);
SLAM_img_with_text.copyTo(SLAM_img_to_show(SLAM_image_rect));
glBindTexture(GL_TEXTURE_2D, SLAM_img_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SLAM_img_to_show.cols, SLAM_img_to_show.rows,
0, GL_BGR, GL_UNSIGNED_BYTE, (unsigned char*)SLAM_img_to_show.data);
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(rendered_image_width_ + 12, SLAM_img_to_show.rows + 40), ImGuiCond_Once);
{
ImGui::Begin("SLAM Frame");
ImGui::Image((void *)(intptr_t)SLAM_img_texture,
ImVec2(SLAM_img_to_show.cols, SLAM_img_to_show.rows));
ImGui::End();
}
cv::Mat rendered_img = pGausMapper_->renderFromPose(
Tcw, rendered_image_width_, rendered_image_height_, false);
cv::Mat rendered_img_to_show = cv::Mat(rendered_image_height_, padded_sub_image_width_, CV_32FC3, cv::Vec3f(0.0f, 0.0f, 0.0f));
rendered_img.copyTo(rendered_img_to_show(image_rect_sub));
glBindTexture(GL_TEXTURE_2D, rendered_img_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rendered_img_to_show.cols, rendered_img_to_show.rows,
0, GL_RGB, GL_FLOAT, (float*)rendered_img_to_show.data);
ImGui::SetNextWindowPos(ImVec2(0, SLAM_img_to_show.rows + 40), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(rendered_image_width_ + 12, rendered_img_to_show.rows + 40), ImGuiCond_Once);
{
ImGui::Begin("Current Rendered Frame");
ImGui::Image((void *)(intptr_t)rendered_img_texture,
ImVec2(rendered_img_to_show.cols, rendered_img_to_show.rows));
ImGui::End();
}
}
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
if (show_main_rendered_)
{
auto drawlist = ImGui::GetBackgroundDrawList();
if (pSLAM_ && tracking_vision_)
{
drawlist->AddImage((void *)(intptr_t)rendered_img_texture, ImVec2(0, 0),
ImVec2(glfw_window_width_, glfw_window_height_));
}
else
{
cv::Mat main_img = pGausMapper_->renderFromPose(
Tcw_main_, rendered_image_width_main_, rendered_image_height_main_, true);
cv::Mat main_img_to_show = cv::Mat(rendered_image_height_main_, padded_main_image_width_, CV_32FC3, cv::Vec3f(0.0f, 0.0f, 0.0f));
main_img.copyTo(main_img_to_show(image_rect_main));
glBindTexture(GL_TEXTURE_2D, main_img_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, main_img_to_show.cols, main_img_to_show.rows,
0, GL_RGB, GL_FLOAT, (float*)main_img_to_show.data);
drawlist->AddImage((void *)(intptr_t)main_img_texture, ImVec2(0, 0),
ImVec2(glfw_window_width_, glfw_window_height_));
}
}
VariableParameters params_in = pGausMapper_->getVaribleParameters();
position_lr_init_ = params_in.position_lr_init;
feature_lr_ = params_in.feature_lr;
opacity_lr_ = params_in.opacity_lr;
scaling_lr_ = params_in.scaling_lr;
rotation_lr_ = params_in.rotation_lr;
percent_dense_ = params_in.percent_dense;
lambda_dssim_ = params_in.lambda_dssim;
opacity_reset_interval_ = params_in.opacity_reset_interval;
densify_grad_th_ = params_in.densify_grad_th;
densify_interval_ = params_in.densify_interval;
new_kf_times_of_use_ = params_in.new_kf_times_of_use;
stable_num_iter_existence_ = params_in.stable_num_iter_existence;
keep_training_ = params_in.keep_training;
do_gaus_pyramid_training_ = params_in.do_gaus_pyramid_training;
do_inactive_geo_densify_ = params_in.do_inactive_geo_densify;
ImGui::SetNextWindowPos(ImVec2(glfw_window_width_ - panel_width_, 0), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(panel_width_, display_panel_height_), ImGuiCond_Once);
{
ImGui::Begin("Display Mode");
if (training_)
{
ImGui::Checkbox("Tracking vision", &tracking_vision_);
ImGui::Checkbox("Show KeyFrames", &show_keyframes_);
ImGui::Checkbox("Show sparse MapPoints", &show_sparse_mappoints_);
}
ImGui::Checkbox("Show main window rendered", &show_main_rendered_);
ImGui::Text("Viewer average FPS %.1f", io.Framerate);
ImGui::End();
}
if (training_)
{
ImGui::SetNextWindowPos(ImVec2(glfw_window_width_ - panel_width_, display_panel_height_ + 8), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(panel_width_, training_panel_height_), ImGuiCond_Once);
{
ImGui::Begin("Training Options");
ImGui::Text("Iteration: %d", pGausMapper_->getIteration());
ImGui::Checkbox("Gaussian-pyramid-based training", &do_gaus_pyramid_training_);
ImGui::Checkbox("Densify with inactive geometries", &do_inactive_geo_densify_);
ImGui::Checkbox("Keep training after stop", &keep_training_);
ImGui::SliderFloat("Position l.r.", &position_lr_init_, 0.00001f, 0.00100f, "%.5f");
ImGui::SliderFloat("Feature l.r.", &feature_lr_, 0.0001f, 0.0050f, "%.5f");
ImGui::SliderFloat("Opacity l.r.", &opacity_lr_, 0.01f, 0.10f, "%.5f");
ImGui::SliderFloat("Scaling l.r.", &scaling_lr_, 0.001f, 0.010f, "%.5f");
ImGui::SliderFloat("Rotation l.r.", &rotation_lr_, 0.0001f, 0.0100f, "%.5f");
ImGui::SliderFloat("Percent dense", &percent_dense_, 0.001f, 0.100f, "%.3f");
ImGui::SliderFloat("Lambda dssim", &lambda_dssim_, 0.01f, 0.40f, "%.2f");
ImGui::SliderInt("Opacity reset", &opacity_reset_interval_, 0, 6000);
ImGui::SliderFloat("Densify grad th.", &densify_grad_th_, 0.0001f, 0.0020f, "%.5f");
ImGui::SliderInt("Densify int.", &densify_interval_, 1, 400);
ImGui::SliderInt("New kf. using", &new_kf_times_of_use_, 0, 10);
ImGui::SliderInt("Stable iter.", &stable_num_iter_existence_, 0, 100);
ImGui::End();
}
}
VariableParameters params_out;
params_out.position_lr_init = position_lr_init_;
params_out.feature_lr = feature_lr_;
params_out.opacity_lr = opacity_lr_;
params_out.scaling_lr = scaling_lr_;
params_out.rotation_lr = rotation_lr_;
params_out.percent_dense = percent_dense_;
params_out.lambda_dssim = lambda_dssim_;
params_out.opacity_reset_interval = opacity_reset_interval_;
params_out.densify_grad_th = densify_grad_th_;
params_out.densify_interval = densify_interval_;
params_out.new_kf_times_of_use = new_kf_times_of_use_;
params_out.stable_num_iter_existence = stable_num_iter_existence_;
params_out.keep_training = keep_training_;
params_out.do_gaus_pyramid_training = do_gaus_pyramid_training_;
params_out.do_inactive_geo_densify = do_inactive_geo_densify_;
pGausMapper_->setVaribleParameters(params_out);
ImGui::SetNextWindowPos(ImVec2(glfw_window_width_ - panel_width_, (training_ ? display_panel_height_ + training_panel_height_ + 16 : display_panel_height_ + 8)), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(panel_width_, camera_panel_height_), ImGuiCond_Once);
{
ImGui::Begin("Camera View Velocity");
ImGui::SliderFloat("Mouse Left", &mouse_left_sensitivity_, 0.01f, 1.0f, "%.2f");
ImGui::SliderFloat("Mouse Right", &mouse_right_sensitivity_, 0.01f, 1.0f, "%.2f");
ImGui::SliderFloat("Mouse Middle", &mouse_middle_sensitivity_, 0.01f, 1.0f, "%.2f");
ImGui::SliderFloat("Keyboard t", &keyboard_velocity_, 0.01f, 1.0f, "%.2f");
ImGui::SliderFloat("Keyboard R", &keyboard_anglular_velocity_, 0.01f, 1.0f, "%.2f");
ImGui::End();
}
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glPushMatrix();
glMultMatrixf(&cam_trans_[0][0]);
if (pSLAM_ && show_keyframes_)
{
pMapDrawer_->DrawCurrentCamera(tracking_vision_ ? glmTwc : glmTwc_main_);
pMapDrawer_->DrawKeyFrames(true, false, true, false);
}
if (pSLAM_ && show_sparse_mappoints_)
{
pMapDrawer_->DrawMapPoints();
}
glPopMatrix();
glfwSwapBuffers(window);
glfwPollEvents();
if (!keep_training_ && pGausMapper_->isStopped())
signalStop();
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
if (pSLAM_ && !pSLAM_->isShutDown())
pSLAM_->Shutdown();
else
pGausMapper_->signalStop();
if (pGausMapper_->isKeepingTraining())
pGausMapper_->setKeepTraining(false);
}
bool ImGuiViewer::isStopped()
{
std::unique_lock<std::mutex> lock_status(this->mutex_status_);
return this->stopped_;
}
void ImGuiViewer::signalStop(const bool going_to_stop)
{
std::unique_lock<std::mutex> lock_status(this->mutex_status_);
this->stopped_ = going_to_stop;
}
* We modify Twc_main_ then Tcw_main_ (Sophus::SE3f) to handle mouse and keyboard inputs
*/
void ImGuiViewer::handleUserInput()
{
if (tracking_vision_)
{
free_view_enabled_ = false;
return;
}
else
{
free_view_enabled_ = true;
}
Twc_main_ = Tcw_main_.inverse();
if (!ImGui::IsAnyItemActive() && !ImGui::GetIO().WantCaptureMouse)
{
mouseWheel();
mouseDrag();
}
keyboardEvent();
Tcw_main_ = Twc_main_.inverse();
}
void ImGuiViewer::mouseWheel()
{
float delta = ImGui::GetIO().MouseWheel;
if (delta == 0)
return;
float scale_factor = std::pow(1.1f, -delta);
Eigen::Matrix3f R = Twc_main_.rotationMatrix();
Twc_main_.translation() *= scale_factor;
}
void ImGuiViewer::mouseDrag()
{
float delta_rel_x = ImGui::GetIO().MouseDelta.x / glfw_window_width_;
float delta_rel_y = ImGui::GetIO().MouseDelta.y / glfw_window_height_;
float delta_l = delta_rel_x * delta_rel_x + delta_rel_y * delta_rel_y;
Eigen::Vector3f eulars = Eigen::Vector3f::Zero();
if (ImGui::GetIO().MouseDown[0])
{
eulars.x() -= M_PI * delta_rel_y;
eulars.y() += M_PI * delta_rel_x;
eulars.x() *= mouse_left_sensitivity_;
eulars.y() *= mouse_left_sensitivity_;
}
if (ImGui::GetIO().MouseDown[1])
{
eulars.z() += M_PI * (delta_rel_x < 0.0f ? -delta_l : delta_l);
eulars.z() *= mouse_right_sensitivity_;
}
Eigen::AngleAxisf roll_angle(eulars.z(), Eigen::Vector3f::UnitZ());
Eigen::AngleAxisf yaw_angle(eulars.y(), Eigen::Vector3f::UnitY());
Eigen::AngleAxisf pitch_angle(eulars.x(), Eigen::Vector3f::UnitX());
Eigen::Quaternion<float> q = roll_angle * yaw_angle * pitch_angle;
Eigen::Matrix3f rotating = q.matrix();
Eigen::Vector3f translating = Eigen::Vector3f::Zero();
if (ImGui::GetIO().MouseDown[2])
{
translating.x() += delta_rel_x;
translating.y() -= delta_rel_y;
translating *= mouse_middle_sensitivity_;
}
Eigen::Matrix3f R = Twc_main_.rotationMatrix();
Twc_main_.translation() += (R * translating);
Twc_main_.setRotationMatrix(R * rotating);
}
void ImGuiViewer::keyboardEvent()
{
if (ImGui::GetIO().WantCaptureKeyboard)
return;
if (ImGui::IsKeyPressed(ImGuiKey_R))
reset_main_to_init_ = true;
Eigen::Vector3f translating = Eigen::Vector3f::Zero();
if (ImGui::IsKeyDown(ImGuiKey_W))
translating.z() += 1.0f;
if (ImGui::IsKeyDown(ImGuiKey_S))
translating.z() -= 1.0f;
if (ImGui::IsKeyDown(ImGuiKey_A))
translating.x() -= 1.0f;
if (ImGui::IsKeyDown(ImGuiKey_D))
translating.x() += 1.0f;
translating *= keyboard_velocity_;
Eigen::Vector3f eulars = Eigen::Vector3f::Zero();
if (ImGui::IsKeyDown(ImGuiKey_I))
eulars.x() += M_PI;
if (ImGui::IsKeyDown(ImGuiKey_K))
eulars.x() -= M_PI;
if (ImGui::IsKeyDown(ImGuiKey_J))
eulars.y() -= M_PI;
if (ImGui::IsKeyDown(ImGuiKey_L))
eulars.y() += M_PI;
if (ImGui::IsKeyDown(ImGuiKey_U))
eulars.z() -= M_PI;
if (ImGui::IsKeyDown(ImGuiKey_O))
eulars.z() += M_PI;
eulars *= keyboard_anglular_velocity_;
Eigen::AngleAxisf roll_angle(eulars.z(), Eigen::Vector3f::UnitZ());
Eigen::AngleAxisf yaw_angle(eulars.y(), Eigen::Vector3f::UnitY());
Eigen::AngleAxisf pitch_angle(eulars.x(), Eigen::Vector3f::UnitX());
Eigen::Quaternion<float> q = roll_angle * yaw_angle * pitch_angle;
Eigen::Matrix3f rotating = q.matrix();
Eigen::Matrix3f R = Twc_main_.rotationMatrix();
Twc_main_.translation() += (R * translating);
Twc_main_.setRotationMatrix(R * rotating);
}