diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 6de6d931b..c129ca4fe 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -5,7 +5,7 @@ labels: bug
---
+https://robotics.stackexchange.com instead.-->
## Environment
* OS Version:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 87233a479..52b56e336 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -6,7 +6,7 @@ labels: enhancement
+https://robotics.stackexchange.com instead.-->
## Desired behavior
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ab45c9400..bdac4dc4c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,6 +1,12 @@
name: Ubuntu CI
-on: [push, pull_request]
+on:
+ pull_request:
+ push:
+ branches:
+ - 'ign-gui[0-9]'
+ - 'gz-gui[0-9]?'
+ - 'main'
jobs:
jammy-ci:
@@ -8,7 +14,7 @@ jobs:
name: Ubuntu Jammy CI
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Compile and test
id: ci
uses: gazebo-tooling/action-gz-ci@jammy
diff --git a/.github/workflows/package_xml.yml b/.github/workflows/package_xml.yml
new file mode 100644
index 000000000..4bd4a9aa0
--- /dev/null
+++ b/.github/workflows/package_xml.yml
@@ -0,0 +1,11 @@
+name: Validate package.xml
+
+on:
+ pull_request:
+
+jobs:
+ package-xml:
+ runs-on: ubuntu-latest
+ name: Validate package.xml
+ steps:
+ - uses: gazebo-tooling/action-gz-ci/validate_package_xml@jammy
diff --git a/Changelog.md b/Changelog.md
index 4aff88aa6..71b64e06c 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -4,6 +4,49 @@
## Gazebo GUI 8
+### Gazebo GUI 8.3.0 (2024-06-20)
+
+1. Backport: Adding cone primitives.
+ * [Pull request #621](https://github.com/gazebosim/gz-gui/pull/621)
+
+### Gazebo GUI 8.2.0 (2024-06-14)
+
+1. Enhanced tracking camera and user visualization experience
+ * [Pull request #619](https://github.com/gazebosim/gz-gui/pull/619)
+
+1. Add package.xml
+ * [Pull request #613](https://github.com/gazebosim/gz-gui/pull/613)
+
+### Gazebo GUI 8.1.1 (2024-04-10)
+
+1. Fix compiler warnings in GCC-13 (Noble)
+ * [Pull request #616](https://github.com/gazebosim/gz-gui/pull/616)
+
+1. Use relative install paths for plugin shared libraries and gz-tools data
+ * [Pull request #614](https://github.com/gazebosim/gz-gui/pull/614)
+
+### Gazebo GUI 8.1.0 (2024-03-14)
+
+1. Update CI badges in README
+ * [Pull request #603](https://github.com/gazebosim/gz-gui/pull/603)
+
+1. Fix plugin filter on Windows
+ * [Pull request #567](https://github.com/gazebosim/gz-gui/pull/567)
+
+1. Tidy namespaces
+ * [Pull request #590](https://github.com/gazebosim/gz-gui/pull/590)
+
+1. Infrastructure
+ * [Pull request #591](https://github.com/gazebosim/gz-gui/pull/591)
+ * [Pull request #597](https://github.com/gazebosim/gz-gui/pull/597)
+ * [Pull request #608](https://github.com/gazebosim/gz-gui/pull/608)
+
+1. Add check for vulkan support in rendering
+ * [Pull request #589](https://github.com/gazebosim/gz-gui/pull/589)
+
+1. Add optional binary relocatability
+ * [Pull request #580](https://github.com/gazebosim/gz-gui/pull/580)
+
### Gazebo GUI 8.0.0 (2023-09-29)
1. Use fully-qualified message names to avoid deprecation warning
diff --git a/conf/CMakeLists.txt b/conf/CMakeLists.txt
index 70201dfd8..4fb0a6a34 100644
--- a/conf/CMakeLists.txt
+++ b/conf/CMakeLists.txt
@@ -20,4 +20,4 @@ configure_file(
# Install the yaml configuration files in an unversioned location.
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GZ_DESIGNATION}${PROJECT_VERSION_MAJOR}.yaml
- DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gz/)
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gz/)
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 0fd15b96c..7a1d464b3 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -25,5 +25,5 @@ if (DOXYGEN_FOUND)
COMMENT "Generating API documentation with Doxygen" VERBATIM)
install(FILES ${CMAKE_BINARY_DIR}/doc/${PROJECT_NAME_LOWER}.tag.xml
- DESTINATION ${CMAKE_INSTALL_PREFIX}/share/gz/${PROJECT_NAME_LOWER}_${PROJECT_VERSION_MINOR})
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gz/${PROJECT_NAME_LOWER}_${PROJECT_VERSION_MINOR})
endif()
diff --git a/examples/standalone/scene_provider/README.md b/examples/standalone/scene_provider/README.md
index 3183a83e4..ce2da00fc 100644
--- a/examples/standalone/scene_provider/README.md
+++ b/examples/standalone/scene_provider/README.md
@@ -9,7 +9,7 @@ plugin to update the scene using Gazebo Transport.
## Build
-```
+```bash
cd examples/standalone/scene_provider
mkdir build
cd build
@@ -21,14 +21,14 @@ make
In one terminal, start the scene provider:
-```
+```bash
cd examples/standalone/scene_provider/build
./scene_provider
```
On another terminal, start the example config:
-```
+```bash
gz gui -c examples/config/scene3d.config
```
@@ -42,24 +42,48 @@ Some commands to test camera tracking with this demo:
Move to box:
-```
+```bash
gz service -s /gui/move_to --reqtype gz.msgs.StringMsg --reptype gz.msgs.Boolean --timeout 2000 --req 'data: "box_model"'
```
Echo camera pose:
-```
+```bash
gz topic -e -t /gui/camera/pose
```
-Follow box:
+Echo camera tracking information:
+```bash
+gz topic -e -t /gui/currently_tracked
```
-gz service -s /gui/follow --reqtype gz.msgs.StringMsg --reptype gz.msgs.Boolean --timeout 2000 --req 'data: "box_model"'
+
+Follow box from track topic:
+
+```bash
+gz topic -t /gui/track -m gz.msgs.CameraTrack -p 'track_mode: 2, follow_target: { name: "box_model"}'
```
-Update follow offset:
+Follow box from track topic:
+```bash
+gz topic -t /gui/track -m gz.msgs.CameraTrack -p 'track_mode: 2, follow_target: "box_model", follow_offset: {x: -1, y: 0, z: 1}'
```
+
+Update follow offset from track topic:
+
+```bash
+gz topic -t /gui/track -m gz.msgs.CameraTrack -p 'track_mode: 2, follow_target: {name: "box_model"}, follow_offset: {x: -1, y: 0, z: 1}'
+```
+
+Follow box from service (deprecated):
+
+```bash
+gz service -s /gui/follow --reqtype gz.msgs.StringMsg --reptype gz.msgs.Boolean --timeout 2000 --req 'data: "box_model"'
+```
+
+Update follow offset from follow offset service (deprecated):
+
+```bash
gz service -s /gui/follow/offset --reqtype gz.msgs.Vector3d --reptype gz.msgs.Boolean --timeout 2000 --req 'x: 5, y: 5, z: 5'
```
diff --git a/include/gz/gui/CMakeLists.txt b/include/gz/gui/CMakeLists.txt
index 5e15317d6..c2994699e 100644
--- a/include/gz/gui/CMakeLists.txt
+++ b/include/gz/gui/CMakeLists.txt
@@ -58,4 +58,8 @@ target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME}
TINYXML2::TINYXML2
)
+target_compile_definitions(${PROJECT_LIBRARY_TARGET_NAME} PRIVATE
+ SHARED_LIBRARY_PREFIX=\"${CMAKE_SHARED_LIBRARY_PREFIX}\"
+ SHARED_LIBRARY_SUFFIX=\"${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+
gz_install_all_headers()
diff --git a/include/gz/gui/qml/Main.qml b/include/gz/gui/qml/Main.qml
index c18154f29..c7e540200 100644
--- a/include/gz/gui/qml/Main.qml
+++ b/include/gz/gui/qml/Main.qml
@@ -189,8 +189,8 @@ ApplicationWindow
contentItem: Image {
fillMode: Image.Pad
horizontalAlignment: Image.AlignHCenter
- verticalAlignment: Image.AlignVCenter
- source: "images/drawer.png"
+ verticalAlignment: Image.AlignVCenter
+ source: Material.theme === Material.Light ? "images/drawer.png" : "images/drawer_dark.png"
}
onClicked: drawer.open()
}
@@ -221,7 +221,7 @@ ApplicationWindow
fillMode: Image.Pad
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
- source: "images/menu.png"
+ source: Material.theme === Material.Light ? "images/menu.png" : "images/menu_dark.png"
}
onClicked: pluginMenu.open()
diff --git a/include/gz/gui/qml/images/drawer_dark.png b/include/gz/gui/qml/images/drawer_dark.png
new file mode 100644
index 000000000..7e0089474
Binary files /dev/null and b/include/gz/gui/qml/images/drawer_dark.png differ
diff --git a/include/gz/gui/qml/images/menu_dark.png b/include/gz/gui/qml/images/menu_dark.png
new file mode 100644
index 000000000..6f4ad6eb9
Binary files /dev/null and b/include/gz/gui/qml/images/menu_dark.png differ
diff --git a/include/gz/gui/resources.qrc b/include/gz/gui/resources.qrc
index 8a18a99f6..1668662ab 100644
--- a/include/gz/gui/resources.qrc
+++ b/include/gz/gui/resources.qrc
@@ -24,7 +24,9 @@
qml/images/gazebo_logo.png
qml/images/drawer.png
+ qml/images/drawer_dark.png
qml/images/menu.png
+ qml/images/menu_dark.png
qml/images/export_icon.png
qml/images/search.svg
qml/images/plottable_icon.svg
diff --git a/package.xml b/package.xml
new file mode 100644
index 000000000..592144e50
--- /dev/null
+++ b/package.xml
@@ -0,0 +1,53 @@
+
+
+
+ gz-gui9
+ 9.0.0
+ Gazebo GUI : Graphical interfaces for robotics applications
+ Jenn Nguyen
+ Apache License 2.0
+ https://github.com/gazebosim/gz-rendering
+
+ cmake
+
+ gz-cmake3
+
+ gz-common6
+ gz-math8
+ gz-msgs11
+ gz-plugin3
+ gz-rendering9
+ gz-tools2
+ gz-transport14
+ gz-utils3
+ libqt5-core
+ libqt5-qml
+ libqt5-quick
+ libqt5-widgets
+ protobuf-dev
+ qml-module-qt-labs-folderlistmodel
+ qml-module-qt-labs-platform
+ qml-module-qt-labs-settings
+ qml-module-qtcharts
+ qml-module-qtgraphicaleffects
+ qml-module-qtlocation
+ qml-module-qtpositioning
+ qml-module-qtquick-controls2
+ qml-module-qtquick-controls
+ qml-module-qtquick-dialogs
+ qml-module-qtquick-extras
+ qml-module-qtquick-layouts
+ qml-module-qtquick-templates2
+ qml-module-qtquick-window2
+ qml-module-qtquick2
+ qtbase5-dev
+ qtdeclarative5-dev
+ qtquickcontrols2-5-dev
+ tinyxml2
+
+ xvfb
+
+
+ cmake
+
+
diff --git a/src/Application.cc b/src/Application.cc
index 5427a67c3..2a414003e 100644
--- a/src/Application.cc
+++ b/src/Application.cc
@@ -843,10 +843,19 @@ std::vector>>
{
auto plugin = common::basename(*dirIter);
- // All we verify is that the file starts with "lib", any further
- // checks would require loading the plugin.
+ // All we verify is that the file starts with shared library prefix and
+ // ends with shared library suffix, any further checks would require
+ // loading the plugin.
- if (plugin.find("lib") == 0)
+ // TODO(anyone): Move this logic into gz-plugin to be reusable
+
+ // This computation could underflow the unsigned range, but that is okay
+ // as in such case we would check if the suffix is placed somewhere much
+ // further than allowed filename length.
+ const auto suffixPos = plugin.length() - strlen(SHARED_LIBRARY_SUFFIX);
+
+ if (plugin.find(SHARED_LIBRARY_PREFIX) == 0 &&
+ plugin.rfind(SHARED_LIBRARY_SUFFIX) == suffixPos)
ps.push_back(plugin);
}
diff --git a/src/MainWindow.cc b/src/MainWindow.cc
index bff0186a9..0bc9eb101 100644
--- a/src/MainWindow.cc
+++ b/src/MainWindow.cc
@@ -128,8 +128,13 @@ QStringList MainWindow::PluginListModel() const
{
for (auto const &plugin : path.second)
{
- // Remove lib and .so
- auto pluginName = plugin.substr(3, plugin.find(".") - 3);
+ // TODO(anyone): Move this into gz-plugin to be reusable
+
+ // Remove shared library prefix and shared library suffix
+ auto pluginName = plugin.substr(
+ strlen(SHARED_LIBRARY_PREFIX),
+ plugin.length() - strlen(SHARED_LIBRARY_PREFIX) -
+ strlen(SHARED_LIBRARY_SUFFIX));
// Split WWWCamelCase3D -> WWW Camel Case 3D
std::regex reg("(\\B[A-Z][a-z])|(\\B[0-9])");
diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt
index 821cd4acf..568de6289 100644
--- a/src/cmd/CMakeLists.txt
+++ b/src/cmd/CMakeLists.txt
@@ -51,4 +51,4 @@ install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/gui${PROJECT_VERSION_MAJOR}.bash_completion.sh
DESTINATION
- ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gz/gz${GZ_TOOLS_VER}.completion.d)
+ ${CMAKE_INSTALL_DATAROOTDIR}/gz/gz${GZ_TOOLS_VER}.completion.d)
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index f5bcf98f1..362df296a 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -110,12 +110,13 @@ function(gz_gui_add_plugin plugin_name)
COMPILE_FLAGS "/wd4251")
endif()
- install (TARGETS ${plugin_name} DESTINATION ${GZ_GUI_PLUGIN_INSTALL_DIR})
+ install (TARGETS ${plugin_name} DESTINATION ${GZ_GUI_PLUGIN_RELATIVE_INSTALL_DIR})
endfunction()
# Plugins
add_subdirectory(camera_fps)
add_subdirectory(camera_tracking)
+add_subdirectory(camera_tracking_config)
add_subdirectory(grid_config)
add_subdirectory(image_display)
add_subdirectory(interactive_view_control)
diff --git a/src/plugins/camera_tracking/CameraTracking.cc b/src/plugins/camera_tracking/CameraTracking.cc
index cda9a446a..2001ca411 100644
--- a/src/plugins/camera_tracking/CameraTracking.cc
+++ b/src/plugins/camera_tracking/CameraTracking.cc
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Open Source Robotics Foundation
+ * Copyright (C) 2024 Rudis Laboratories LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,9 +18,13 @@
#include
#include
+#include
#include
+#include
#include
+#include
+#include
#include
#include
#include
@@ -60,6 +65,10 @@ class CameraTracking::Implementation
public: bool OnMoveTo(const msgs::StringMsg &_msg,
msgs::Boolean &_res);
+ /// \brief Callback for a track message
+ /// \param[in] _msg Message is of type CameraTrack.
+ public: void OnTrackSub(const msgs::CameraTrack &_msg);
+
/// \brief Callback for a follow request
/// \param[in] _msg Request message to set the target to follow.
/// \param[in] _res Response data
@@ -97,27 +106,42 @@ class CameraTracking::Implementation
//// \brief Pointer to the rendering scene
public: rendering::ScenePtr scene = nullptr;
+ /// \brief Target to track
+ public: std::string selectedTrackTarget;
+
/// \brief Target to follow
- public: std::string followTarget;
+ public: std::string selectedFollowTarget;
- /// \brief Wait for follow target
- public: bool followTargetWait = false;
+ /// \brief Wait for target to track
+ public: bool selectedTargetWait = false;
/// \brief Offset of camera from target being followed
- public: math::Vector3d followOffset = math::Vector3d(-5, 0, 3);
+ public: math::Vector3d followOffset = math::Vector3d(-3, 0, 2);
+
+ /// \brief Offset on target to be tracked
+ public: math::Vector3d trackOffset = math::Vector3d(0, 0, 0);
- /// \brief Flag to indicate the follow offset needs to be updated
- public: bool followOffsetDirty = false;
+ /// \brief Camera tracking message
+ public: gz::msgs::CameraTrack trackMsg;
- /// \brief Flag to indicate the follow offset has been updated
- public: bool newFollowOffset = true;
+ /// \brief Flag to indicate new tracking
+ public: bool newTrack = true;
+
+ /// \brief Track P gain
+ public: double trackPGain = 0.01;
/// \brief Follow P gain
public: double followPGain = 0.01;
- /// \brief True follow the target at an offset that is in world frame,
- /// false to follow in target's local frame
- public: bool followWorldFrame = false;
+ /// \brief Free Look P gain
+ public: double freeLookPGain = 1.0;
+
+ /// \brief Default track mode to None
+ public: int trackMode = gz::msgs::CameraTrack::NONE;
+
+ /// \brief True track the target at an offset that is in world frame,
+ /// false to track in target's local frame
+ public: bool trackWorldFrame = false;
/// \brief Last move to animation time
public: std::chrono::time_point prevMoveToTime;
@@ -137,17 +161,23 @@ class CameraTracking::Implementation
/// \brief Move to service
public: std::string moveToService;
+ /// \brief Follow service (deprecated)
+ public: std::string followService;
+
+ /// \brief Follow offset service (deprecated)
+ public: std::string followOffsetService;
+
/// \brief The pose set from the move to pose service.
public: std::optional moveToPoseValue;
/// \brief The motion duration set from the move to pose service.
public: std::optional moveToPoseDuration;
- /// \brief Follow service
- public: std::string followService;
+ /// \brief Track topic
+ public: std::string trackTopic;
- /// \brief Follow offset service
- public: std::string followOffsetService;
+ /// \brief Track status topic
+ public: std::string trackStatusTopic;
/// \brief Camera pose topic
public: std::string cameraPoseTopic;
@@ -155,6 +185,9 @@ class CameraTracking::Implementation
/// \brief Move to pose service
public: std::string moveToPoseService;
+ /// \brief Camera pose publisher
+ public: transport::Node::Publisher trackStatusPub;
+
/// \brief Camera pose publisher
public: transport::Node::Publisher cameraPosePub;
@@ -196,7 +229,21 @@ void CameraTracking::Implementation::Initialize()
this->node.Advertise(this->followService,
&Implementation::OnFollow, this);
gzmsg << "Follow service on ["
- << this->followService << "]" << std::endl;
+ << this->followService << "] (deprecated)" << std::endl;
+
+ // track
+ this->trackTopic = "/gui/track";
+ this->node.Subscribe(this->trackTopic,
+ &Implementation::OnTrackSub, this);
+ gzmsg << "Tracking topic on ["
+ << this->trackTopic << "]" << std::endl;
+
+ // tracking status
+ this->trackStatusTopic = "/gui/currently_tracked";
+ this->trackStatusPub =
+ this->node.Advertise(this->trackStatusTopic);
+ gzmsg << "Tracking status topic on ["
+ << this->trackStatusTopic << "]" << std::endl;
// move to pose service
this->moveToPoseService =
@@ -218,7 +265,7 @@ void CameraTracking::Implementation::Initialize()
this->node.Advertise(this->followOffsetService,
&Implementation::OnFollowOffset, this);
gzmsg << "Follow offset service on ["
- << this->followOffsetService << "]" << std::endl;
+ << this->followOffsetService << "] (deprecated)" << std::endl;
}
/////////////////////////////////////////////////
@@ -237,12 +284,60 @@ bool CameraTracking::Implementation::OnFollow(const msgs::StringMsg &_msg,
msgs::Boolean &_res)
{
std::lock_guard lock(this->mutex);
- this->followTarget = _msg.data();
+ this->selectedFollowTarget = _msg.data();
_res.set_data(true);
+
+ this->trackMode = gz::msgs::CameraTrack::FOLLOW;
+
+ this->newTrack = true;
return true;
}
+/////////////////////////////////////////////////
+void CameraTracking::Implementation::OnTrackSub(const msgs::CameraTrack &_msg)
+{
+ std::lock_guard lock(this->mutex);
+ gzmsg << "Got new track message." << std::endl;
+
+ if (_msg.track_mode() != gz::msgs::CameraTrack::USE_LAST)
+ {
+ this->trackMode = _msg.track_mode();
+ }
+ if (!_msg.follow_target().name().empty())
+ {
+ this->selectedFollowTarget = _msg.follow_target().name();
+ }
+ if (!_msg.track_target().name().empty())
+ {
+ this->selectedTrackTarget = _msg.track_target().name();
+ }
+ if (_msg.follow_target().name().empty() && _msg.track_target().name().empty()
+ && _msg.track_mode() != gz::msgs::CameraTrack::USE_LAST)
+ {
+ gzmsg << "Track and Follow target names empty."<< std::endl;
+ }
+ if (_msg.has_follow_offset())
+ {
+ this->followOffset = msgs::Convert(_msg.follow_offset());
+ }
+ if (_msg.has_track_offset())
+ {
+ this->trackOffset = msgs::Convert(_msg.track_offset());
+ }
+ if (_msg.track_pgain() > 0.00001)
+ {
+ this->trackPGain = _msg.track_pgain();
+ }
+ if (_msg.follow_pgain() > 0.00001)
+ {
+ this->followPGain = _msg.follow_pgain();
+ }
+
+ this->newTrack = true;
+ return;
+}
+
/////////////////////////////////////////////////
void CameraTracking::Implementation::OnMoveToComplete()
{
@@ -261,9 +356,9 @@ bool CameraTracking::Implementation::OnFollowOffset(const msgs::Vector3d &_msg,
msgs::Boolean &_res)
{
std::lock_guard lock(this->mutex);
- if (!this->followTarget.empty())
+ if (!this->selectedFollowTarget.empty())
{
- this->newFollowOffset = true;
+ this->newTrack = true;
this->followOffset = msgs::Convert(_msg);
}
@@ -379,66 +474,114 @@ void CameraTracking::Implementation::OnRender()
}
}
- // Follow
+ // Track
{
- GZ_PROFILE("CameraTracking::Implementation::OnRender Follow");
- // reset follow mode if target node got removed
- if (!this->followTarget.empty())
+ GZ_PROFILE("CameraTracking::Implementation::OnRender Track");
+ // reset track mode if target node got removed
+ if (!this->selectedFollowTarget.empty())
{
- rendering::NodePtr target = this->scene->NodeByName(this->followTarget);
- if (!target && !this->followTargetWait)
+ rendering::NodePtr targetFollow = this->scene->NodeByName(
+ this->selectedFollowTarget);
+ if (!targetFollow && !this->selectedTargetWait)
{
this->camera->SetFollowTarget(nullptr);
+ this->selectedFollowTarget.clear();
+ }
+ }
+ if (!this->selectedTrackTarget.empty())
+ {
+ rendering::NodePtr targetTrack = this->scene->NodeByName(
+ this->selectedTrackTarget);
+ if (!targetTrack && !this->selectedTargetWait)
+ {
this->camera->SetTrackTarget(nullptr);
- this->followTarget.clear();
+ this->selectedTrackTarget.clear();
}
}
if (!this->moveToTarget.empty())
return;
- rendering::NodePtr followTargetTmp = this->camera->FollowTarget();
- if (!this->followTarget.empty())
+ rendering::NodePtr selectedFollowTargetTmp = this->camera->FollowTarget();
+ rendering::NodePtr selectedTrackTargetTmp = this->camera->TrackTarget();
+ if (!this->selectedTrackTarget.empty() ||
+ !this->selectedFollowTarget.empty())
{
- rendering::NodePtr target = scene->NodeByName(
- this->followTarget);
- if (target)
+ rendering::NodePtr targetFollow = this->scene->NodeByName(
+ this->selectedFollowTarget);
+ rendering::NodePtr targetTrack = this->scene->NodeByName(
+ this->selectedTrackTarget);
+ if (targetFollow || targetTrack)
{
- if (!followTargetTmp || target != followTargetTmp
- || this->newFollowOffset)
+ if (this->trackMode == gz::msgs::CameraTrack::FOLLOW_FREE_LOOK ||
+ this->trackMode == gz::msgs::CameraTrack::FOLLOW ||
+ this->trackMode == gz::msgs::CameraTrack::FOLLOW_LOOK_AT )
{
- this->camera->SetFollowTarget(target,
- this->followOffset,
- this->followWorldFrame);
- this->camera->SetFollowPGain(this->followPGain);
-
- this->camera->SetTrackTarget(target);
- // found target, no need to wait anymore
- this->newFollowOffset = false;
- this->followTargetWait = false;
+ if (!selectedFollowTargetTmp ||
+ targetFollow != selectedFollowTargetTmp ||
+ this->newTrack)
+ {
+ this->trackWorldFrame = false;
+ this->camera->SetFollowTarget(targetFollow,
+ this->followOffset,
+ this->trackWorldFrame);
+ if (this->trackMode == gz::msgs::CameraTrack::FOLLOW)
+ {
+ this->camera->SetTrackTarget(targetFollow);
+ this->camera->SetTrackPGain(this->followPGain);
+ this->camera->SetFollowPGain(this->trackPGain);
+ }
+ if (this->trackMode == gz::msgs::CameraTrack::FOLLOW_LOOK_AT)
+ {
+ this->camera->SetTrackTarget(targetTrack);
+ this->camera->SetTrackPGain(this->followPGain);
+ this->camera->SetFollowPGain(this->trackPGain);
+ }
+ if (this->trackMode == gz::msgs::CameraTrack::FOLLOW_FREE_LOOK)
+ {
+ this->camera->SetTrackTarget(nullptr);
+ this->camera->SetFollowPGain(this->freeLookPGain);
+ }
+ this->newTrack = false;
+ this->selectedTargetWait = false;
+ }
}
- else if (this->followOffsetDirty)
+ if (this->trackMode == gz::msgs::CameraTrack::TRACK)
{
- math::Vector3d offset =
- this->camera->WorldPosition() - target->WorldPosition();
- if (!this->followWorldFrame)
+ if (!selectedTrackTargetTmp ||
+ targetTrack != selectedTrackTargetTmp ||
+ this->newTrack)
{
- offset = target->WorldRotation().RotateVectorReverse(offset);
+ this->trackWorldFrame = true;
+ this->camera->SetFollowTarget(nullptr);
+ this->camera->SetTrackTarget(targetTrack,
+ this->trackOffset,
+ this->trackWorldFrame);
+ this->camera->SetTrackPGain(this->trackPGain);
+ this->newTrack = false;
+ this->selectedTargetWait = false;
}
- this->camera->SetFollowOffset(offset);
- this->followOffsetDirty = false;
}
}
- else if (!this->followTargetWait)
+ else if (!this->selectedTargetWait)
{
+ gzerr << "Unable to track target. Target: '"
+ << this->selectedTrackTarget << "' not found" << std::endl;
gzerr << "Unable to follow target. Target: '"
- << this->followTarget << "' not found" << std::endl;
- this->followTarget.clear();
+ << this->selectedFollowTarget << "' not found" << std::endl;
+ this->selectedFollowTarget.clear();
+ this->selectedTrackTarget.clear();
}
}
- else if (followTargetTmp)
+ else
{
- this->camera->SetFollowTarget(nullptr);
- this->camera->SetTrackTarget(nullptr);
+ if (selectedFollowTargetTmp)
+ {
+ this->camera->SetFollowTarget(nullptr);
+ }
+ if (selectedTrackTargetTmp)
+ {
+ this->camera->SetTrackTarget(nullptr);
+ }
}
}
}
@@ -458,6 +601,96 @@ CameraTracking::CameraTracking()
auto poseMsg = msgs::Convert(this->dataPtr->camera->WorldPose());
this->dataPtr->cameraPosePub.Publish(poseMsg);
}
+ if (this->dataPtr->trackStatusPub.HasConnections())
+ {
+ if (this->dataPtr->trackMode == gz::msgs::CameraTrack::TRACK)
+ {
+ this->dataPtr->trackMsg.set_track_mode(gz::msgs::CameraTrack::TRACK);
+ this->dataPtr->trackMsg.mutable_track_target()->set_name(
+ this->dataPtr->selectedTrackTarget);
+ this->dataPtr->trackMsg.mutable_track_offset()->set_x(
+ this->dataPtr->trackOffset.X());
+ this->dataPtr->trackMsg.mutable_track_offset()->set_y(
+ this->dataPtr->trackOffset.Y());
+ this->dataPtr->trackMsg.mutable_track_offset()->set_z(
+ this->dataPtr->trackOffset.Z());
+ this->dataPtr->trackMsg.set_track_pgain(
+ this->dataPtr->trackPGain);
+ this->dataPtr->trackMsg.clear_follow_target();
+ this->dataPtr->trackMsg.clear_follow_offset();
+ this->dataPtr->trackMsg.clear_follow_pgain();
+ }
+ else if (this->dataPtr->trackMode == gz::msgs::CameraTrack::FOLLOW)
+ {
+ this->dataPtr->trackMsg.set_track_mode(gz::msgs::CameraTrack::FOLLOW);
+ this->dataPtr->trackMsg.mutable_follow_target()->set_name(
+ this->dataPtr->selectedFollowTarget);
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_x(
+ this->dataPtr->followOffset.X());
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_y(
+ this->dataPtr->followOffset.Y());
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_z(
+ this->dataPtr->followOffset.Z());
+ this->dataPtr->trackMsg.set_follow_pgain(this->dataPtr->followPGain);
+ this->dataPtr->trackMsg.clear_track_target();
+ this->dataPtr->trackMsg.clear_track_offset();
+ this->dataPtr->trackMsg.clear_track_pgain();
+ }
+ else if (this->dataPtr->trackMode ==
+ gz::msgs::CameraTrack::FOLLOW_FREE_LOOK)
+ {
+ this->dataPtr->trackMsg.set_track_mode(
+ gz::msgs::CameraTrack::FOLLOW_FREE_LOOK);
+ this->dataPtr->trackMsg.mutable_follow_target()->set_name(
+ this->dataPtr->selectedFollowTarget);
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_x(
+ this->dataPtr->followOffset.X());
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_y(
+ this->dataPtr->followOffset.Y());
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_z(
+ this->dataPtr->followOffset.Z());
+ this->dataPtr->trackMsg.set_follow_pgain(this->dataPtr->followPGain);
+ this->dataPtr->trackMsg.clear_track_target();
+ this->dataPtr->trackMsg.clear_track_offset();
+ this->dataPtr->trackMsg.clear_track_pgain();
+ }
+ else if (this->dataPtr->trackMode ==
+ gz::msgs::CameraTrack::FOLLOW_LOOK_AT)
+ {
+ this->dataPtr->trackMsg.set_track_mode(
+ gz::msgs::CameraTrack::FOLLOW_LOOK_AT);
+ this->dataPtr->trackMsg.mutable_follow_target()->set_name(
+ this->dataPtr->selectedFollowTarget);
+ this->dataPtr->trackMsg.mutable_track_target()->set_name(
+ this->dataPtr->selectedTrackTarget);
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_x(
+ this->dataPtr->followOffset.X());
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_y(
+ this->dataPtr->followOffset.Y());
+ this->dataPtr->trackMsg.mutable_follow_offset()->set_z(
+ this->dataPtr->followOffset.Z());
+ this->dataPtr->trackMsg.mutable_track_offset()->set_x(
+ this->dataPtr->trackOffset.X());
+ this->dataPtr->trackMsg.mutable_track_offset()->set_y(
+ this->dataPtr->trackOffset.Y());
+ this->dataPtr->trackMsg.mutable_track_offset()->set_z(
+ this->dataPtr->trackOffset.Z());
+ this->dataPtr->trackMsg.set_follow_pgain(this->dataPtr->followPGain);
+ this->dataPtr->trackMsg.set_track_pgain(this->dataPtr->trackPGain);
+ }
+ else
+ {
+ this->dataPtr->trackMsg.set_track_mode(gz::msgs::CameraTrack::NONE);
+ this->dataPtr->trackMsg.clear_track_target();
+ this->dataPtr->trackMsg.clear_track_offset();
+ this->dataPtr->trackMsg.clear_track_pgain();
+ this->dataPtr->trackMsg.clear_follow_target();
+ this->dataPtr->trackMsg.clear_follow_offset();
+ this->dataPtr->trackMsg.clear_follow_pgain();
+ }
+
+ this->dataPtr->trackStatusPub.Publish(this->dataPtr->trackMsg);
+ }
});
this->dataPtr->timer->setInterval(1000.0 / 50.0);
this->dataPtr->timer->start();
@@ -467,11 +700,39 @@ CameraTracking::CameraTracking()
CameraTracking::~CameraTracking() = default;
/////////////////////////////////////////////////
-void CameraTracking::LoadConfig(const tinyxml2::XMLElement *)
+void CameraTracking::LoadConfig(const tinyxml2::XMLElement *_pluginElem)
{
if (this->title.empty())
this->title = "Camera tracking";
+ if (_pluginElem)
+ {
+ if (auto followTargetElem = _pluginElem->FirstChildElement("follow_target"))
+ {
+ this->dataPtr->selectedFollowTarget = followTargetElem->GetText();
+ gzmsg << "CameraTracking: Loaded follow target from sdf ["
+ << this->dataPtr->selectedFollowTarget << "]" << std::endl;
+ this->dataPtr->selectedTargetWait = true;
+ }
+ if (auto followOffsetElem = _pluginElem->FirstChildElement("follow_offset"))
+ {
+ std::stringstream followOffsetStr;
+ followOffsetStr << std::string(followOffsetElem->GetText());
+ followOffsetStr >> this->dataPtr->followOffset;
+ gzmsg << "CameraTracking: Loaded offset from sdf ["
+ << this->dataPtr->followOffset << "]" << std::endl;
+ this->dataPtr->newTrack = true;
+ }
+ if (auto followPGainElem = _pluginElem->FirstChildElement("follow_pgain"))
+ {
+ this->dataPtr->followPGain = std::stod(
+ std::string(followPGainElem->GetText()));
+ gzmsg << "CameraTracking: Loaded follow pgain from sdf ["
+ << this->dataPtr->followPGain << "]" << std::endl;
+ this->dataPtr->newTrack = true;
+ }
+ }
+
App()->findChild()->installEventFilter(this);
}
@@ -481,9 +742,12 @@ void CameraTracking::Implementation::HandleKeyRelease(
{
if (_e->Key().Key() == Qt::Key_Escape)
{
- if (!this->followTarget.empty())
+ this->trackMode = gz::msgs::CameraTrack::NONE;
+ if (!this->selectedFollowTarget.empty() ||
+ !this->selectedTrackTarget.empty())
{
- this->followTarget = std::string();
+ this->selectedFollowTarget = std::string();
+ this->selectedTrackTarget = std::string();
_e->accept();
}
diff --git a/src/plugins/camera_tracking/CameraTracking.hh b/src/plugins/camera_tracking/CameraTracking.hh
index df4601001..2ce6ef92c 100644
--- a/src/plugins/camera_tracking/CameraTracking.hh
+++ b/src/plugins/camera_tracking/CameraTracking.hh
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Open Source Robotics Foundation
+ * Copyright (C) 2024 Rudis Laboratories LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,12 +30,14 @@ namespace gz::gui::plugins
/// and "follow".
///
/// Services:
+ /// * `/gui/follow`: Set the user camera to follow a given target,
+ /// identified by name (deprecated).
+ /// * `/gui/follow/offset`: Set the offset for following (deprecated).
/// * `/gui/move_to`: Move the user camera to look at a given target,
/// identified by name.
/// * `/gui/move_to/pose`: Move the user camera to a given pose.
- /// * `/gui/follow`: Set the user camera to follow a given target,
- /// identified by name.
- /// * `/gui/follow/offset`: Set the offset for following.
+ /// * `/gui/track`: Set the user camera to follow a given target,
+ /// identified by name, offset, pgain, track type.
///
/// Topics:
/// * `/gui/camera/pose`: Publishes the current user camera pose.
diff --git a/src/plugins/camera_tracking/CameraTracking.qml b/src/plugins/camera_tracking/CameraTracking.qml
index 09c339f0b..a8c82d45e 100644
--- a/src/plugins/camera_tracking/CameraTracking.qml
+++ b/src/plugins/camera_tracking/CameraTracking.qml
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Open Source Robotics Foundation
+ * Copyright (C) 2024 Rudis Laboratories LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,11 +27,12 @@ ColumnLayout {
anchors.margins: 10
property string message: 'Services provided:
' +
+ '- /gui/follow/pose
' +
'- /gui/move_to
' +
'- /gui/move_to/pose
' +
- '- /gui/follow
' +
- '- /gui/follow/offset
Topics provided:
'
+ '/gui/track
Topics provided:
' +
+ '- /gui/camera/pose
'+
+ '- /gui/currently_tracked
'
Label {
Layout.fillWidth: true
diff --git a/src/plugins/camera_tracking_config/CMakeLists.txt b/src/plugins/camera_tracking_config/CMakeLists.txt
new file mode 100644
index 000000000..b6877357c
--- /dev/null
+++ b/src/plugins/camera_tracking_config/CMakeLists.txt
@@ -0,0 +1,6 @@
+gz_gui_add_plugin(CameraTrackingConfig
+ SOURCES
+ CameraTrackingConfig.cc
+ QT_HEADERS
+ CameraTrackingConfig.hh
+)
diff --git a/src/plugins/camera_tracking_config/CameraTrackingConfig.cc b/src/plugins/camera_tracking_config/CameraTrackingConfig.cc
new file mode 100644
index 000000000..c61f8ac44
--- /dev/null
+++ b/src/plugins/camera_tracking_config/CameraTrackingConfig.cc
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2024 CogniPilot Foundation
+ * Copyright (C) 2024 Rudis Laboratories LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "gz/gui/Application.hh"
+#include "gz/gui/Conversions.hh"
+#include "gz/gui/GuiEvents.hh"
+#include "gz/gui/MainWindow.hh"
+
+#include
+
+#include "CameraTrackingConfig.hh"
+
+/// \brief Private data class for CameraTrackingConfig
+class gz::gui::plugins::CameraTrackingConfigPrivate
+{
+
+ /// \brief Topic for track message
+ public: std::string cameraTrackingTopic;
+
+ /// \brief tracking offset
+ public: math::Vector3d trackOffset{math::Vector3d(0.0, 0.0, 0.0)};
+
+ /// \brief track P gain
+ public: double trackPGain{0.01};
+
+ /// \brief Offset of camera from target being followed
+ public: math::Vector3d followOffset{math::Vector3d(-3.0, 0.0, -2.0)};
+
+ /// \brief Follow P gain
+ public: double followPGain{0.01};
+
+ public: transport::Node node;
+
+ /// \brief Process updated track
+ public: void UpdateTracking();
+
+ /// \brief flag for updating
+ public: bool newTrackingUpdate = false;
+
+ /// \brief track publisher
+ public: transport::Node::Publisher trackingPub;
+};
+
+using namespace gz;
+using namespace gui;
+using namespace plugins;
+
+/////////////////////////////////////////////////
+CameraTrackingConfig::CameraTrackingConfig()
+ : gz::gui::Plugin(), dataPtr(std::make_unique())
+{
+}
+
+/////////////////////////////////////////////////
+CameraTrackingConfig::~CameraTrackingConfig() = default;
+
+/////////////////////////////////////////////////
+void CameraTrackingConfig::LoadConfig(const tinyxml2::XMLElement *)
+{
+ if (this->title.empty())
+ this->title = "Camera Tracking Config";
+
+ // Track target pose service
+ this->dataPtr->cameraTrackingTopic = "/gui/track";
+ this->dataPtr->trackingPub =
+ this->dataPtr->node.Advertise(
+ this->dataPtr->cameraTrackingTopic);
+ gzmsg << "CameraTrackingConfig: Tracking topic publisher advertised on ["
+ << this->dataPtr->cameraTrackingTopic << "]" << std::endl;
+
+ gui::App()->findChild<
+ MainWindow *>()->installEventFilter(this);
+}
+
+/////////////////////////////////////////////////
+bool CameraTrackingConfig::eventFilter(QObject *_obj, QEvent *_event)
+{
+ if (_event->type() == events::Render::kType)
+ {
+ if (this->dataPtr->newTrackingUpdate)
+ {
+ this->dataPtr->UpdateTracking();
+ }
+ }
+
+ // Standard event processing
+ return QObject::eventFilter(_obj, _event);
+}
+
+/////////////////////////////////////////////////
+void CameraTrackingConfig::SetTracking(
+ double _tx, double _ty, double _tz, double _tp,
+ double _fx, double _fy, double _fz, double _fp)
+{
+ if (!this->dataPtr->newTrackingUpdate)
+ {
+ this->dataPtr->trackOffset = math::Vector3d(
+ _tx, _ty, _tz);
+ this->dataPtr->followOffset = math::Vector3d(
+ _fx, _fy, _fz);
+ this->dataPtr->trackPGain = _tp;
+ this->dataPtr->followPGain = _fp;
+ gzmsg << "CameraTrackingConfig: Track: Offset("
+ << this->dataPtr->trackOffset << "), PGain("
+ << this->dataPtr->trackPGain << ")" << std::endl;
+ gzmsg << "CameraTrackingConfig: Follow: Offset("
+ << this->dataPtr->followOffset << "), PGain("
+ << this->dataPtr->followPGain << ")" << std::endl;
+ this->dataPtr->newTrackingUpdate = true;
+ }
+}
+
+/////////////////////////////////////////////////
+void CameraTrackingConfigPrivate::UpdateTracking()
+{
+ // Track
+ msgs::CameraTrack trackingMsg;
+ trackingMsg.set_track_mode(msgs::CameraTrack::USE_LAST);
+ trackingMsg.mutable_track_offset()->set_x(this->trackOffset.X());
+ trackingMsg.mutable_track_offset()->set_y(this->trackOffset.Y());
+ trackingMsg.mutable_track_offset()->set_z(this->trackOffset.Z());
+ trackingMsg.mutable_follow_offset()->set_x(this->followOffset.X());
+ trackingMsg.mutable_follow_offset()->set_y(this->followOffset.Y());
+ trackingMsg.mutable_follow_offset()->set_z(this->followOffset.Z());
+ trackingMsg.set_follow_pgain(this->followPGain);
+ trackingMsg.set_track_pgain(this->trackPGain);
+
+ this->trackingPub.Publish(trackingMsg);
+ gzmsg << "CameraTrackingConfig: Publishing message." << std::endl;
+ this->newTrackingUpdate = false;
+}
+
+// Register this plugin
+GZ_ADD_PLUGIN(CameraTrackingConfig,
+ gui::Plugin)
diff --git a/src/plugins/camera_tracking_config/CameraTrackingConfig.hh b/src/plugins/camera_tracking_config/CameraTrackingConfig.hh
new file mode 100644
index 000000000..dca58a52e
--- /dev/null
+++ b/src/plugins/camera_tracking_config/CameraTrackingConfig.hh
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 CogniPilot Foundation
+ * Copyright (C) 2024 Rudis Laboratories LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+#ifndef GZ_GUI_PLUGINS_CAMERATRACKINGCONFIG_HH_
+#define GZ_GUI_PLUGINS_CAMERATRACKINGCONFIG_HH_
+
+#include
+#include
+#include
+
+#include "gz/gui/Plugin.hh"
+
+namespace gz
+{
+namespace gui
+{
+namespace plugins
+{
+ class CameraTrackingConfigPrivate;
+
+ class CameraTrackingConfig : public Plugin
+ {
+ Q_OBJECT
+
+ /// \brief Constructor
+ public: CameraTrackingConfig();
+
+ /// \brief Destructor
+ public: virtual ~CameraTrackingConfig();
+
+ // Documentation inherited
+ public: virtual void LoadConfig(const tinyxml2::XMLElement *)
+ override;
+
+ /// \brief Set the tracking camera, requested from the GUI.
+ /// \param[in] _tx The track offset in x
+ /// \param[in] _ty The track offset in y
+ /// \param[in] _tz The track offset in z
+ /// \param[in] _tp The track camera P gain
+ /// \param[in] _fx The follow offset in x
+ /// \param[in] _fy The follow offset in y
+ /// \param[in] _fz The follow offset in z
+ /// \param[in] _fp The follow camera P gain
+ public slots: void SetTracking(
+ double _tx, double _ty, double _tz, double _tp,
+ double _fx, double _fy, double _fz, double _fp);
+
+ // Documentation inherited
+ private: bool eventFilter(QObject *_obj, QEvent *_event) override;
+
+ /// \internal
+ /// \brief Pointer to private data.
+ private: std::unique_ptr dataPtr;
+ };
+}
+}
+}
+#endif
diff --git a/src/plugins/camera_tracking_config/CameraTrackingConfig.qml b/src/plugins/camera_tracking_config/CameraTrackingConfig.qml
new file mode 100644
index 000000000..91c5e144a
--- /dev/null
+++ b/src/plugins/camera_tracking_config/CameraTrackingConfig.qml
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2024 CogniPilot Foundation
+ * Copyright (C) 2024 Rudis Laboratories LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+import QtQuick 2.9
+import QtQuick.Controls 2.2
+import QtQuick.Controls.Material 2.1
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.3
+import gz.gui 1.0
+
+ColumnLayout {
+ Layout.minimumWidth: 200
+ Layout.minimumHeight: 200
+ Layout.margins: 2
+ anchors.fill: parent
+ focus: true
+
+ // X track camera pose
+ property double xTrackPose: 0.0
+ // Y track camera pose
+ property double yTrackPose: 0.0
+ // Z track camera pose
+ property double zTrackPose: 0.0
+ // P Gain track camera pose
+ property double pGainTrack: 0.01
+ // X camera follow distance
+ property double xFollowOffset: -3.0
+ // Y camera follow distance
+ property double yFollowOffset: 0.0
+ // Z camera follow distance
+ property double zFollowOffset: 2.0
+ // P Gain camera follow distance
+ property double pGainFollow: 0.01
+
+ GridLayout {
+ Layout.fillWidth: true
+ Layout.margins: 2
+ columns: 2
+
+ // X Track Offset
+ Label {
+ id: xTrackPoseLabel
+ text: "Track Offset X (m)"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: xTrackPoseField
+ Layout.fillWidth: true
+ value: xTrackPose
+ maximumValue: 1000.0
+ minimumValue: -1000.0
+ decimals: 2
+ stepSize: 0.5
+ onEditingFinished:{
+ xTrackPose = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset, pGainFollow)
+ }
+ }
+ // Y Track Offset
+ Label {
+ id: yTrackPoseLabel
+ text: "Track Offset Y (m)"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: yTrackPoseField
+ Layout.fillWidth: true
+ value: yTrackPose
+ maximumValue: 1000.0
+ minimumValue: -1000.0
+ decimals: 2
+ stepSize: 0.5
+ onEditingFinished:{
+ yTrackPose = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset, pGainFollow)
+ }
+ }
+ // Z Track Offset
+ Label {
+ id: zTrackPoseLabel
+ text: "Track Offset Z (m)"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: zTrackPoseField
+ Layout.fillWidth: true
+ value: zTrackPose
+ maximumValue: 1000.0
+ minimumValue: -1000.0
+ decimals: 2
+ stepSize: 0.5
+ onEditingFinished:{
+ zTrackPose = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset, pGainFollow)
+ }
+ }
+ // P Gain track
+ Label {
+ id: pGainTrackLabel
+ text: "Track P Gain"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: pGainTrackField
+ Layout.fillWidth: true
+ value: pGainTrack
+ maximumValue: 1.0
+ minimumValue: 0.001
+ decimals: 3
+ stepSize: 0.01
+ onEditingFinished:{
+ pGainTrack = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset, pGainFollow)
+ }
+ }
+ // X Follow Offset
+ Label {
+ id: xFollowOffsetLabel
+ text: "Follow Offset X (m)"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: xFollowOffsetField
+ Layout.fillWidth: true
+ value: xFollowOffset
+ maximumValue: 100.0
+ minimumValue: -100.0
+ decimals: 2
+ stepSize: 0.5
+ onEditingFinished:{
+ xFollowOffset = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset,pGainFollow)
+ }
+ }
+ // Y Follow Offset
+ Label {
+ id: yFollowOffsetLabel
+ text: "Follow Offset Y (m)"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: yFollowOffsetField
+ Layout.fillWidth: true
+ value: yFollowOffset
+ maximumValue: 100.0
+ minimumValue: -100.0
+ decimals: 2
+ stepSize: 0.5
+ onEditingFinished:{
+ yFollowOffset = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset,pGainFollow)
+ }
+ }
+ // Z Follow Offset
+ Label {
+ id: zFollowOffsetLabel
+ text: "Follow Offset Z (m)"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: zFollowOffsetField
+ Layout.fillWidth: true
+ value: zFollowOffset
+ maximumValue: 100.0
+ minimumValue: -100.0
+ decimals: 2
+ stepSize: 0.5
+ onEditingFinished:{
+ zFollowOffset = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset,pGainFollow)
+ }
+ }
+ // P Gain follow
+ Label {
+ id: pGainFollowLabel
+ text: "Follow Offset P Gain"
+ color: "dimgrey"
+ }
+ GzSpinBox {
+ id: pGainFollowField
+ Layout.fillWidth: true
+ value: pGainFollow
+ maximumValue: 1.0
+ minimumValue: 0.001
+ decimals: 3
+ stepSize: 0.01
+ onEditingFinished:{
+ pGainFollow = value
+ CameraTrackingConfig.SetTracking(xTrackPose, yTrackPose, zTrackPose, pGainTrack, xFollowOffset, yFollowOffset, zFollowOffset,pGainFollow)
+ }
+ }
+ }
+}
diff --git a/src/plugins/camera_tracking_config/CameraTrackingConfig.qrc b/src/plugins/camera_tracking_config/CameraTrackingConfig.qrc
new file mode 100644
index 000000000..5b9e0d08d
--- /dev/null
+++ b/src/plugins/camera_tracking_config/CameraTrackingConfig.qrc
@@ -0,0 +1,5 @@
+
+
+ CameraTrackingConfig.qml
+
+
diff --git a/src/plugins/grid_config/CMakeLists.txt b/src/plugins/grid_config/CMakeLists.txt
index 101e6edee..5c2a3cb65 100644
--- a/src/plugins/grid_config/CMakeLists.txt
+++ b/src/plugins/grid_config/CMakeLists.txt
@@ -11,4 +11,4 @@ gz_gui_add_plugin(GridConfig
install (
FILES $
RENAME ${CMAKE_SHARED_LIBRARY_PREFIX}Grid3D${CMAKE_SHARED_LIBRARY_SUFFIX}
- DESTINATION ${GZ_GUI_PLUGIN_INSTALL_DIR})
+ DESTINATION ${GZ_GUI_PLUGIN_RELATIVE_INSTALL_DIR})
diff --git a/src/plugins/image_display/ImageDisplay.cc b/src/plugins/image_display/ImageDisplay.cc
index d0a090d49..404c48a7b 100644
--- a/src/plugins/image_display/ImageDisplay.cc
+++ b/src/plugins/image_display/ImageDisplay.cc
@@ -121,7 +121,8 @@ void ImageDisplay::ProcessImage()
case msgs::PixelFormatType::RGB_INT8:
// copy image data buffer directly to QImage
image = QImage(reinterpret_cast(
- this->dataPtr->imageMsg.data().c_str()), width, height, qFormat);
+ this->dataPtr->imageMsg.data().c_str()), width, height,
+ 3 * width, qFormat);
break;
// for other cases, convert to RGB common::Image
case msgs::PixelFormatType::R_FLOAT32:
diff --git a/src/plugins/minimal_scene/EngineToQtInterface.cc b/src/plugins/minimal_scene/EngineToQtInterface.cc
index 8e82576ff..380f881f4 100644
--- a/src/plugins/minimal_scene/EngineToQtInterface.cc
+++ b/src/plugins/minimal_scene/EngineToQtInterface.cc
@@ -136,7 +136,13 @@ GLuint EngineToQtInterface::TextureId(gz::rendering::CameraPtr &_camera)
{
if (!this->NeedsFallback(_camera))
{
- return _camera->RenderTextureGLId();
+ auto textureId = _camera->RenderTextureGLId();
+
+ QOpenGLFunctions *glFuncs = this->dataPtr->glContext->functions();
+ glFuncs->glBindTexture(GL_TEXTURE_2D, textureId);
+ glFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT,
+ GL_SKIP_DECODE_EXT);
+ return textureId;
}
else
{
diff --git a/src/plugins/minimal_scene/MinimalScene.cc b/src/plugins/minimal_scene/MinimalScene.cc
index 2405b56d2..720854306 100644
--- a/src/plugins/minimal_scene/MinimalScene.cc
+++ b/src/plugins/minimal_scene/MinimalScene.cc
@@ -1514,12 +1514,6 @@ void MinimalScene::LoadConfig(const tinyxml2::XMLElement *_pluginElem)
}
renderWindow->SetEngineName(cmdRenderEngine);
- // there is a problem with displaying ogre2 render textures that are in
- // sRGB format. Workaround for now is to apply gamma correction
- // manually.
- // There maybe a better way to solve the problem by making OpenGL calls.
- if (cmdRenderEngine == std::string("ogre2"))
- this->PluginItem()->setProperty("gammaCorrect", true);
}
/////////////////////////////////////////////////
diff --git a/src/plugins/minimal_scene/MinimalScene.qml b/src/plugins/minimal_scene/MinimalScene.qml
index 5969a31c6..62919ec79 100644
--- a/src/plugins/minimal_scene/MinimalScene.qml
+++ b/src/plugins/minimal_scene/MinimalScene.qml
@@ -25,11 +25,6 @@ Rectangle {
Layout.minimumHeight: 200
anchors.fill: parent
- /**
- * True to enable gamma correction
- */
- property bool gammaCorrect: false
-
/**
* Get mouse position on 3D widget
*/
@@ -54,16 +49,6 @@ Rectangle {
visible: MinimalScene.loadingError.length == 0
}
- /*
- * Gamma correction for sRGB output. Enabled when engine is set to ogre2
- */
- GammaAdjust {
- anchors.fill: renderWindow
- source: renderWindow
- gamma: 2.4
- enabled: gammaCorrect
- visible: gammaCorrect
- }
onParentChanged: {
if (undefined === parent)