diff --git a/include/ignition/gazebo/Primitives.hh b/include/ignition/gazebo/Primitives.hh new file mode 100644 index 0000000000..eff9a97b83 --- /dev/null +++ b/include/ignition/gazebo/Primitives.hh @@ -0,0 +1,83 @@ +/* + * 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_PRIMITIVES_HH_ +#define IGNITION_GAZEBO_PRIMITIVES_HH_ + +#include +#include + +#include + +namespace ignition +{ + namespace gazebo + { + // Inline bracket to help doxygen filtering. + inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { + + /// \brief Enumeration of available primitive shape types + enum class IGNITION_GAZEBO_VISIBLE PrimitiveShape + { + kBox, + kCapsule, + kCylinder, + kEllipsoid, + kSphere, + }; + + /// \brief Enumeration of available primitive light types + enum class IGNITION_GAZEBO_VISIBLE PrimitiveLight + { + kDirectional, + kPoint, + kSpot, + }; + + /// \brief Return an SDF string of one of the available primitive + /// shape types + /// \param[in] _type Type of shape to retrieve + /// \return String containing SDF description of primitive shape + /// Empty string if the _type is not supported. + std::string IGNITION_GAZEBO_VISIBLE + getPrimitiveShape(const PrimitiveShape &_type); + + /// \brief Return an SDF string of one of the available primitive + /// light types + /// \param[in] _type Type of light to retrieve + /// \return String containing SDF description of primitive light + /// Empty string if the _type is not supported. + std::string IGNITION_GAZEBO_VISIBLE + getPrimitiveLight(const PrimitiveLight &_type); + + /// \brief Return an SDF string of one of the available primitive shape or + /// light types. + /// \param[in] _typeName Type name of the of shape or light to retrieve. + /// Must be one of: box, sphere, cylinder, capsule, ellipsoid, directional, + /// point, or spot. + /// \return String containing SDF description of primitive shape or light. + /// Empty string if the _typeName is invalid. + std::string IGNITION_GAZEBO_VISIBLE + getPrimitive(const std::string &_typeName); + } + } // namespace gazebo +} // namespace ignition + + +#endif // IGNITION_GAZEBO_PRIMITIVES_HH_ + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 44d715c097..358256f1e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,7 @@ set (sources LevelManager.cc Link.cc Model.cc + Primitives.cc SdfEntityCreator.cc SdfGenerator.cc Server.cc @@ -78,6 +79,7 @@ set (gtest_sources EventManager_TEST.cc Link_TEST.cc Model_TEST.cc + Primitives_TEST.cc SdfEntityCreator_TEST.cc SdfGenerator_TEST.cc ServerConfig_TEST.cc diff --git a/src/Primitives.cc b/src/Primitives.cc new file mode 100644 index 0000000000..e83880008a --- /dev/null +++ b/src/Primitives.cc @@ -0,0 +1,364 @@ +/* + * 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 "ignition/gazebo/Primitives.hh" + +using namespace ignition; +using namespace gazebo; + +///////////////////////////////////////////////// +constexpr const char * kBoxSdf = R"( + + + 0 0 0.5 0 0 0 + + + + 0.16666 + 0 + 0 + 0.16666 + 0 + 0.16666 + + 1.0 + + + + + 1 1 1 + + + + + + + 1 1 1 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + +)"; + +///////////////////////////////////////////////// +constexpr const char * kSphereSdf = R"( + + + 0 0 0.5 0 0 0 + + + + 0.1 + 0 + 0 + 0.1 + 0 + 0.1 + + 1.0 + + + + + 0.5 + + + + + + + 0.5 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + +)"; + +///////////////////////////////////////////////// +constexpr const char * kCylinderSdf = R"( + + + 0 0 0.5 0 0 0 + + + + 0.1458 + 0 + 0 + 0.1458 + 0 + 0.125 + + 1.0 + + + + + 0.5 + 1.0 + + + + + + + 0.5 + 1.0 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + +)"; + +///////////////////////////////////////////////// +constexpr const char * kCapsuleSdf = R"( + + + 0 0 0.5 0 0 0 + + + + 0.074154 + 0 + 0 + 0.074154 + 0 + 0.018769 + + 1.0 + + + + + 0.2 + 0.6 + + + + + + + 0.2 + 0.6 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + +)"; + +///////////////////////////////////////////////// +constexpr const char *kEllipsoidSdf = R"( + + + 0 0 0.5 0 0 0 + + + + 0.068 + 0 + 0 + 0.058 + 0 + 0.026 + + 1.0 + + + + + 0.2 0.3 0.5 + + + + + + + 0.2 0.3 0.5 + + + + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + 0.8 0.8 0.8 1 + + + + + +)"; + +///////////////////////////////////////////////// +constexpr const char *kDirectionalSdf = R"( + + + 0 0 2 0 0 0 + true + 0.8 0.8 0.8 1 + 0.2 0.2 0.2 1 + + 1000 + 0.9 + 0.01 + 0.001 + + 0 0 -1 + + +)"; + +///////////////////////////////////////////////// +constexpr const char *kPointSdf = R"( + + + 0 0 2 0 0 0 + false + 0.5 0.5 0.5 1 + 0.5 0.5 0.5 1 + + 4 + 0.2 + 0.5 + 0.01 + + + +)"; + +///////////////////////////////////////////////// +constexpr const char *kSpotSdf = R"( + + + 0 0 2 0 0 0 + true + 0.5 0.5 0.5 1 + 0.5 0.5 0.5 1 + + 4 + 0.2 + 0.5 + 0.01 + + 0 0 -1 + + 0.1 + 0.5 + 0.8 + + + +)"; + +///////////////////////////////////////////////// +std::string ignition::gazebo::getPrimitiveShape(const PrimitiveShape &_type) +{ + switch(_type) + { + case PrimitiveShape::kBox: + return kBoxSdf; + case PrimitiveShape::kSphere: + return kSphereSdf; + case PrimitiveShape::kCylinder: + return kCylinderSdf; + case PrimitiveShape::kCapsule: + return kCapsuleSdf; + case PrimitiveShape::kEllipsoid: + return kEllipsoidSdf; + default: + return ""; + } +} + +///////////////////////////////////////////////// +std::string ignition::gazebo::getPrimitiveLight(const PrimitiveLight &_type) +{ + switch(_type) + { + case PrimitiveLight::kDirectional: + return kDirectionalSdf; + case PrimitiveLight::kPoint: + return kPointSdf; + case PrimitiveLight::kSpot: + return kSpotSdf; + default: + return ""; + } +} + +///////////////////////////////////////////////// +std::string ignition::gazebo::getPrimitive(const std::string &_typeName) +{ + std::string type = common::lowercase(_typeName); + + if (type == "box") + return getPrimitiveShape(PrimitiveShape::kBox); + else if (type == "sphere") + return getPrimitiveShape(PrimitiveShape::kSphere); + else if (type == "cylinder") + return getPrimitiveShape(PrimitiveShape::kCylinder); + else if (type == "capsule") + return getPrimitiveShape(PrimitiveShape::kCapsule); + else if (type == "ellipsoid") + return getPrimitiveShape(PrimitiveShape::kEllipsoid); + else if (type == "point") + return getPrimitiveLight(PrimitiveLight::kPoint); + else if (type == "directional") + return getPrimitiveLight(PrimitiveLight::kDirectional); + else if (type == "spot") + return getPrimitiveLight(PrimitiveLight::kSpot); + + ignwarn << "Invalid model string " << type << "\n"; + ignwarn << "The valid options are:\n"; + ignwarn << " - box\n"; + ignwarn << " - sphere\n"; + ignwarn << " - cylinder\n"; + ignwarn << " - capsule\n"; + ignwarn << " - ellipsoid\n"; + ignwarn << " - point\n"; + ignwarn << " - directional\n"; + ignwarn << " - spot\n"; + return ""; +} diff --git a/src/Primitives_TEST.cc b/src/Primitives_TEST.cc new file mode 100644 index 0000000000..b6635e6144 --- /dev/null +++ b/src/Primitives_TEST.cc @@ -0,0 +1,95 @@ +/* + * 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 + +using PrimitiveShape = ignition::gazebo::PrimitiveShape; +using PrimitiveLight = ignition::gazebo::PrimitiveLight; + +///////////////////////////////////////////////// +TEST(Primitives, shapes) +{ + auto primitives = { + PrimitiveShape::kBox, + PrimitiveShape::kSphere, + PrimitiveShape::kCylinder, + PrimitiveShape::kCapsule, + PrimitiveShape::kEllipsoid + }; + + for (auto prim : primitives) + { + auto sdfString = ignition::gazebo::getPrimitiveShape(prim); + ASSERT_FALSE(sdfString.empty()); + + /// Verify that string contains valid SDF + sdf::Root root; + auto errors = root.LoadSdfString(sdfString); + EXPECT_TRUE(errors.empty()) << sdfString; + } +} + +///////////////////////////////////////////////// +TEST(Primitives, lights) +{ + auto primitives = { + PrimitiveLight::kDirectional, + PrimitiveLight::kPoint, + PrimitiveLight::kSpot, + }; + + for (auto prim : primitives) + { + auto sdfString = ignition::gazebo::getPrimitiveLight(prim); + ASSERT_FALSE(sdfString.empty()); + + /// Verify that string contains valid SDF + sdf::Root root; + auto errors = root.LoadSdfString(sdfString); + EXPECT_TRUE(errors.empty()) << sdfString; + } +} + +///////////////////////////////////////////////// +TEST(Primitives, invalid) +{ + auto sdfString = ignition::gazebo::getPrimitive("foobar"); + ASSERT_TRUE(sdfString.empty()); +} + +///////////////////////////////////////////////// +TEST(Primitives, strings) +{ + auto primitives = { + "box", "sphere", "cylinder", "capsule", "ellipsoid", + "point", "directional", "spot" + }; + + for (auto prim : primitives) + { + auto sdfString = ignition::gazebo::getPrimitive(prim); + ASSERT_FALSE(sdfString.empty()); + + /// Verify that string contains valid SDF + sdf::Root root; + auto errors = root.LoadSdfString(sdfString); + EXPECT_TRUE(errors.empty()) << sdfString; + } +} diff --git a/src/gui/plugins/entity_tree/EntityTree.cc b/src/gui/plugins/entity_tree/EntityTree.cc index 4fc50c8adf..de909caa38 100644 --- a/src/gui/plugins/entity_tree/EntityTree.cc +++ b/src/gui/plugins/entity_tree/EntityTree.cc @@ -17,14 +17,18 @@ #include "EntityTree.hh" +#include #include #include #include +#include #include #include +#include #include #include +#include #include #include @@ -41,9 +45,11 @@ #include "ignition/gazebo/components/Sensor.hh" #include "ignition/gazebo/components/Visual.hh" #include "ignition/gazebo/components/World.hh" -#include "ignition/gazebo/EntityComponentManager.hh" #include "ignition/gazebo/gui/GuiEvents.hh" +#include "ignition/gazebo/EntityComponentManager.hh" +#include "ignition/gazebo/Primitives.hh" + namespace ignition::gazebo { class EntityTreePrivate @@ -459,6 +465,65 @@ void EntityTree::DeselectAllEntities() &event); } +///////////////////////////////////////////////// +void EntityTree::OnInsertEntity(const QString &_type) +{ + std::string modelSdfString = getPrimitive(_type.toStdString()); + ignition::gui::events::SpawnFromDescription event(modelSdfString); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &event); +} + +///////////////////////////////////////////////// +void EntityTree::OnLoadMesh(const QString &_mesh) +{ + std::string meshStr = _mesh.toStdString(); + if (QUrl(_mesh).isLocalFile()) + { + // mesh to sdf model + common::rtrim(meshStr); + + if (!common::MeshManager::Instance()->IsValidFilename(meshStr)) + { + QString errTxt = QString::fromStdString("Invalid URI: " + meshStr + + "\nOnly mesh file types DAE, OBJ, and STL are supported."); + return; + } + + std::string filename = common::basename(meshStr); + std::vector splitName = common::split(filename, "."); + + std::string sdf = "" + "" + "" + "" + "" + "" + "" + "" + meshStr + "" + "" + "" + "" + "" + "" + "" + "" + meshStr + "" + "" + "" + "" + "" + "" + ""; + + ignition::gui::events::SpawnFromDescription event(sdf); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &event); + + } +} + ///////////////////////////////////////////////// bool EntityTree::eventFilter(QObject *_obj, QEvent *_event) { diff --git a/src/gui/plugins/entity_tree/EntityTree.hh b/src/gui/plugins/entity_tree/EntityTree.hh index 092332913a..b899c12980 100644 --- a/src/gui/plugins/entity_tree/EntityTree.hh +++ b/src/gui/plugins/entity_tree/EntityTree.hh @@ -130,6 +130,14 @@ namespace gazebo /// This should be called from QML. public: Q_INVOKABLE void DeselectAllEntities(); + /// \brief Callback to insert a new entity + /// \param[in] _type Type of entity to insert + public: Q_INVOKABLE void OnInsertEntity(const QString &_type); + + /// \brief Callback to insert a new entity + /// \param[in] _type Type of entity to insert + public: Q_INVOKABLE void OnLoadMesh(const QString &_type); + // Documentation inherited protected: bool eventFilter(QObject *_obj, QEvent *_event) override; diff --git a/src/gui/plugins/entity_tree/EntityTree.qml b/src/gui/plugins/entity_tree/EntityTree.qml index 5e73519718..b0cf0d55a3 100644 --- a/src/gui/plugins/entity_tree/EntityTree.qml +++ b/src/gui/plugins/entity_tree/EntityTree.qml @@ -21,12 +21,13 @@ import QtQuick.Controls 2.2 import QtQuick.Controls.Material 2.1 import QtQuick.Layouts 1.3 import QtQuick.Controls.Styles 1.4 +import QtQuick.Dialogs 1.0 import IgnGazebo 1.0 as IgnGazebo Rectangle { id: entityTree - color: "transparent" - Layout.minimumWidth: 250 + color: lightGrey + Layout.minimumWidth: 400 Layout.minimumHeight: 375 anchors.fill: parent @@ -35,6 +36,20 @@ Rectangle { */ property int tooltipDelay: 500 + /** + * Dark grey according to theme + */ + property color darkGrey: (Material.theme == Material.Light) ? + Material.color(Material.Grey, Material.Shade200) : + Material.color(Material.Grey, Material.Shade900) + + /** + * Light grey according to theme + */ + property color lightGrey: (Material.theme == Material.Light) ? + Material.color(Material.Grey, Material.Shade100) : + Material.color(Material.Grey, Material.Shade800) + /** * Height of each item in pixels */ @@ -86,9 +101,160 @@ Rectangle { } } + Rectangle { + id: header + visible: true + height: addEntity.height + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + width: parent.width + color: darkGrey + + RowLayout { + anchors.fill: parent + spacing: 0 + + Label { + text: "Entity Tree" + font.capitalization: Font.Capitalize + color: Material.theme == Material.Light ? "#444444" : "#cccccc" + font.pointSize: 12 + padding: 5 + } + + ToolButton { + anchors.right: parent.right + id: addEntity + ToolTip.text: "Add Entity" + ToolTip.visible: hovered + contentItem: Image { + fillMode: Image.Pad + horizontalAlignment: Image.AlignHCenter + verticalAlignment: Image.AlignVCenter + source: "qrc:/Gazebo/images/plus.png" + sourceSize.width: 18; + sourceSize.height: 18; + } + onClicked: addEntityMenu.open() + + FileDialog { + id: loadFileDialog + title: "Load mesh" + folder: shortcuts.home + nameFilters: [ "Collada files (*.dae)", "(*.stl)", "(*.obj)" ] + selectMultiple: false + selectExisting: true + onAccepted: { + EntityTree.OnLoadMesh(fileUrl) + } + } + + Menu { + id: addEntityMenu + + MenuItem + { + id: box + text: "Box" + onClicked: { + EntityTree.OnInsertEntity("box") + } + } + + MenuItem + { + id: capsule + text: "Capsule" + onClicked: { + EntityTree.OnInsertEntity("capsule") + } + } + + MenuItem + { + id: cylinder + text: "Cylinder" + onClicked: { + EntityTree.OnInsertEntity("cylinder") + } + } + + MenuItem + { + id: ellipsoid + text: "Ellipsoid" + onClicked: { + EntityTree.OnInsertEntity("ellipsoid") + } + } + + MenuItem + { + id: sphere + text: "Sphere" + onClicked: { + EntityTree.OnInsertEntity("sphere") + } + } + + MenuItem + { + id: mesh + text: "Mesh" + onClicked: { + loadFileDialog.open() + } + } + + MenuSeparator { + padding: 0 + topPadding: 12 + bottomPadding: 12 + contentItem: Rectangle { + implicitWidth: 200 + implicitHeight: 1 + color: "#1E000000" + } + } + + MenuItem + { + id: directionalLight + text: "Directional" + onClicked: { + EntityTree.OnInsertEntity("directional") + } + } + + MenuItem + { + id: pointLight + text: "Point" + onClicked: { + EntityTree.OnInsertEntity("point") + } + } + + MenuItem + { + id: spotLight + text: "Spot" + onClicked: { + EntityTree.OnInsertEntity("spot") + } + } + } + } + } + } + TreeView { id: tree - anchors.fill: parent + anchors.top: header.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right model: EntityTreeModel selectionMode: SelectionMode.MultiSelection @@ -105,16 +271,20 @@ Rectangle { } style: TreeViewStyle { + frame: Rectangle { + border{ + color: lightGrey + } + } indentation: itemHeight * 0.75 headerDelegate: Rectangle { visible: false } - branchDelegate: Rectangle { height: itemHeight width: itemHeight * 0.75 - color: "transparent" + color: lightGrey Image { id: icon sourceSize.height: itemHeight * 0.4 diff --git a/src/gui/plugins/lights/Lights.cc b/src/gui/plugins/lights/Lights.cc index 929c773328..81ff6554ef 100644 --- a/src/gui/plugins/lights/Lights.cc +++ b/src/gui/plugins/lights/Lights.cc @@ -33,6 +33,7 @@ #include #include "ignition/gazebo/EntityComponentManager.hh" +#include "ignition/gazebo/Primitives.hh" namespace ignition::gazebo { @@ -65,85 +66,15 @@ void Lights::LoadConfig(const tinyxml2::XMLElement *) void Lights::OnNewLightClicked(const QString &_sdfString) { std::string modelSdfString = _sdfString.toStdString(); - std::transform(modelSdfString.begin(), modelSdfString.end(), - modelSdfString.begin(), ::tolower); + modelSdfString = getPrimitive(modelSdfString); - if (modelSdfString == "point") + if (!modelSdfString.empty()) { - modelSdfString = std::string("" - "" - "" - "0 0 2 0 0 0" - "false" - "0.5 0.5 0.5 1" - "0.5 0.5 0.5 1" - "" - "4" - "0.2" - "0.5" - "0.01" - "" - "" - ""); + ignition::gui::events::SpawnFromDescription event(modelSdfString); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &event); } - else if (modelSdfString == "directional") - { - modelSdfString = std::string("" - "" - "" - "0 0 2 0 0 0" - "true" - "0.8 0.8 0.8 1" - "0.2 0.2 0.2 1" - "" - "1000" - "0.9" - "0.01" - "0.001" - "" - "0 0 -1" - "" - ""); - } - else if (modelSdfString == "spot") - { - modelSdfString = std::string("" - "" - "" - "0 0 2 0 0 0" - "true" - "0.5 0.5 0.5 1" - "0.5 0.5 0.5 1" - "" - "4" - "0.2" - "0.5" - "0.01" - "" - "0 0 -1" - "" - "0.1" - "0.5" - "0.8" - "" - "" - ""); - } - else - { - ignwarn << "Invalid model string " << modelSdfString << "\n"; - ignwarn << "The valid options are:\n"; - ignwarn << " - point\n"; - ignwarn << " - directional\n"; - ignwarn << " - spot\n"; - return; - } - - ignition::gui::events::SpawnFromDescription event(modelSdfString); - ignition::gui::App()->sendEvent( - ignition::gui::App()->findChild(), - &event); } // Register this plugin diff --git a/src/gui/plugins/shapes/Shapes.cc b/src/gui/plugins/shapes/Shapes.cc index daed2743e0..acd25ee6d1 100644 --- a/src/gui/plugins/shapes/Shapes.cc +++ b/src/gui/plugins/shapes/Shapes.cc @@ -32,6 +32,8 @@ #include #include +#include + namespace ignition::gazebo { class ShapesPrivate @@ -72,209 +74,15 @@ void Shapes::LoadConfig(const tinyxml2::XMLElement *) void Shapes::OnMode(const QString &_mode) { std::string modelSdfString = _mode.toStdString(); - std::transform(modelSdfString.begin(), modelSdfString.end(), - modelSdfString.begin(), ::tolower); + modelSdfString = getPrimitive(modelSdfString); - if (modelSdfString == "box") - { - modelSdfString = std::string("" - "" - "" - "0 0 0.5 0 0 0" - "" - "" - "" - "0.16666" - "0" - "0" - "0.16666" - "0" - "0.16666" - "" - "1.0" - "" - "" - "" - "" - "1 1 1" - "" - "" - "" - "" - "" - "" - "1 1 1" - "" - "" - "" - "" - "" - ""); - } - else if (modelSdfString == "sphere") - { - modelSdfString = std::string("" - "" - "" - "0 0 0.5 0 0 0" - "" - "" - "" - "0.1" - "0" - "0" - "0.1" - "0" - "0.1" - "" - "1.0" - "" - "" - "" - "" - "0.5" - "" - "" - "" - "" - "" - "" - "0.5" - "" - "" - "" - "" - "" - ""); - } - else if (modelSdfString == "cylinder") - { - modelSdfString = std::string("" - "" - "" - "0 0 0.5 0 0 0" - "" - "" - "" - "0.1458" - "0" - "0" - "0.1458" - "0" - "0.125" - "" - "1.0" - "" - "" - "" - "" - "0.5" - "1.0" - "" - "" - "" - "" - "" - "" - "0.5" - "1.0" - "" - "" - "" - "" - "" - ""); - } - else if (modelSdfString == "capsule") - { - modelSdfString = std::string("" - "" - "" - "0 0 0.5 0 0 0" - "" - "" - "" - "0.074154" - "0" - "0" - "0.074154" - "0" - "0.018769" - "" - "1.0" - "" - "" - "" - "" - "0.2" - "0.6" - "" - "" - "" - "" - "" - "" - "0.2" - "0.6" - "" - "" - "" - "" - "" - ""); - } - else if (modelSdfString == "ellipsoid") + if (!modelSdfString.empty()) { - modelSdfString = std::string("" - "" - "" - "0 0 0.5 0 0 0" - "" - "" - "" - "0.068" - "0" - "0" - "0.058" - "0" - "0.026" - "" - "1.0" - "" - "" - "" - "" - "0.2 0.3 0.5" - "" - "" - "" - "" - "" - "" - "0.2 0.3 0.5" - "" - "" - "" - "" - "" - ""); + ignition::gui::events::SpawnFromDescription event(modelSdfString); + ignition::gui::App()->sendEvent( + ignition::gui::App()->findChild(), + &event); } - else - { - ignwarn << "Invalid model string " << modelSdfString << "\n"; - ignwarn << "The valid options are:\n"; - ignwarn << " - box\n"; - ignwarn << " - sphere\n"; - ignwarn << " - capsule\n"; - ignwarn << " - cylinder\n"; - ignwarn << " - ellipsoid\n"; - return; - } - - ignition::gui::events::SpawnFromDescription event(modelSdfString); - ignition::gui::App()->sendEvent( - ignition::gui::App()->findChild(), - &event); } // Register this plugin