Skip to content

Commit

Permalink
mola_kernel: new UI interface for datasets
Browse files Browse the repository at this point in the history
  • Loading branch information
jlblancoc committed Feb 20, 2024
1 parent c3dc1fc commit 6c1102c
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 4 deletions.
47 changes: 47 additions & 0 deletions mola_kernel/include/mola_kernel/interfaces/Dataset_UI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* -------------------------------------------------------------------------
* A Modular Optimization framework for Localization and mApping (MOLA)
* Copyright (C) 2018-2024 Jose Luis Blanco, University of Almeria
* See LICENSE for license information.
* ------------------------------------------------------------------------- */
/**
* @file Dataset_UI.h
* @brief Virtual interface for offline dataset sources to have a GUI
* @author Jose Luis Blanco Claraco
* @date Feb 20, 2024
*/
#pragma once

#include <cstdlib>
#include <memory>

namespace mola
{
/** Virtual base for offline dataset sources to have a GUI within MolaViz
* \ingroup mola_kernel_grp */
class Dataset_UI
{
public:
Dataset_UI() = default;
virtual ~Dataset_UI() = default;

/** @name Virtual interface of Dataset_UI
*{ */

/** Number of different time steps available to call getObservations() */
virtual size_t datasetUI_size() const = 0;

/** Returns the latest requested observation, range [0, datasetSize()] */
virtual size_t datasetUI_lastQueriedTimestep() const = 0;

virtual double datasetUI_playback_speed() const = 0;
virtual void datasetUI_playback_speed(double speed) = 0;

virtual bool datasetUI_paused() const = 0;
virtual void datasetUI_paused(bool paused) = 0;

/** Forces continue replaying in this moment in time */
virtual void datasetUI_teleport(size_t timestep) = 0;
/** @} */
};

} // namespace mola
2 changes: 1 addition & 1 deletion mola_kernel/include/mola_kernel/interfaces/FrontEndBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class FrontEndBase : public ExecutableBase, RawDataConsumer
* multiple sensors.
*
*/
void initialize_common(const Yaml& cfg);
void initialize_common(const Yaml& cfg) override;

