From cdbd53cf7bb9306fa549990cbfcbda59cb88758a Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Thu, 10 Nov 2022 15:35:51 -0800 Subject: [PATCH 1/5] Add view control reference visual (#500) Adds a reference visual to help visualize the anchor point for view control operations. The implementation is done in gz-gui instead of gz-rendering as it's easier to do since we need to toggle visibility depending on mouse events, and also we don't need to write the same code twice for different view controllers. Signed-off-by: Ian Chen --- .../InteractiveViewControl.cc | 105 +++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/src/plugins/interactive_view_control/InteractiveViewControl.cc b/src/plugins/interactive_view_control/InteractiveViewControl.cc index 9dfecceae..442c3dfc2 100644 --- a/src/plugins/interactive_view_control/InteractiveViewControl.cc +++ b/src/plugins/interactive_view_control/InteractiveViewControl.cc @@ -27,6 +27,8 @@ #include #include +#include +#include #include #include #include @@ -45,11 +47,23 @@ class ignition::gui::plugins::InteractiveViewControlPrivate /// \brief Callback for camera view controller request /// \param[in] _msg Request message to set the camera view controller - /// \param[in] _res Response data + /// \param[out] _res Response data /// \return True if the request is received public: bool OnViewControl(const msgs::StringMsg &_msg, msgs::Boolean &_res); + + /// \brief Callback for camera reference visual request + /// \param[in] _msg Request message to enable/disable the reference visual + /// \param[out] _res Response data + /// \return True if the request is received + public: bool OnReferenceVisual(const msgs::Boolean &_msg, + msgs::Boolean &_res); + + /// \brief Update the reference visual. Adjust scale based on distance from + /// camera to target point so it remains the same size on screen. + public: void UpdateReferenceVisual(); + /// \brief Flag to indicate if mouse event is dirty public: bool mouseDirty = false; @@ -83,15 +97,24 @@ class ignition::gui::plugins::InteractiveViewControlPrivate /// \brief View controller public: std::string viewController{"orbit"}; + /// \brief Enable / disable reference visual + public: bool enableRefVisual{true}; + /// \brief Camera view control service public: std::string cameraViewControlService; + /// \brief Camera reference visual service + public: std::string cameraRefVisualService; + /// \brief Ray query for mouse clicks public: rendering::RayQueryPtr rayQuery{nullptr}; //// \brief Pointer to the rendering scene public: rendering::ScenePtr scene{nullptr}; + /// \brief Reference visual for visualizing the target point + public: rendering::VisualPtr refVisual{nullptr}; + /// \brief Transport node for making transform control requests public: transport::Node node; }; @@ -173,6 +196,34 @@ void InteractiveViewControlPrivate::OnRender() } this->viewControl->SetCamera(this->camera); + if (this->enableRefVisual) + { + if (!this->refVisual) + { + // create ref visual + this->refVisual = scene->CreateVisual(); + rendering::GeometryPtr sphere = scene->CreateSphere(); + this->refVisual->AddGeometry(sphere); + this->refVisual->SetLocalScale(math::Vector3d(0.2, 0.2, 0.1)); + this->refVisual->SetVisibilityFlags( + IGN_VISIBILITY_GUI & ~IGN_VISIBILITY_SELECTABLE + ); + + // create material + math::Color diffuse(1.0f, 1.0f, 0.0f, 1.0f); + math::Color specular(1.0f, 1.0f, 0.0f, 1.0f); + double transparency = 0.3; + rendering::MaterialPtr material = scene->CreateMaterial(); + material->SetDiffuse(diffuse); + material->SetSpecular(specular); + material->SetTransparency(transparency); + material->SetCastShadows(false); + this->refVisual->SetMaterial(material); + scene->DestroyMaterial(material); + } + this->refVisual->SetVisible(true); + } + if (this->mouseEvent.Type() == common::MouseEvent::SCROLL) { this->target = rendering::screenToScene( @@ -183,12 +234,14 @@ void InteractiveViewControlPrivate::OnRender() this->target); double amount = -this->drag.Y() * distance / 5.0; this->viewControl->Zoom(amount); + this->UpdateReferenceVisual(); } else if (this->mouseEvent.Type() == common::MouseEvent::PRESS) { this->target = rendering::screenToScene( this->mouseEvent.PressPos(), this->camera, this->rayQuery); this->viewControl->SetTarget(this->target); + this->UpdateReferenceVisual(); } else { @@ -199,11 +252,13 @@ void InteractiveViewControlPrivate::OnRender() this->viewControl->Orbit(this->drag); else this->viewControl->Pan(this->drag); + this->UpdateReferenceVisual(); } // Orbit with middle button else if (this->mouseEvent.Buttons() & common::MouseEvent::MIDDLE) { this->viewControl->Orbit(this->drag); + this->UpdateReferenceVisual(); } // Zoom with right button else if (this->mouseEvent.Buttons() & common::MouseEvent::RIGHT) @@ -215,12 +270,36 @@ void InteractiveViewControlPrivate::OnRender() static_cast(this->camera->ImageHeight())) * distance * tan(vfov/2.0) * 6.0); this->viewControl->Zoom(amount); + this->UpdateReferenceVisual(); + } + // hover + else + { + if (this->refVisual) + this->refVisual->SetVisible(false); } } + this->drag = 0; this->mouseDirty = false; } +///////////////////////////////////////////////// +void InteractiveViewControlPrivate::UpdateReferenceVisual() +{ + if (!this->refVisual || !this->enableRefVisual) + return; + this->refVisual->SetWorldPosition(this->target); + // Update the size of the reference visual based on the distance to the + // target point. + double distance = + this->camera->WorldPosition().Distance(this->target); + + double scale = distance * atan(IGN_DTOR(1.0)); + this->refVisual->SetLocalScale( + math::Vector3d(scale, scale, scale * 0.5)); +} + ///////////////////////////////////////////////// bool InteractiveViewControlPrivate::OnViewControl(const msgs::StringMsg &_msg, msgs::Boolean &_res) @@ -245,6 +324,17 @@ bool InteractiveViewControlPrivate::OnViewControl(const msgs::StringMsg &_msg, return true; } +///////////////////////////////////////////////// +bool InteractiveViewControlPrivate::OnReferenceVisual(const msgs::Boolean &_msg, + msgs::Boolean &_res) +{ + std::lock_guard lock(this->mutex); + this->enableRefVisual = _msg.data(); + + _res.set_data(true); + return true; +} + ///////////////////////////////////////////////// InteractiveViewControl::InteractiveViewControl() : Plugin(), dataPtr(std::make_unique()) @@ -268,6 +358,12 @@ void InteractiveViewControl::LoadConfig( ignmsg << "Camera view controller topic advertised on [" << this->dataPtr->cameraViewControlService << "]" << std::endl; + this->dataPtr->cameraRefVisualService = "/gui/camera/reference_visual"; + this->dataPtr->node.Advertise(this->dataPtr->cameraRefVisualService, + &InteractiveViewControlPrivate::OnReferenceVisual, this->dataPtr.get()); + ignmsg << "Camera reference visual topic advertised on [" + << this->dataPtr->cameraRefVisualService << "]" << std::endl; + ignition::gui::App()->findChild< ignition::gui::MainWindow *>()->installEventFilter(this); } @@ -329,6 +425,13 @@ bool InteractiveViewControl::eventFilter(QObject *_obj, QEvent *_event) _event); this->dataPtr->blockOrbit = blockOrbit->Block(); } + else if (_event->type() == gui::events::HoverOnScene::kType) + { + gui::events::HoverOnScene *_e = + static_cast(_event); + this->dataPtr->mouseDirty = true; + this->dataPtr->mouseEvent = _e->Mouse(); + } // Standard event processing return QObject::eventFilter(_obj, _event); From e6d45daa0c5d7f7ce7161f2cd28e11c5c147173c Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Wed, 16 Nov 2022 11:41:20 -0800 Subject: [PATCH 2/5] Fix large / unexpected camera movements (#502) Fixes large / unexpected camera movement when orbiting / panning due to missing mouse events. Signed-off-by: Ian Chen --- .../InteractiveViewControl.cc | 35 ++++++++----- src/plugins/minimal_scene/MinimalScene.cc | 49 ++++++++++++------- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/src/plugins/interactive_view_control/InteractiveViewControl.cc b/src/plugins/interactive_view_control/InteractiveViewControl.cc index 442c3dfc2..99c02a10d 100644 --- a/src/plugins/interactive_view_control/InteractiveViewControl.cc +++ b/src/plugins/interactive_view_control/InteractiveViewControl.cc @@ -67,6 +67,12 @@ class ignition::gui::plugins::InteractiveViewControlPrivate /// \brief Flag to indicate if mouse event is dirty public: bool mouseDirty = false; + /// \brief Flag to indicate if hover event is dirty + public: bool hoverDirty = false; + + /// \brief Flag to indicate if mouse press event is dirty + public: bool mousePressDirty = false; + /// \brief True to block orbiting with the mouse. public: bool blockOrbit = false; @@ -171,10 +177,18 @@ void InteractiveViewControlPrivate::OnRender() return; } - if (!this->mouseDirty) + if (!this->camera) return; - if (!this->camera) + // hover + if (this->hoverDirty) + { + if (this->refVisual) + this->refVisual->SetVisible(false); + this->hoverDirty = false; + } + + if (!this->mouseDirty) return; std::lock_guard lock(this->mutex); @@ -240,8 +254,10 @@ void InteractiveViewControlPrivate::OnRender() { this->target = rendering::screenToScene( this->mouseEvent.PressPos(), this->camera, this->rayQuery); + this->viewControl->SetTarget(this->target); this->UpdateReferenceVisual(); + this->mousePressDirty = false; } else { @@ -272,12 +288,6 @@ void InteractiveViewControlPrivate::OnRender() this->viewControl->Zoom(amount); this->UpdateReferenceVisual(); } - // hover - else - { - if (this->refVisual) - this->refVisual->SetVisible(false); - } } this->drag = 0; @@ -389,12 +399,16 @@ bool InteractiveViewControl::eventFilter(QObject *_obj, QEvent *_event) auto pressOnScene = reinterpret_cast(_event); this->dataPtr->mouseDirty = true; + this->dataPtr->mousePressDirty = true; this->dataPtr->drag = math::Vector2d::Zero; this->dataPtr->mouseEvent = pressOnScene->Mouse(); } else if (_event->type() == events::DragOnScene::kType) { + if (this->dataPtr->mousePressDirty) + return QObject::eventFilter(_obj, _event); + auto dragOnScene = reinterpret_cast(_event); this->dataPtr->mouseDirty = true; @@ -427,10 +441,7 @@ bool InteractiveViewControl::eventFilter(QObject *_obj, QEvent *_event) } else if (_event->type() == gui::events::HoverOnScene::kType) { - gui::events::HoverOnScene *_e = - static_cast(_event); - this->dataPtr->mouseDirty = true; - this->dataPtr->mouseEvent = _e->Mouse(); + this->dataPtr->hoverDirty = true; } // Standard event processing diff --git a/src/plugins/minimal_scene/MinimalScene.cc b/src/plugins/minimal_scene/MinimalScene.cc index 56833ed16..24b0fff71 100644 --- a/src/plugins/minimal_scene/MinimalScene.cc +++ b/src/plugins/minimal_scene/MinimalScene.cc @@ -18,6 +18,7 @@ #include "MinimalScene.hh" #include +#include #include #include #include @@ -67,12 +68,23 @@ class ignition::gui::plugins::IgnRenderer::Implementation /// \brief Flag to indicate if drop event is dirty public: bool dropDirty{false}; - /// \brief Mouse event + /// \brief Current mouse event public: common::MouseEvent mouseEvent; + /// \brief A list of mouse events + public: std::list mouseEvents; + /// \brief Key event public: common::KeyEvent keyEvent; + /// \brief Max number of mouse events to store in the queue. + /// These events are then propagated to other gui plugins. A queue is used + /// instead of just keeping the latest mouse event so that we can capture + /// important events like mouse presses. However we keep the queue size + /// small on purpose so that we do not flood other gui plugins with events + /// that may be outdated. + public: const unsigned int kMaxMouseEventSize = 5u; + /// \brief Mutex to protect mouse events public: std::mutex mutex; @@ -329,14 +341,21 @@ void IgnRenderer::Render(RenderSync *_renderSync) void IgnRenderer::HandleMouseEvent() { std::lock_guard lock(this->dataPtr->mutex); + for (const auto &e : this->dataPtr->mouseEvents) + { + this->dataPtr->mouseEvent = e; + + this->BroadcastDrag(); + this->BroadcastMousePress(); + this->BroadcastLeftClick(); + this->BroadcastRightClick(); + this->BroadcastScroll(); + this->BroadcastKeyPress(); + this->BroadcastKeyRelease(); + } + this->dataPtr->mouseEvents.clear(); + this->BroadcastHoverPos(); - this->BroadcastDrag(); - this->BroadcastMousePress(); - this->BroadcastLeftClick(); - this->BroadcastRightClick(); - this->BroadcastScroll(); - this->BroadcastKeyPress(); - this->BroadcastKeyRelease(); this->BroadcastDrop(); this->dataPtr->mouseDirty = false; } @@ -410,8 +429,6 @@ void IgnRenderer::BroadcastDrag() events::DragOnScene dragEvent(this->dataPtr->mouseEvent); App()->sendEvent(App()->findChild(), &dragEvent); - - this->dataPtr->mouseDirty = false; } ///////////////////////////////////////////////// @@ -432,8 +449,6 @@ void IgnRenderer::BroadcastLeftClick() events::LeftClickOnScene leftClickOnSceneEvent(this->dataPtr->mouseEvent); App()->sendEvent(App()->findChild(), &leftClickOnSceneEvent); - - this->dataPtr->mouseDirty = false; } ///////////////////////////////////////////////// @@ -454,8 +469,6 @@ void IgnRenderer::BroadcastRightClick() events::RightClickOnScene rightClickOnSceneEvent(this->dataPtr->mouseEvent); App()->sendEvent(App()->findChild(), &rightClickOnSceneEvent); - - this->dataPtr->mouseDirty = false; } ///////////////////////////////////////////////// @@ -469,8 +482,6 @@ void IgnRenderer::BroadcastMousePress() events::MousePressOnScene event(this->dataPtr->mouseEvent); App()->sendEvent(App()->findChild(), &event); - - this->dataPtr->mouseDirty = false; } ///////////////////////////////////////////////// @@ -484,8 +495,6 @@ void IgnRenderer::BroadcastScroll() events::ScrollOnScene scrollOnSceneEvent(this->dataPtr->mouseEvent); App()->sendEvent(App()->findChild(), &scrollOnSceneEvent); - - this->dataPtr->mouseDirty = false; } ///////////////////////////////////////////////// @@ -641,7 +650,9 @@ void IgnRenderer::NewDropEvent(const std::string &_dropText, void IgnRenderer::NewMouseEvent(const common::MouseEvent &_e) { std::lock_guard lock(this->dataPtr->mutex); - this->dataPtr->mouseEvent = _e; + if (this->dataPtr->mouseEvents.size() >= this->dataPtr->kMaxMouseEventSize) + this->dataPtr->mouseEvents.pop_front(); + this->dataPtr->mouseEvents.push_back(_e); this->dataPtr->mouseDirty = true; } From 0e4a198062f814573b32164804279237d93e2d6d Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Thu, 17 Nov 2022 14:45:20 -0800 Subject: [PATCH 3/5] Add service for configuring view control sensitivity (#504) Signed-off-by: Ian Chen --- .../InteractiveViewControl.cc | 65 +++++++++++++++++-- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/src/plugins/interactive_view_control/InteractiveViewControl.cc b/src/plugins/interactive_view_control/InteractiveViewControl.cc index 99c02a10d..335916487 100644 --- a/src/plugins/interactive_view_control/InteractiveViewControl.cc +++ b/src/plugins/interactive_view_control/InteractiveViewControl.cc @@ -52,7 +52,6 @@ class ignition::gui::plugins::InteractiveViewControlPrivate public: bool OnViewControl(const msgs::StringMsg &_msg, msgs::Boolean &_res); - /// \brief Callback for camera reference visual request /// \param[in] _msg Request message to enable/disable the reference visual /// \param[out] _res Response data @@ -60,6 +59,16 @@ class ignition::gui::plugins::InteractiveViewControlPrivate public: bool OnReferenceVisual(const msgs::Boolean &_msg, msgs::Boolean &_res); + /// \brief Callback for camera view control sensitivity request + /// \param[in] _msg Request message to set the camera view controller + /// sensitivity. Value must be greater than zero. The higher the number + /// the more sensitive camera control is to mouse movements. Affects all + /// camera movements (pan, orbit, zoom) + /// \param[out] _res Response data + /// \return True if the request is received + public: bool OnViewControlSensitivity(const msgs::Double &_msg, + msgs::Boolean &_res); + /// \brief Update the reference visual. Adjust scale based on distance from /// camera to target point so it remains the same size on screen. public: void UpdateReferenceVisual(); @@ -112,6 +121,9 @@ class ignition::gui::plugins::InteractiveViewControlPrivate /// \brief Camera reference visual service public: std::string cameraRefVisualService; + /// \brief Camera view control sensitivity service + public: std::string cameraViewControlSensitivityService; + /// \brief Ray query for mouse clicks public: rendering::RayQueryPtr rayQuery{nullptr}; @@ -123,6 +135,9 @@ class ignition::gui::plugins::InteractiveViewControlPrivate /// \brief Transport node for making transform control requests public: transport::Node node; + + /// \brief View control sensitivity value. Must be greater than 0. + public: double viewControlSensitivity = 1.0; }; using namespace ignition; @@ -246,7 +261,9 @@ void InteractiveViewControlPrivate::OnRender() this->viewControl->SetTarget(this->target); double distance = this->camera->WorldPosition().Distance( this->target); - double amount = -this->drag.Y() * distance / 5.0; + + math::Vector2d newDrag = this->drag * this->viewControlSensitivity; + double amount = -newDrag.Y() * distance / 5.0; this->viewControl->Zoom(amount); this->UpdateReferenceVisual(); } @@ -261,19 +278,20 @@ void InteractiveViewControlPrivate::OnRender() } else { + math::Vector2d newDrag = this->drag * this->viewControlSensitivity; // Pan with left button if (this->mouseEvent.Buttons() & common::MouseEvent::LEFT) { if (Qt::ShiftModifier == QGuiApplication::queryKeyboardModifiers()) - this->viewControl->Orbit(this->drag); + this->viewControl->Orbit(newDrag); else - this->viewControl->Pan(this->drag); + this->viewControl->Pan(newDrag); this->UpdateReferenceVisual(); } // Orbit with middle button else if (this->mouseEvent.Buttons() & common::MouseEvent::MIDDLE) { - this->viewControl->Orbit(this->drag); + this->viewControl->Orbit(newDrag); this->UpdateReferenceVisual(); } // Zoom with right button @@ -282,7 +300,7 @@ void InteractiveViewControlPrivate::OnRender() double hfov = this->camera->HFOV().Radian(); double vfov = 2.0f * atan(tan(hfov / 2.0f) / this->camera->AspectRatio()); double distance = this->camera->WorldPosition().Distance(this->target); - double amount = ((-this->drag.Y() / + double amount = ((-newDrag.Y() / static_cast(this->camera->ImageHeight())) * distance * tan(vfov/2.0) * 6.0); this->viewControl->Zoom(amount); @@ -345,6 +363,26 @@ bool InteractiveViewControlPrivate::OnReferenceVisual(const msgs::Boolean &_msg, return true; } +///////////////////////////////////////////////// +bool InteractiveViewControlPrivate::OnViewControlSensitivity( + const msgs::Double &_msg, msgs::Boolean &_res) +{ + std::lock_guard lock(this->mutex); + + if (_msg.data() <= 0.0) + { + ignwarn << "View controller sensitivity must be greater than zero [" + << _msg.data() << "]" << std::endl; + _res.set_data(false); + return true; + } + + this->viewControlSensitivity = _msg.data(); + + _res.set_data(true); + return true; +} + ///////////////////////////////////////////////// InteractiveViewControl::InteractiveViewControl() : Plugin(), dataPtr(std::make_unique()) @@ -368,12 +406,25 @@ void InteractiveViewControl::LoadConfig( ignmsg << "Camera view controller topic advertised on [" << this->dataPtr->cameraViewControlService << "]" << std::endl; - this->dataPtr->cameraRefVisualService = "/gui/camera/reference_visual"; + // camera reference visual + this->dataPtr->cameraRefVisualService = + "/gui/camera/view_control/reference_visual"; this->dataPtr->node.Advertise(this->dataPtr->cameraRefVisualService, &InteractiveViewControlPrivate::OnReferenceVisual, this->dataPtr.get()); ignmsg << "Camera reference visual topic advertised on [" << this->dataPtr->cameraRefVisualService << "]" << std::endl; + // camera view control sensitivity + this->dataPtr->cameraViewControlSensitivityService = + "/gui/camera/view_control/sensitivity"; + this->dataPtr->node.Advertise( + this->dataPtr->cameraViewControlSensitivityService, + &InteractiveViewControlPrivate::OnViewControlSensitivity, + this->dataPtr.get()); + ignmsg << "Camera view control sensitivity advertised on [" + << this->dataPtr->cameraViewControlSensitivityService << "]" + << std::endl; + ignition::gui::App()->findChild< ignition::gui::MainWindow *>()->installEventFilter(this); } From b3468aba35745250a0b4cee9aa71685b9e84dbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Thu, 1 Dec 2022 10:03:09 +0100 Subject: [PATCH 4/5] Set View Camera controller from plugin configuration (#506) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero Signed-off-by: Jenn Nguyen Co-authored-by: Jenn Nguyen --- src/plugins/minimal_scene/CMakeLists.txt | 2 +- src/plugins/minimal_scene/MinimalScene.cc | 47 +++++++++++++++++++++++ src/plugins/minimal_scene/MinimalScene.hh | 9 +++++ test/integration/minimal_scene.cc | 9 ++++- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/plugins/minimal_scene/CMakeLists.txt b/src/plugins/minimal_scene/CMakeLists.txt index 7f98b9908..663f844fb 100644 --- a/src/plugins/minimal_scene/CMakeLists.txt +++ b/src/plugins/minimal_scene/CMakeLists.txt @@ -5,5 +5,5 @@ ign_gui_add_plugin(MinimalScene MinimalScene.hh PUBLIC_LINK_LIBS ignition-rendering${IGN_RENDERING_VER}::ignition-rendering${IGN_RENDERING_VER} + ignition-transport${IGN_TRANSPORT_VER}::ignition-transport${IGN_TRANSPORT_VER} ) - diff --git a/src/plugins/minimal_scene/MinimalScene.cc b/src/plugins/minimal_scene/MinimalScene.cc index 24b0fff71..ba7038477 100644 --- a/src/plugins/minimal_scene/MinimalScene.cc +++ b/src/plugins/minimal_scene/MinimalScene.cc @@ -29,6 +29,15 @@ #include #include #include + +#ifdef _MSC_VER +#pragma warning(push, 0) +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #include // TODO(louise) Remove these pragmas once ign-rendering @@ -48,6 +57,8 @@ #pragma warning(pop) #endif +#include + #include "ignition/gui/Application.hh" #include "ignition/gui/Conversions.hh" #include "ignition/gui/GuiEvents.hh" @@ -328,6 +339,28 @@ void IgnRenderer::Render(RenderSync *_renderSync) // update and render to texture this->dataPtr->camera->Update(); + if (!this->cameraViewController.empty()) + { + std::string viewControlService = "/gui/camera/view_control"; + transport::Node node; + std::function cb = + [&](const msgs::Boolean &/*_rep*/, const bool _result) + { + if (!_result) + { + // LCOV_EXCL_START + ignerr << "Error setting view controller. Check if the View Angle GUI " + "plugin is loaded." << std::endl; + // LCOV_EXCL_STOP + } + this->cameraViewController = ""; + }; + + msgs::StringMsg req; + req.set_data(this->cameraViewController); + node.Request(viewControlService, req, cb); + } + if (ignition::gui::App()) { ignition::gui::App()->sendEvent( @@ -1014,6 +1047,14 @@ void RenderWindowItem::SetCameraHFOV(const math::Angle &_fov) this->dataPtr->renderThread->ignRenderer.cameraHFOV = _fov; } +///////////////////////////////////////////////// +void RenderWindowItem::SetCameraViewController( + const std::string &_view_controller) +{ + this->dataPtr->renderThread->ignRenderer.cameraViewController = + _view_controller; +} + ///////////////////////////////////////////////// MinimalScene::MinimalScene() : Plugin(), dataPtr(utils::MakeUniqueImpl()) @@ -1153,6 +1194,12 @@ void MinimalScene::LoadConfig(const tinyxml2::XMLElement *_pluginElem) renderWindow->SetCameraHFOV(fov); } } + + elem = _pluginElem->FirstChildElement("view_controller"); + if (nullptr != elem && nullptr != elem->GetText()) + { + renderWindow->SetCameraViewController(elem->GetText()); + } } renderWindow->SetEngineName(cmdRenderEngine); diff --git a/src/plugins/minimal_scene/MinimalScene.hh b/src/plugins/minimal_scene/MinimalScene.hh index 29b41903b..203b5873a 100644 --- a/src/plugins/minimal_scene/MinimalScene.hh +++ b/src/plugins/minimal_scene/MinimalScene.hh @@ -63,6 +63,8 @@ namespace plugins /// * \ : If present, sky is enabled. /// * \ : Horizontal FOV of the user camera in degrees, /// defaults to 90 + /// * \ : Set the view controller (InteractiveViewControl + /// currently supports types: ortho or orbit). class MinimalScene : public Plugin { Q_OBJECT @@ -242,6 +244,9 @@ namespace plugins /// \brief Horizontal FOV of the camera; public: math::Angle cameraHFOV = math::Angle(M_PI * 0.5); + /// \brief View controller type + public: std::string cameraViewController{""}; + /// \internal /// \brief Pointer to private data. IGN_UTILS_UNIQUE_IMPL_PTR(dataPtr) @@ -347,6 +352,10 @@ namespace plugins /// \param[in] _fov FOV of the camera in degree public: void SetCameraHFOV(const ignition::math::Angle &_fov); + /// \brief Set the camera view controller + /// \param[in] _view_controller The camera view controller type to set + public: void SetCameraViewController(const std::string &_view_controller); + /// \brief Slot called when thread is ready to be started public Q_SLOTS: void Ready(); diff --git a/test/integration/minimal_scene.cc b/test/integration/minimal_scene.cc index dcb6b59fb..a8a420ef4 100644 --- a/test/integration/minimal_scene.cc +++ b/test/integration/minimal_scene.cc @@ -90,12 +90,14 @@ TEST(MinimalSceneTest, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(Config)) " 5000" "" "60" + "ortho" ""; tinyxml2::XMLDocument pluginDoc; pluginDoc.Parse(pluginStr); EXPECT_TRUE(app.LoadPlugin("MinimalScene", pluginDoc.FirstChildElement("plugin"))); + EXPECT_TRUE(app.LoadPlugin("InteractiveViewControl")); // Get main window auto win = app.findChild(); @@ -130,7 +132,7 @@ TEST(MinimalSceneTest, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(Config)) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); QCoreApplication::processEvents(); - sleep++; + ++sleep; } EXPECT_TRUE(receivedPreRenderEvent); EXPECT_TRUE(receivedRenderEvent); @@ -157,9 +159,12 @@ TEST(MinimalSceneTest, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(Config)) EXPECT_NEAR(60, camera->HFOV().Degree(), 1e-4); + EXPECT_EQ(rendering::CameraProjectionType::CPT_ORTHOGRAPHIC, + camera->ProjectionType()); + // Cleanup auto plugins = win->findChildren(); - EXPECT_EQ(1, plugins.size()); + EXPECT_EQ(2, plugins.size()); auto pluginName = plugins[0]->CardItem()->objectName().toStdString(); EXPECT_TRUE(app.RemovePlugin(pluginName)); From 5dfd0fd75fd9e7e30fb77d583fd782f6c23fa5b3 Mon Sep 17 00:00:00 2001 From: Jenn Nguyen Date: Fri, 2 Dec 2022 11:56:19 -0800 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=8E=88=206.7.0=20(#509)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jenn Nguyen --- CMakeLists.txt | 2 +- Changelog.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 478de942a..d860ca620 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) #============================================================================ # Initialize the project #============================================================================ -project(ignition-gui6 VERSION 6.6.1) +project(ignition-gui6 VERSION 6.7.0) #============================================================================ # Find ignition-cmake diff --git a/Changelog.md b/Changelog.md index 798bb8e21..9d59c77ee 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,19 @@ ## Gazebo GUI 6 +### Gazebo GUI 6.7.0 (2022-12-02) + +1. Set View Camera controller from plugin configuration + * [Pull request #506](https://github.com/gazebosim/gz-gui/pull/506) + +1. Add service for configuring view control sensitivity + * [Pull request #504](https://github.com/gazebosim/gz-gui/pull/504) + +1. Fix large / unexpected camera movements + * [Pull request #502](https://github.com/gazebosim/gz-gui/pull/502) + +1. Add view control reference visual + * [Pull request #500](https://github.com/gazebosim/gz-gui/pull/500) + ### Gazebo GUI 6.6.1 (2022-08-17) 1. Fix mistaken dialog error message