Skip to content

Commit

Permalink
Merge pull request #1173 from MRPT/feature/navlog-ui-improvement
Browse files Browse the repository at this point in the history
Feature/navlog UI improvement
  • Loading branch information
jlblancoc committed Sep 20, 2021
2 parents af8dfc3 + b98db67 commit 78ea3a0
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 26 deletions.
49 changes: 43 additions & 6 deletions apps/navlog-viewer/navlog-viewer-ui.cpp
Expand Up @@ -206,24 +206,24 @@ NavlogViewerApp::NavlogViewerApp()
{
auto* panel = layer->add<nanogui::Widget>();
panel->setLayout(new nanogui::BoxLayout(
nanogui::Orientation::Horizontal, nanogui::Alignment::Fill, 5));
nanogui::Orientation::Horizontal, nanogui::Alignment::Fill, 0));
panel->add<nanogui::Label>("Min. dist. robot shapes:");
edShapeMinDist = panel->add<nanogui::TextBox>("1.0");
edShapeMinDist->setEditable(true);
edShapeMinDist->setFormat("[0-9.]*");
}

m_cbOrtho2DView = layer->add<nanogui::CheckBox>("Orthogonal 2D mode");
m_cbOrtho2DView->setChecked(true);
// No need to catch callbacks: the checkbox is checked in the GUI main
// loop.

layer->add<nanogui::Label>("Show for each PTG:");
const auto lst = std::vector<std::string>(
{"TP-Obstacles only", "+ final scores", "+ preliminary scores"});
m_rbPerPTGPlots = layer->add<nanogui::ComboBox>(lst, lst);
m_rbPerPTGPlots->setCallback([this](int) { updateVisualization(); });
m_rbPerPTGPlots->setSelectedIndex(2);

auto cbOrtho = layer->add<nanogui::CheckBox>("Orthogonal");
cbOrtho->setCallback([this](bool ortho) {
m_win->camera().setCameraProjective(!ortho);
});
}

// ===== TAB: Advanced
Expand Down Expand Up @@ -308,6 +308,16 @@ NavlogViewerApp::NavlogViewerApp()
m_win->camera().setElevationDegrees(90.0f);
m_win->camera().setZoomDistance(25.0f);

{
auto vi = scene->createViewport("xyz");
vi->setViewportPosition(-0.1, 0.0, 0.1, 0.1);
vi->setTransparent(true);

auto glCorners =
mrpt::opengl::stock_objects::CornerXYZSimple(1.0f, 1.0f);
scene->insert(glCorners, "xyz");
}

// XY ground plane:
mrpt::opengl::CGridPlaneXY::Ptr gl_grid =
mrpt::opengl::CGridPlaneXY::Create(-20, 20, -20, 20, 0, 1, 0.75f);
Expand Down Expand Up @@ -467,6 +477,33 @@ void NavlogViewerApp::OnMainIdleLoop()
}

if (m_showCursorXY) { OntimMouseXY(); }

// Restrict camera motion:
if (m_win->background_scene)
{
auto& mainCam = m_win->camera();
if (m_cbOrtho2DView->checked())
{
mainCam.setElevationDegrees(90);
mainCam.setAzimuthDegrees(-90);
}
mainCam.setCameraProjective(!m_cbOrtho2DView->checked());
}

// Copy camera orientation from the main window into the small XYZ view:
if (m_win && m_win->background_scene)
{
if (auto view = m_win->background_scene->getViewport("xyz"); view)
{
auto& mainCam = m_win->camera();
auto& xyzCam = view->getCamera();

xyzCam.setAzimuthDegrees(mainCam.getAzimuthDegrees());
xyzCam.setElevationDegrees(mainCam.getElevationDegrees());
xyzCam.setOrthogonal(true);
xyzCam.setZoomDistance(2.0);
}
}
}

