diff --git a/examples/worlds/minimal_scene.sdf b/examples/worlds/minimal_scene.sdf index fa09de8c38..bbbd93d4bf 100644 --- a/examples/worlds/minimal_scene.sdf +++ b/examples/worlds/minimal_scene.sdf @@ -180,6 +180,16 @@ Missing for parity with GzScene3D: true + + + false + 5 + 5 + floating + false + + + diff --git a/src/gui/gui.config b/src/gui/gui.config index a250a3c1a9..c482aa74eb 100644 --- a/src/gui/gui.config +++ b/src/gui/gui.config @@ -116,6 +116,16 @@ + + + false + 5 + 5 + floating + false + + + diff --git a/src/gui/plugins/CMakeLists.txt b/src/gui/plugins/CMakeLists.txt index d74c63cca3..84d5f99e2a 100644 --- a/src/gui/plugins/CMakeLists.txt +++ b/src/gui/plugins/CMakeLists.txt @@ -121,6 +121,7 @@ add_subdirectory(modules) add_subdirectory(align_tool) add_subdirectory(banana_for_scale) add_subdirectory(component_inspector) +add_subdirectory(drop_from_fuel) add_subdirectory(entity_context_menu) add_subdirectory(entity_tree) add_subdirectory(joint_position_controller) diff --git a/src/gui/plugins/drop_from_fuel/CMakeLists.txt b/src/gui/plugins/drop_from_fuel/CMakeLists.txt new file mode 100644 index 0000000000..2fd4256c6a --- /dev/null +++ b/src/gui/plugins/drop_from_fuel/CMakeLists.txt @@ -0,0 +1,8 @@ +gz_add_gui_plugin(DropFromFuel + SOURCES + DropFromFuel.cc + QT_HEADERS + DropFromFuel.hh + PUBLIC_LINK_LIBS + ${PROJECT_LIBRARY_TARGET_NAME}-rendering +) diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.cc b/src/gui/plugins/drop_from_fuel/DropFromFuel.cc new file mode 100644 index 0000000000..b52be5967f --- /dev/null +++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.cc @@ -0,0 +1,231 @@ +/* + * 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 "DropFromFuel.hh" + +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +namespace ignition::gazebo +{ + class DropFromFuelPrivate + { + /// \brief Update the 3D scene with new entities + public: void OnRender(); + + /// \brief User camera + public: rendering::CameraPtr camera{nullptr}; + + /// \brief Pointer to the rendering scene + public: rendering::ScenePtr scene{nullptr}; + + /// \brief Ray query for mouse clicks + public: rendering::RayQueryPtr rayQuery{nullptr}; + + /// \brief Transport node for making transform control requests + public: ignition::transport::Node node; + + /// \brief Name of the world + public: std::string worldName; + }; +} + +using namespace ignition; +using namespace gazebo; + +///////////////////////////////////////////////// +void DropFromFuelPrivate::OnRender() +{ + if (nullptr == this->scene) + { + this->scene = rendering::sceneFromFirstRenderEngine(); + if (nullptr == this->scene) + { + return; + } + + for (unsigned int i = 0; i < this->scene->NodeCount(); ++i) + { + auto cam = std::dynamic_pointer_cast( + this->scene->NodeByIndex(i)); + if (cam) + { + if (std::get(cam->UserData("user-camera"))) + { + this->camera = cam; + + // Ray Query + this->rayQuery = this->camera->Scene()->CreateRayQuery(); + + igndbg << "DropFromFuel plugin is using camera [" + << this->camera->Name() << "]" << std::endl; + break; + } + } + } + } +} + +///////////////////////////////////////////////// +DropFromFuel::DropFromFuel() + : ignition::gui::Plugin(), + dataPtr(std::make_unique()) +{ +} + +///////////////////////////////////////////////// +DropFromFuel::~DropFromFuel() = default; + +///////////////////////////////////////////////// +void DropFromFuel::LoadConfig(const tinyxml2::XMLElement *) +{ + if (this->title.empty()) + this->title = "Drop from fuel"; + + // World name from window, to construct default topics and services + auto worldNames = gui::worldNames(); + if (!worldNames.empty()) + this->dataPtr->worldName = worldNames[0].toStdString(); + + ignition::gui::App()->findChild + ()->installEventFilter(this); +} + +//////////////////////////////////////////////// +bool DropFromFuel::eventFilter(QObject *_obj, QEvent *_event) +{ + if (_event->type() == ignition::gui::events::Render::kType) + { + this->dataPtr->OnRender(); + } + else if (_event->type() == ignition::gui::events::DropOnScene::kType) + { + auto dropOnSceneEvent = + reinterpret_cast(_event); + if (dropOnSceneEvent) + { + if (dropOnSceneEvent->DropText().empty()) + { + ignerr << "Dropped empty entity URI.\n"; + } + else + { + if (this->dataPtr->camera && this->dataPtr->rayQuery) + { + std::function cb = + [](const ignition::msgs::Boolean &_res, const bool _result) + { + if (!_result || !_res.data()) + ignerr << "Error creating dropped entity." << std::endl; + }; + + math::Vector3d pos = ignition::rendering::screenToScene( + dropOnSceneEvent->Mouse(), + this->dataPtr->camera, + this->dataPtr->rayQuery); + + msgs::EntityFactory req; + std::string dropStr = dropOnSceneEvent->DropText(); + if (QUrl(QString(dropStr.c_str())).isLocalFile()) + { + // mesh to sdf model + common::rtrim(dropStr); + + if (!common::MeshManager::Instance()->IsValidFilename(dropStr)) + { + ignerr << "Invalid URI: " + dropStr + + "\nOnly Fuel URLs or mesh file types DAE, OBJ, and STL" + "are supported."; + return QObject::eventFilter(_obj, _event); + } + + // Fixes whitespace + dropStr = common::replaceAll(dropStr, "%20", " "); + + std::string filename = common::basename(dropStr); + std::vector splitName = common::split(filename, "."); + + std::string sdf = "" + "" + "" + "" + "" + "" + "" + "" + dropStr + "" + "" + "" + "" + "" + "" + "" + "" + dropStr + "" + "" + "" + "" + "" + "" + ""; + + req.set_sdf(sdf); + } + else + { + // model from fuel + req.set_sdf_filename(dropStr); + } + + req.set_allow_renaming(true); + msgs::Set(req.mutable_pose(), + math::Pose3d(pos.X(), pos.Y(), pos.Z(), 1, 0, 0, 0)); + + this->dataPtr->node.Request( + "/world/" + this->dataPtr->worldName + "/create", + req, cb); + } + } + } + } + + return QObject::eventFilter(_obj, _event); +} + +// Register this plugin +IGNITION_ADD_PLUGIN(ignition::gazebo::DropFromFuel, + ignition::gui::Plugin) diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.hh b/src/gui/plugins/drop_from_fuel/DropFromFuel.hh new file mode 100644 index 0000000000..13fca93120 --- /dev/null +++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.hh @@ -0,0 +1,56 @@ +/* + * 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. + * +*/ + +#ifndef IGNITION_GAZEBO_GUI_DROP_FROM_FUEL_HH_ +#define IGNITION_GAZEBO_GUI_DROP_FROM_FUEL_HH_ + +#include + +#include + +namespace ignition +{ +namespace gazebo +{ + class DropFromFuelPrivate; + + /// \brief Allows to DropFromFuel models and lights using te gui event + /// DropFromFuelFromDescription + class DropFromFuel : public ignition::gui::Plugin + { + Q_OBJECT + + /// \brief Constructor + public: DropFromFuel(); + + /// \brief Destructor + public: ~DropFromFuel() override; + + // Documentation inherited + public: void LoadConfig(const tinyxml2::XMLElement *_pluginElem) override; + + // Documentation inherited + protected: bool eventFilter(QObject *_obj, QEvent *_event) override; + + /// \internal + /// \brief Pointer to private data. + private: std::unique_ptr dataPtr; + }; +} +} + +#endif diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.qml b/src/gui/plugins/drop_from_fuel/DropFromFuel.qml new file mode 100644 index 0000000000..873da30014 --- /dev/null +++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.qml @@ -0,0 +1,28 @@ +/* + * 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. + * +*/ + +import QtQuick 2.0 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 + +// TODO: remove invisible rectangle, see +// https://github.com/ignitionrobotics/ign-gui/issues/220 +Rectangle { + visible: false + Layout.minimumWidth: 100 + Layout.minimumHeight: 100 +} diff --git a/src/gui/plugins/drop_from_fuel/DropFromFuel.qrc b/src/gui/plugins/drop_from_fuel/DropFromFuel.qrc new file mode 100644 index 0000000000..91ce21f53b --- /dev/null +++ b/src/gui/plugins/drop_from_fuel/DropFromFuel.qrc @@ -0,0 +1,5 @@ + + + DropFromFuel.qml + +