diff --git a/examples/config/scene3d.config b/examples/config/scene3d.config
index 1f6caa286..afb673afc 100644
--- a/examples/config/scene3d.config
+++ b/examples/config/scene3d.config
@@ -32,6 +32,20 @@
/example/delete
/example/scene
+
+
+
+
+
+
+ false
+ 5
+ 5
+ floating
+ false
+
+ /example/stats
+
diff --git a/examples/standalone/marker/CMakeLists.txt b/examples/standalone/marker/CMakeLists.txt
new file mode 100644
index 000000000..c9bd8262f
--- /dev/null
+++ b/examples/standalone/marker/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ find_package(ignition-transport11 QUIET REQUIRED OPTIONAL_COMPONENTS log)
+ set(IGN_TRANSPORT_VER ${ignition-transport11_VERSION_MAJOR})
+
+ find_package(ignition-common4 REQUIRED)
+ set(IGN_COMMON_VER ${ignition-common4_VERSION_MAJOR})
+
+ find_package(ignition-msgs8 REQUIRED)
+ set(IGN_MSGS_VER ${ignition-msgs8_VERSION_MAJOR})
+
+ add_executable(marker marker.cc)
+ target_link_libraries(marker
+ ignition-transport${IGN_TRANSPORT_VER}::core
+ ignition-msgs${IGN_MSGS_VER}
+ ignition-common${IGN_COMMON_VER}::ignition-common${IGN_COMMON_VER}
+ )
+endif()
diff --git a/examples/standalone/marker/README.md b/examples/standalone/marker/README.md
new file mode 100644
index 000000000..a0c5bd565
--- /dev/null
+++ b/examples/standalone/marker/README.md
@@ -0,0 +1,22 @@
+# Ignition Visualization Marker Example
+
+This example demonstrates how to create, modify, and delete visualization
+markers in Ignition GUI.
+
+## Build Instructions
+
+From this directory:
+
+ mkdir build
+ cd build
+ cmake ..
+ make
+
+## Execute Instructions
+
+Launch ign gazebo unpaused then from the build directory above:
+
+ ./marker
+
+The terminal will output messages indicating visualization changes that
+will occur in Ignition GUI's render window.
diff --git a/examples/standalone/marker/marker.cc b/examples/standalone/marker/marker.cc
new file mode 100644
index 000000000..ec57227e8
--- /dev/null
+++ b/examples/standalone/marker/marker.cc
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2019 Open Source Robotics Foundation
+ *
+ * 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
+
+/////////////////////////////////////////////////
+int main(int _argc, char **_argv)
+{
+ ignition::transport::Node node;
+
+ // Create the marker message
+ ignition::msgs::Marker markerMsg;
+ ignition::msgs::Material matMsg;
+ markerMsg.set_ns("default");
+ markerMsg.set_id(0);
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::SPHERE);
+ markerMsg.set_visibility(ignition::msgs::Marker::GUI);
+
+ // Set color to Blue
+ markerMsg.mutable_material()->mutable_ambient()->set_r(0);
+ markerMsg.mutable_material()->mutable_ambient()->set_g(0);
+ markerMsg.mutable_material()->mutable_ambient()->set_b(1);
+ markerMsg.mutable_material()->mutable_ambient()->set_a(1);
+ markerMsg.mutable_material()->mutable_diffuse()->set_r(0);
+ markerMsg.mutable_material()->mutable_diffuse()->set_g(0);
+ markerMsg.mutable_material()->mutable_diffuse()->set_b(1);
+ markerMsg.mutable_material()->mutable_diffuse()->set_a(1);
+ markerMsg.mutable_lifetime()->set_sec(2);
+ markerMsg.mutable_lifetime()->set_nsec(0);
+ ignition::msgs::Set(markerMsg.mutable_scale(),
+ ignition::math::Vector3d(1.0, 1.0, 1.0));
+
+ // The rest of this function adds different shapes and/or modifies shapes.
+ // Read the terminal statements to figure out what each node.Request
+ // call accomplishes.
+ std::cout << "Spawning a blue sphere with lifetime 2s\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d(2, 2, 0, 0, 0, 0));
+ node.Request("/marker", markerMsg);
+ std::cout << "Sleeping for 2 seconds\n";
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+
+ std::cout << "Spawning a black sphere at the origin with no lifetime\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(1);
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d::Zero);
+ markerMsg.mutable_material()->mutable_ambient()->set_b(0);
+ markerMsg.mutable_material()->mutable_diffuse()->set_b(0);
+ markerMsg.mutable_lifetime()->set_sec(0);
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Moving the black sphere to x=0, y=1, z=1\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d(0, 1, 1, 0, 0, 0));
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Shrinking the black sphere\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ ignition::msgs::Set(markerMsg.mutable_scale(),
+ ignition::math::Vector3d(0.2, 0.2, 0.2));
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Changing the black sphere to red\n";
+ markerMsg.mutable_material()->mutable_ambient()->set_r(1);
+ markerMsg.mutable_material()->mutable_ambient()->set_g(0);
+ markerMsg.mutable_material()->mutable_ambient()->set_b(0);
+ markerMsg.mutable_material()->mutable_diffuse()->set_r(1);
+ markerMsg.mutable_material()->mutable_diffuse()->set_g(0);
+ markerMsg.mutable_material()->mutable_diffuse()->set_b(0);
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Adding a green ellipsoid\n";
+ markerMsg.mutable_material()->mutable_ambient()->set_r(0);
+ markerMsg.mutable_material()->mutable_ambient()->set_g(1);
+ markerMsg.mutable_material()->mutable_ambient()->set_b(0);
+ markerMsg.mutable_material()->mutable_diffuse()->set_r(0);
+ markerMsg.mutable_material()->mutable_diffuse()->set_g(1);
+ markerMsg.mutable_material()->mutable_diffuse()->set_b(0);
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(2);
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::SPHERE);
+ ignition::msgs::Set(markerMsg.mutable_scale(),
+ ignition::math::Vector3d(0.5, 1.0, 1.5));
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d(2, 0, .5, 0, 0, 0));
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Changing the green ellipsoid to a cylinder\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_type(ignition::msgs::Marker::CYLINDER);
+ ignition::msgs::Set(markerMsg.mutable_scale(),
+ ignition::math::Vector3d(0.5, 0.5, 1.5));
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Connecting the sphere and cylinder with a line\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(3);
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d(0, 0, 0, 0, 0, 0));
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::LINE_LIST);
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(0.0, 1.0, 1.0));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(2, 0, 0.5));
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Adding a square around the origin\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(4);
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::LINE_STRIP);
+ ignition::msgs::Set(markerMsg.mutable_point(0),
+ ignition::math::Vector3d(0.5, 0.5, 0.05));
+ ignition::msgs::Set(markerMsg.mutable_point(1),
+ ignition::math::Vector3d(0.5, -0.5, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(-0.5, -0.5, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(-0.5, 0.5, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(0.5, 0.5, 0.05));
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Adding 100 points inside the square\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(5);
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::POINTS);
+ markerMsg.clear_point();
+ for (int i = 0; i < 100; ++i)
+ {
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(
+ ignition::math::Rand::DblUniform(-0.49, 0.49),
+ ignition::math::Rand::DblUniform(-0.49, 0.49),
+ 0.05));
+ }
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Adding a semi-circular triangle fan\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(6);
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::TRIANGLE_FAN);
+ markerMsg.clear_point();
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d(0, 1.5, 0, 0, 0, 0));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(0, 0, 0.05));
+ double radius = 2;
+ for (double t = 0; t <= M_PI; t+= 0.01)
+ {
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(radius * cos(t), radius * sin(t), 0.05));
+ }
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Adding two triangles using a triangle list\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(7);
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::TRIANGLE_LIST);
+ markerMsg.clear_point();
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d(0, -1.5, 0, 0, 0, 0));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(0, 0, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(1, 0, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(1, 1, 0.05));
+
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(1, 1, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(2, 1, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(2, 2, 0.05));
+
+ node.Request("/marker", markerMsg);
+
+ std::cout << "Adding a rectangular triangle strip\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_id(8);
+ markerMsg.set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg.set_type(ignition::msgs::Marker::TRIANGLE_STRIP);
+ markerMsg.clear_point();
+ ignition::msgs::Set(markerMsg.mutable_pose(),
+ ignition::math::Pose3d(-2, -2, 0, 0, 0, 0));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(0, 0, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(1, 0, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(0, 1, 0.05));
+
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(1, 1, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(0, 2, 0.05));
+ ignition::msgs::Set(markerMsg.add_point(),
+ ignition::math::Vector3d(1, 2, 0.05));
+
+ node.Request("/marker", markerMsg);
+ std::cout << "Adding multiple markers via /marker_array\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+
+ ignition::msgs::Marker_V markerMsgs;
+ ignition::msgs::Boolean res;
+ bool result;
+ unsigned int timeout = 5000;
+
+ // Create first blue sphere marker
+ auto markerMsg1 = markerMsgs.add_marker();
+ markerMsg1->set_ns("default");
+ markerMsg1->set_id(0);
+ markerMsg1->set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg1->set_type(ignition::msgs::Marker::SPHERE);
+ markerMsg1->set_visibility(ignition::msgs::Marker::GUI);
+
+ // Set color to Blue
+ markerMsg1->mutable_material()->mutable_ambient()->set_r(0);
+ markerMsg1->mutable_material()->mutable_ambient()->set_g(0);
+ markerMsg1->mutable_material()->mutable_ambient()->set_b(1);
+ markerMsg1->mutable_material()->mutable_ambient()->set_a(1);
+ markerMsg1->mutable_material()->mutable_diffuse()->set_r(0);
+ markerMsg1->mutable_material()->mutable_diffuse()->set_g(0);
+ markerMsg1->mutable_material()->mutable_diffuse()->set_b(1);
+ markerMsg1->mutable_material()->mutable_diffuse()->set_a(1);
+ ignition::msgs::Set(markerMsg1->mutable_scale(),
+ ignition::math::Vector3d(1.0, 1.0, 1.0));
+ ignition::msgs::Set(markerMsg1->mutable_pose(),
+ ignition::math::Pose3d(3, 3, 0, 0, 0, 0));
+
+ // Create second red box marker
+ auto markerMsg2 = markerMsgs.add_marker();
+ markerMsg2->set_ns("default");
+ markerMsg2->set_id(0);
+ markerMsg2->set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg2->set_type(ignition::msgs::Marker::BOX);
+ markerMsg2->set_visibility(ignition::msgs::Marker::GUI);
+
+ // Set color to Red
+ markerMsg2->mutable_material()->mutable_ambient()->set_r(1);
+ markerMsg2->mutable_material()->mutable_ambient()->set_g(0);
+ markerMsg2->mutable_material()->mutable_ambient()->set_b(0);
+ markerMsg2->mutable_material()->mutable_ambient()->set_a(1);
+ markerMsg2->mutable_material()->mutable_diffuse()->set_r(1);
+ markerMsg2->mutable_material()->mutable_diffuse()->set_g(0);
+ markerMsg2->mutable_material()->mutable_diffuse()->set_b(0);
+ markerMsg2->mutable_material()->mutable_diffuse()->set_a(1);
+ markerMsg2->mutable_lifetime()->set_sec(2);
+ markerMsg2->mutable_lifetime()->set_nsec(0);
+ ignition::msgs::Set(markerMsg2->mutable_scale(),
+ ignition::math::Vector3d(1.0, 1.0, 1.0));
+ ignition::msgs::Set(markerMsg2->mutable_pose(),
+ ignition::math::Pose3d(3, 3, 2, 0, 0, 0));
+
+ // Create green capsule marker
+ auto markerMsg3 = markerMsgs.add_marker();
+ markerMsg3->set_ns("default");
+ markerMsg3->set_id(0);
+ markerMsg3->set_action(ignition::msgs::Marker::ADD_MODIFY);
+ markerMsg3->set_type(ignition::msgs::Marker::CAPSULE);
+ markerMsg3->set_visibility(ignition::msgs::Marker::GUI);
+
+ // Set color to Green
+ markerMsg3->mutable_material()->mutable_ambient()->set_r(0);
+ markerMsg3->mutable_material()->mutable_ambient()->set_g(1);
+ markerMsg3->mutable_material()->mutable_ambient()->set_b(0);
+ markerMsg3->mutable_material()->mutable_ambient()->set_a(1);
+ markerMsg3->mutable_material()->mutable_diffuse()->set_r(0);
+ markerMsg3->mutable_material()->mutable_diffuse()->set_g(1);
+ markerMsg3->mutable_material()->mutable_diffuse()->set_b(0);
+ markerMsg3->mutable_material()->mutable_diffuse()->set_a(1);
+ markerMsg3->mutable_lifetime()->set_sec(2);
+ markerMsg3->mutable_lifetime()->set_nsec(0);
+ ignition::msgs::Set(markerMsg3->mutable_scale(),
+ ignition::math::Vector3d(1.0, 1.0, 1.0));
+ ignition::msgs::Set(markerMsg3->mutable_pose(),
+ ignition::math::Pose3d(3, 3, 4, 0, 0, 0));
+
+ // Publish the three created markers above simultaneously
+ node.Request("/marker_array", markerMsgs, timeout, res, result);
+
+ std::cout << "Deleting all the markers\n";
+ std::this_thread::sleep_for(std::chrono::seconds(4));
+ markerMsg.set_action(ignition::msgs::Marker::DELETE_ALL);
+ node.Request("/marker", markerMsg);
+}
diff --git a/examples/standalone/scene_provider/scene_provider.cc b/examples/standalone/scene_provider/scene_provider.cc
index 5f32eab8e..2bb4a9ab1 100644
--- a/examples/standalone/scene_provider/scene_provider.cc
+++ b/examples/standalone/scene_provider/scene_provider.cc
@@ -21,6 +21,8 @@
#include
#include
#include
+#include
+#include
#include
using namespace std::chrono_literals;
@@ -75,6 +77,10 @@ int main(int argc, char **argv)
// Scene service
node.Advertise("/example/scene", sceneService);
+ // Periodic pose updated
+ auto statsPub =
+ node.Advertise("/example/stats");
+
// Periodic pose updated
auto posePub = node.Advertise("/example/pose");
@@ -90,6 +96,10 @@ int main(int argc, char **argv)
double y{0.0};
double z{0.0};
+ std::chrono::steady_clock::duration timePoint =
+ std::chrono::steady_clock::duration::zero();
+ ignition::msgs::WorldStatistics msgWorldStatistics;
+
while (true)
{
std::this_thread::sleep_for(100ms);
@@ -102,6 +112,16 @@ int main(int argc, char **argv)
positionMsg->set_y(y);
positionMsg->set_z(z);
posePub.Publish(poseVMsg);
+
+ timePoint += 100ms;
+ msgWorldStatistics.set_real_time_factor(1);
+
+ auto s = std::chrono::duration_cast(timePoint);
+ auto ns = std::chrono::duration_cast(timePoint-s);
+
+ msgWorldStatistics.mutable_sim_time()->set_sec(s.count());
+ msgWorldStatistics.mutable_sim_time()->set_nsec(ns.count());
+ statsPub.Publish(msgWorldStatistics);
}
ignition::transport::waitForShutdown();
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 68464ff2f..a1d814e29 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -121,6 +121,7 @@ add_subdirectory(image_display)
add_subdirectory(key_publisher)
add_subdirectory(plotting)
add_subdirectory(publisher)
+add_subdirectory(marker_manager)
add_subdirectory(minimal_scene)
add_subdirectory(scene3d)
add_subdirectory(screenshot)
diff --git a/src/plugins/marker_manager/CMakeLists.txt b/src/plugins/marker_manager/CMakeLists.txt
new file mode 100644
index 000000000..42713a762
--- /dev/null
+++ b/src/plugins/marker_manager/CMakeLists.txt
@@ -0,0 +1,8 @@
+ign_gui_add_plugin(MarkerManager
+ SOURCES
+ MarkerManager.cc
+ QT_HEADERS
+ MarkerManager.hh
+ PUBLIC_LINK_LIBS
+ ignition-rendering${IGN_RENDERING_VER}::ignition-rendering${IGN_RENDERING_VER}
+)
diff --git a/src/plugins/marker_manager/MarkerManager.cc b/src/plugins/marker_manager/MarkerManager.cc
new file mode 100644
index 000000000..a78531c2a
--- /dev/null
+++ b/src/plugins/marker_manager/MarkerManager.cc
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2021 Open Source Robotics Foundation
+ *
+ * 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