bool NavlogViewerApp::OnKeyboardCallback(
Expand Down
1 change: 1 addition & 0 deletions apps/navlog-viewer/navlog-viewer-ui.h
Expand Up @@ -43,6 +43,7 @@ class NavlogViewerApp
nanogui::CheckBox* m_cbShowCursor = nullptr;
nanogui::CheckBox* m_ClearanceOverPath = nullptr;
nanogui::ComboBox* m_rbPerPTGPlots = nullptr;
nanogui::CheckBox* m_cbOrtho2DView = nullptr;

nanogui::CheckBox* m_cbManualPickMode = nullptr;
nanogui::Slider* m_slidPtgIndex = nullptr;
Expand Down
6 changes: 6 additions & 0 deletions doc/source/doxygen-docs/changelog.md
Expand Up @@ -4,6 +4,8 @@
- Changes in applications:
- ptg-configurator:
- Show selected PTG path output motion command.
- navlog-viewer:
- New checkbox to enforce 2D orthogonal view, which is now the default view.
- rawlog-edit
- The `--info` command now also shows the first and last timestamp in a rawlog.
- RawLogViewer:
Expand All @@ -27,6 +29,8 @@
- mrpt::nav::CParameterizedTrajectoryGenerator::initTPObstacleSingle() now always initializes to the maximum free distance, instead of saturating free space when heading to a target waypoint.
- \ref mrpt_obs_grp
- Fix const-correctness of mrpt::obs::CObservation::unload() for consistency with load().
- \ref mrpt_opengl_grp
- New method mrpt::opengl::COpenGLViewport::setClonedCameraFrom()
- \ref mrpt_poses_grp
- New function mrpt::poses::sensor_poses_from_yaml()
- New header `<mrpt/poses/gtsam_wrappers.h>`, see \ref mrpt_gtsam_wrappers
Expand All @@ -36,6 +40,7 @@
- \ref mrpt_system_grp
- Backwards-compatible change: New function mrpt::system::InvalidTimeStamp() used now inside the macro INVALID_TIMESTAMP, so the macro always returns a const reference instead of returning by value.
- New function mrpt::system::consoleColorAndStyle()
- mrpt::system::intervalFormat() now generates more human-friendly strings for time periods larger than 1 second (e.g. "1 year, 3 days, 8 hours").
- \ref mrpt_vision_grp
- SIFT descriptors can now be evaluated for arbitrary keypoint coordinates.
- BUG FIXES:
Expand All @@ -48,6 +53,7 @@
- mrpt::comms::CClientTCPSocket crashed if socket handle >=1024 in Linux (Closes [#1157](https://github.com/MRPT/mrpt/issues/1157))
- Fix error generating and parsing TUM RGBD dataset rawlog files.
- Fix regresion in mrpt::opengl::CFBORender::render() throwing an exception if the input image was empty.
- Fix incorrect handling of negative, fractional viewport sizes in mrpt::opengl::COpenGLViewport

# Version 2.3.2: Released Jul 14, 2021
- Changes in applications:
Expand Down
25 changes: 24 additions & 1 deletion libs/opengl/include/mrpt/opengl/COpenGLViewport.h
Expand Up @@ -101,10 +101,22 @@ class COpenGLViewport : public mrpt::serialization::CSerializable,
* \sa setCloneView, setNormalMode
*/
inline void resetCloneView() { setNormalMode(); }

/** If set to true, and setCloneView() has been called, this viewport will
* be rendered using the camera of the cloned viewport.
*/
inline void setCloneCamera(bool enable) { m_isClonedCamera = enable; }
void setCloneCamera(bool enable);

/** Use the camera of another viewport.
* Note this works even for viewports not in "clone" mode, so you can
* render different scenes but using the same camera.
*/
inline void setClonedCameraFrom(const std::string& viewPortName)
{
m_isClonedCamera = true;
m_clonedCameraViewport = viewPortName;
}

/** Resets the viewport to a normal 3D viewport \sa setCloneView,
* setImageView */
void setNormalMode();
Expand Down Expand Up @@ -363,18 +375,29 @@ class COpenGLViewport : public mrpt::serialization::CSerializable,

/** The camera associated to the viewport */
opengl::CCamera m_camera;

/** The scene that contains this viewport. */
mrpt::safe_ptr<COpenGLScene> m_parent;

/** Set by setCloneView */
bool m_isCloned{false};

/** Set by setCloneCamera */
bool m_isClonedCamera{false};

/** Only if m_isCloned=true */
std::string m_clonedViewport;

/** If m_isClonedCamera && !m_isCloned, take the camera from another view,
* to render a different scene. */
std::string m_clonedCameraViewport;

/** The viewport's name */
std::string m_name;

/** Whether to clear color buffer. */
bool m_isTransparent{false};

/** Default=0, the border around the viewport. */
uint32_t m_borderWidth{0};

Expand Down
55 changes: 49 additions & 6 deletions libs/opengl/src/COpenGLViewport.cpp
Expand Up @@ -120,9 +120,15 @@ static int sizeFromRatio(
}
static int startFromRatio(const double frac, const int dSize)
{
return frac > 1 ? static_cast<int>(frac)
: (frac < 0 ? static_cast<int>(dSize + frac)
: static_cast<int>(dSize * frac));
const bool doWrap = (frac < 0);
const auto fracAbs = std::abs(frac);

const int L = fracAbs > 1 ? static_cast<int>(fracAbs)
: static_cast<int>(dSize * fracAbs);

int ret = doWrap ? dSize - L : L;

return ret;
}

// "Image mode" rendering:
Expand Down Expand Up @@ -217,19 +223,33 @@ void COpenGLViewport::renderNormalSceneMode() const
{ // Clone: render someone's else objects.
ASSERT_(m_parent.get() != nullptr);

COpenGLViewport::Ptr view = m_parent->getViewport(m_clonedViewport);
const auto view = m_parent->getViewport(m_clonedViewport);
if (!view)
THROW_EXCEPTION_FMT(
"Cloned viewport '%s' not found in parent COpenGLScene",
m_clonedViewport.c_str());

objectsToRender = &view->m_objects;
}
else
{ // Normal case: render our own objects:
objectsToRender = &m_objects;
viewForGetCamera = const_cast<COpenGLViewport*>(this);
}

if (!m_clonedCameraViewport.empty())
{
const auto view = m_parent->getViewport(m_clonedCameraViewport);
if (!view)
THROW_EXCEPTION_FMT(
"Cloned viewport '%s' not found in parent COpenGLScene",
m_clonedViewport.c_str());

viewForGetCamera =
m_isClonedCamera ? view.get() : const_cast<COpenGLViewport*>(this);
}
else
{ // Normal case: render our own objects:
objectsToRender = &m_objects;
viewForGetCamera = const_cast<COpenGLViewport*>(this);
}

Expand Down Expand Up @@ -546,7 +566,7 @@ void COpenGLViewport::render(
#endif
}

uint8_t COpenGLViewport::serializeGetVersion() const { return 5; }
uint8_t COpenGLViewport::serializeGetVersion() const { return 6; }
void COpenGLViewport::serializeTo(mrpt::serialization::CArchive& out) const
{
// Save data:
Expand Down Expand Up @@ -588,6 +608,9 @@ void COpenGLViewport::serializeTo(mrpt::serialization::CArchive& out) const
// Added in v5: image mode
out.WriteAs<bool>(m_imageViewPlane);
if (m_imageViewPlane) out << *m_imageViewPlane;

// Added in v6:
out << m_clonedCameraViewport;
}

void COpenGLViewport::serializeFrom(
Expand All @@ -601,6 +624,7 @@ void COpenGLViewport::serializeFrom(
case 3:
case 4:
case 5:
case 6:
{
// Load data:
in >> m_camera >> m_isCloned >> m_isClonedCamera >>
Expand Down Expand Up @@ -673,6 +697,10 @@ void COpenGLViewport::serializeFrom(
{
m_imageViewPlane.reset();
}

if (version >= 6) in >> m_clonedCameraViewport;
else
m_clonedCameraViewport.clear();
}
break;
default: MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version);
Expand Down Expand Up @@ -974,3 +1002,18 @@ auto COpenGLViewport::getBoundingBox() const -> mrpt::math::TBoundingBox

return bb;
}

void COpenGLViewport::setCloneCamera(bool enable)
{
m_isClonedCamera = enable;
if (!enable) { m_clonedCameraViewport.clear(); }
else
{
ASSERTMSG_(
!m_clonedViewport.empty(),
"Error: cannot setCloneCamera(true) on a viewport before calling "
"setCloneView()");

m_clonedCameraViewport = m_clonedViewport;
}
}
10 changes: 8 additions & 2 deletions libs/system/include/mrpt/system/datetime.h
Expand Up @@ -198,8 +198,14 @@ std::string timeLocalToString(
/** This function implements time interval formatting: Given a time in seconds,
* it will return a string describing the interval with the most appropriate
* unit.
* E.g.: 1.23 year, 3.50 days, 9.3 hours, 5.3 minutes, 3.34 sec, 178.1 ms, 87.1
* us.
* E.g.:
* - "1 year, 3 days, 4 minutes"
* - "3 days, 8 hours"
* - "9 hours, 4 minutes, 4.3 sec",
* - "3.34 sec"
* - "178.1 ms"
* - "87.1 us"
*
* \sa unitsFormat
*/
std::string intervalFormat(const double seconds);
Expand Down
39 changes: 28 additions & 11 deletions libs/system/src/datetime.cpp
Expand Up @@ -285,22 +285,34 @@ string mrpt::system::dateToString(const mrpt::system::TTimeStamp tt)
"%u/%02u/%02u", 1900 + ptm->tm_year, ptm->tm_mon + 1, ptm->tm_mday);
}

/** This function implements time interval formatting: Given a time in seconds,
* it will return a string describing the interval with the most appropriate
* unit.
* E.g.: 1.23 year, 3.50 days, 9.3 hours, 5.3 minutes, 3.34 sec, 178.1 ms, 87.1
* us.
*/
std::string mrpt::system::intervalFormat(const double seconds)
static std::string implIntervalFormat(const double seconds)
{
using namespace std::string_literals;

if (seconds >= 365 * 24 * 3600)
return format("%.2f years", seconds / (365 * 24 * 3600));
{
const int i = static_cast<int>(seconds / (365 * 24 * 3600));
return format("%i year%s", i, i > 1 ? "s" : "") + ", "s +
implIntervalFormat(std::fmod(seconds, (365 * 24 * 3600)));
}
else if (seconds >= 24 * 3600)
return format("%.2f days", seconds / (24 * 3600));
{
const int i = static_cast<int>(seconds / (24 * 3600));
return format("%i day%s", i, i > 1 ? "s" : "") + ", "s +
implIntervalFormat(std::fmod(seconds, (24 * 3600)));
}
else if (seconds >= 3600)
return format("%.2f hours", seconds / 3600);
{
const int i = static_cast<int>(seconds / 3600);
return format("%i hour%s", i, i > 1 ? "s" : "") + ", "s +
implIntervalFormat(std::fmod(seconds, 3600));
}
else if (seconds >= 60)
return format("%.2f minutes", seconds / 60);
{
const int i = static_cast<int>(seconds / 60);
return format("%i minute%s", i, i > 1 ? "s" : "") + ", "s +
implIntervalFormat(std::fmod(seconds, 60));
}
else if (seconds >= 1)
return format("%.2f sec", seconds);
else if (seconds >= 1e-3)
Expand All @@ -311,6 +323,11 @@ std::string mrpt::system::intervalFormat(const double seconds)
return format("%.2f ns", seconds * 1e9);
}

std::string mrpt::system::intervalFormat(const double seconds)
{
return implIntervalFormat(seconds);
}

std::ostream& mrpt::system::operator<<(std::ostream& o, const TTimeStamp& t)
{
const uint64_t v = t.time_since_epoch().count();
Expand Down

0 comments on commit 78ea3a0

Please sign in to comment.