protected:
/** A list of one or multiple MOLA **module names** to which to subscribe
Expand Down
18 changes: 18 additions & 0 deletions mola_viz/include/mola_viz/MolaViz.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/
#pragma once

#include <mola_kernel/interfaces/Dataset_UI.h>
#include <mola_kernel/interfaces/ExecutableBase.h>
#include <mola_kernel/interfaces/VizInterface.h>
#include <mrpt/gui/CDisplayWindowGUI.h>
Expand Down Expand Up @@ -157,6 +158,23 @@ class MolaViz : public ExecutableBase, public VizInterface
task_queue_t guiThreadPendingTasks_;
std::set<window_name_t> guiThreadMustReLayoutTheseWindows_;
std::mutex guiThreadPendingTasksMtx_;

double lastTimeCheckForNewModules_ = 0;
double lastTimeUpdateDatasetUIs_ = 0;
struct DataPerDatasetUI
{
std::shared_ptr<mola::Dataset_UI> module;

nanogui::Window* ui = nullptr;
nanogui::Label* lbPlaybackPosition = nullptr;
nanogui::Slider* slider = nullptr;
nanogui::CheckBox* cbPaused = nullptr;
nanogui::ComboBox* cmRate = nullptr;
};
std::map<std::string, DataPerDatasetUI> datasetUIs_;

void dataset_ui_check_new_modules();
void dataset_ui_update();
};

} // namespace mola
105 changes: 102 additions & 3 deletions mola_viz/src/MolaViz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,106 @@ void MolaViz::initialize(const Yaml& c)

void MolaViz::spinOnce()
{
// Nothing to do.
// once every X seconds, check for modules with automatically generated
// UI by this MolaViz:
const double PERIOD_CHECK_NEW_MODS = 2.0;
const double PERIOD_UPDATE_DATASET_UI = 0.25;

const double tNow = mrpt::Clock::nowDouble();
if (tNow - lastTimeCheckForNewModules_ > PERIOD_CHECK_NEW_MODS)
{
dataset_ui_check_new_modules();
lastTimeCheckForNewModules_ = tNow;
}
if (tNow - lastTimeUpdateDatasetUIs_ > PERIOD_UPDATE_DATASET_UI)
{
dataset_ui_update();
lastTimeUpdateDatasetUIs_ = tNow;
}
}

void MolaViz::dataset_ui_check_new_modules()
{
auto datasetUIs = findService<Dataset_UI>();
for (auto& module : datasetUIs)
{
const auto modUI = std::dynamic_pointer_cast<Dataset_UI>(module);
ASSERT_(modUI);

auto& e = datasetUIs_[module->getModuleInstanceName()];
if (e.module) continue; // an already known one

e.module = modUI;

// Create UI:
auto fut = this->create_subwindow(module->getModuleInstanceName());
e.ui = fut.get();
e.ui->requestFocus();
e.ui->setVisible(true);
e.ui->setPosition({300, 5});

e.ui->setLayout(new nanogui::BoxLayout(
nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 5,
2));
e.ui->setFixedWidth(650);
e.ui->setFixedHeight(60);

e.cbPaused = e.ui->add<nanogui::CheckBox>("Paused");
e.cbPaused->setChecked(modUI->datasetUI_paused());
e.cbPaused->setCallback(
[modUI](bool checked) { modUI->datasetUI_paused(checked); });

e.lbPlaybackPosition = e.ui->add<nanogui::Label>("Progress: ");
e.lbPlaybackPosition->setFixedWidth(100);
e.slider = e.ui->add<nanogui::Slider>();
e.slider->setFixedWidth(300);
e.slider->setCallback([modUI](float pos) {
modUI->datasetUI_teleport(static_cast<size_t>(pos));
});

e.ui->add<nanogui::Label>("Playback rate:");
e.cmRate = e.ui->add<nanogui::ComboBox>();
const std::vector<float> rates = {0.1, 0.25, 0.5, 0.75, 1.0,
1.25, 1.5, 2.0, 3.0, 5.0};
e.cmRate->setItems(
{"x0.1", "x0.25", "x0.5", "x0.75", "x1.0", "x1.25", "x1.5", "x2.0",
"x3.0", "x5.0"});
int selIdx = 4;
const double initialRate = modUI->datasetUI_playback_speed();
for (size_t i = 0; i < rates.size(); i++)
if (rates[i] == initialRate)
{
selIdx = i;
break;
}
e.cmRate->setSelectedIndex(selIdx);
e.cmRate->setCallback([rates, modUI](int idx) {
const double rate = rates.at(idx);
modUI->datasetUI_playback_speed(rate);
});

markWindowForReLayout(DEFAULT_WINDOW_NAME);
}
}

void MolaViz::dataset_ui_update()
{
for (auto& kv : datasetUIs_)
{
this->enqueue_custom_nanogui_code([&kv]() {
auto& e = kv.second; // lambda capture structured bind is >C++20
if (!e.module) return;

const size_t pos = e.module->datasetUI_lastQueriedTimestep();
const size_t N = e.module->datasetUI_size();

e.lbPlaybackPosition->setCaption(mrpt::format("%zu / %zu", pos, N));
e.slider->setRange(std::make_pair<float>(0, N));
e.slider->setValue(pos);
e.slider->setHighlightedRange(
std::make_pair<float>(0.f, pos * 1.0f / (N)));
});
}
}

mrpt::gui::CDisplayWindowGUI::Ptr MolaViz::create_and_add_window(
Expand Down Expand Up @@ -811,8 +910,8 @@ std::future<bool> MolaViz::update_3d_object(
topWin->background_scene->insert(glContainer, viewportName);
}

// Move user contents and container properties (pose, scale, etc.)
// via the "operator=":
// Move user contents and container properties (pose, scale,
// etc.) via the "operator=":
*glContainer = *obj;

// (except the name! which we need to re-use in the next call)
Expand Down

0 comments on commit 6c1102c

Please sign in to comment.