Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System inspector GUI widget #1404

Merged
merged 8 commits into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/ignition/gazebo/Conversions.hh
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,22 @@ namespace ignition
/// \return Particle emitter message.
template<>
sdf::ParticleEmitter convert(const msgs::ParticleEmitter &_in);

/// \brief Generic conversion from an SDF element to another type.
/// \param[in] _in SDF element.
/// \return Conversion result.
/// \tparam Out Output type.
template<class Out>
Out convert(const sdf::Element &/*_in*/)
{
Out::ConversionNotImplemented;
}

/// \brief Specialized conversion from an SDF element to a plugin message.
/// \param[in] _in SDF element.
/// \return Plugin message.
template<>
msgs::Plugin convert(const sdf::Element &_in);
chapulina marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions include/ignition/gazebo/components/SystemInfo.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2022 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_COMPONENTS_SYSTEMINFO_HH_
#define IGNITION_GAZEBO_COMPONENTS_SYSTEMINFO_HH_

#include <ignition/msgs/plugin_v.pb.h>
#include <ignition/gazebo/components/Factory.hh>
#include <ignition/gazebo/components/Component.hh>
#include <ignition/gazebo/components/Serialization.hh>
#include <ignition/gazebo/config.hh>

namespace ignition
{
namespace gazebo
{
// Inline bracket to help doxygen filtering.
inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {
namespace components
{
/// \brief This component holds information about all the systems that are
/// attached to an entity. The content of each system is populated the moment
/// the plugin is instantiated and isn't modified throughout simulation.
using SystemInfo = Component<msgs::Plugin_V, class SystemInfoTag,
serializers::MsgSerializer>;
IGN_GAZEBO_REGISTER_COMPONENT("ign_gazebo_components.SystemInfo", SystemInfo)
}
}
}
}

#endif
39 changes: 29 additions & 10 deletions src/Conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -681,16 +681,7 @@ msgs::GUI ignition::gazebo::convert(const sdf::Gui &_in)
while (pluginElem)
{
auto pluginMsg = out.add_plugin();
pluginMsg->set_name(pluginElem->Get<std::string>("name"));
pluginMsg->set_filename(pluginElem->Get<std::string>("filename"));

std::stringstream ss;
for (auto innerElem = pluginElem->GetFirstElement();
innerElem; innerElem = innerElem->GetNextElement(""))
{
ss << innerElem->ToString("");
}
pluginMsg->set_innerxml(ss.str());
pluginMsg->CopyFrom(convert<msgs::Plugin>(*(pluginElem.get())));
pluginElem = pluginElem->GetNextElement("plugin");
}
}
Expand Down Expand Up @@ -1722,3 +1713,31 @@ sdf::ParticleEmitter ignition::gazebo::convert(const msgs::ParticleEmitter &_in)

return out;
}

//////////////////////////////////////////////////
template<>
IGNITION_GAZEBO_VISIBLE
msgs::Plugin ignition::gazebo::convert(const sdf::Element &_in)
{
msgs::Plugin result;

if (_in.GetName() != "plugin")
{
ignerr << "Tried to convert SDF [" << _in.GetName() <<
"] into [plugin]" << std::endl;
chapulina marked this conversation as resolved.
Show resolved Hide resolved
return result;
}

result.set_name(_in.Get<std::string>("name"));
result.set_filename(_in.Get<std::string>("filename"));

std::stringstream ss;
for (auto innerElem = _in.GetFirstElement(); innerElem;
innerElem = innerElem->GetNextElement(""))
{
ss << innerElem->ToString("");
}
result.set_innerxml(ss.str());

return result;
}
29 changes: 29 additions & 0 deletions src/Conversions_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <sdf/Box.hh>
#include <sdf/Capsule.hh>
#include <sdf/Cylinder.hh>
#include <sdf/Element.hh>
#include <sdf/Ellipsoid.hh>
#include <sdf/Gui.hh>
#include <sdf/Heightmap.hh>
Expand Down Expand Up @@ -1025,3 +1026,31 @@ TEST(Conversions, ParticleEmitter)
EXPECT_EQ(emitter2.RawPose(), emitter.RawPose());
EXPECT_FLOAT_EQ(emitter2.ScatterRatio(), emitter.ScatterRatio());
}

/////////////////////////////////////////////////
TEST(Conversions, PluginElement)
{
sdf::Root root;
root.LoadSdfString("<?xml version='1.0'?><sdf version='1.6'>"
"<world name='default'>"
" <plugin filename='plum' name='peach'>"
" <avocado>0.5</avocado>"
" </plugin>"
"</world></sdf>");

auto world = root.WorldByIndex(0);
ASSERT_NE(nullptr, world);

auto worldElem = world->Element();
ASSERT_NE(nullptr, worldElem);

auto pluginElem = worldElem->GetElement("plugin");
ASSERT_NE(nullptr, pluginElem);

auto pluginMsg = convert<msgs::Plugin>(*(pluginElem.get()));
EXPECT_EQ("plum", pluginMsg.filename());
EXPECT_EQ("peach", pluginMsg.name());

EXPECT_NE(pluginMsg.innerxml().find("<avocado>0.5</avocado>"),
std::string::npos);
}
44 changes: 34 additions & 10 deletions src/SystemManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*
*/

#include "ignition/gazebo/components/SystemInfo.hh"
#include "ignition/gazebo/Conversions.hh"
#include "SystemManager.hh"

using namespace ignition;
Expand Down Expand Up @@ -120,6 +122,29 @@ void SystemManager::AddSystemImpl(
SystemInternal _system,
std::shared_ptr<const sdf::Element> _sdf)
{
// Add component
if (this->entityCompMgr && kNullEntity != _system.parentEntity)
{
msgs::Plugin_V systemInfoMsg;
auto systemInfoComp =
this->entityCompMgr->Component<components::SystemInfo>(
_system.parentEntity);
if (systemInfoComp)
{
systemInfoMsg = systemInfoComp->Data();
}
if (_sdf)
{
auto pluginMsg = systemInfoMsg.add_plugins();
pluginMsg->CopyFrom(convert<msgs::Plugin>(*_sdf.get()));
}

this->entityCompMgr->SetComponentData<components::SystemInfo>(
_system.parentEntity, systemInfoMsg);
this->entityCompMgr->SetChanged(_system.parentEntity,
components::SystemInfo::typeId);
}

// Configure the system, if necessary
if (_system.configure && this->entityCompMgr && this->eventMgr)
{
Expand Down Expand Up @@ -160,16 +185,15 @@ const std::vector<ISystemPostUpdate *>& SystemManager::SystemsPostUpdate()
//////////////////////////////////////////////////
std::vector<SystemInternal> SystemManager::TotalByEntity(Entity _entity)
{
auto checkEntity = [&](const SystemInternal &_system)
{
return _system.parentEntity == _entity;
};

std::vector<SystemInternal> result;
for (auto system : this->systems)
{
if (system.parentEntity == _entity)
result.push_back(system);
}
for (auto system : this->pendingSystems)
{
if (system.parentEntity == _entity)
result.push_back(system);
}
std::copy_if(this->systems.begin(), this->systems.end(),
std::back_inserter(result), checkEntity);
std::copy_if(this->pendingSystems.begin(), this->pendingSystems.end(),
std::back_inserter(result), checkEntity);
return result;
}
58 changes: 58 additions & 0 deletions src/SystemManager_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "ignition/gazebo/System.hh"
#include "ignition/gazebo/SystemLoader.hh"
#include "ignition/gazebo/Types.hh"
#include "ignition/gazebo/components/SystemInfo.hh"
#include "ignition/gazebo/test_config.hh" // NOLINT(build/include)

#include "SystemManager.hh"
Expand Down Expand Up @@ -202,3 +203,60 @@ TEST(SystemManager, AddSystemEcm)
EXPECT_EQ(1u, systemMgr.SystemsPostUpdate().size());
}

/////////////////////////////////////////////////
TEST(SystemManager, AddSystemWithInfo)
{
auto loader = std::make_shared<SystemLoader>();

EntityComponentManager ecm;
auto entity = ecm.CreateEntity();
EXPECT_NE(kNullEntity, entity);

auto eventManager = EventManager();

SystemManager systemMgr(loader, &ecm, &eventManager);

// No element, no SystemInfo component
auto configSystem = std::make_shared<SystemWithConfigure>();
systemMgr.AddSystem(configSystem, entity, nullptr);

// Element becomes SystemInfo component
auto pluginElem = std::make_shared<sdf::Element>();
sdf::initFile("plugin.sdf", pluginElem);
sdf::readString("<?xml version='1.0'?><sdf version='1.6'>"
" <plugin filename='plum' name='peach'>"
" <avocado>0.5</avocado>"
" </plugin>"
"</sdf>", pluginElem);

auto updateSystem = std::make_shared<SystemWithUpdates>();
systemMgr.AddSystem(updateSystem, entity, pluginElem);

int entityCount{0};
ecm.Each<components::SystemInfo>(
[&](const Entity &_entity,
const components::SystemInfo *_systemInfoComp) -> bool
{
EXPECT_EQ(entity, _entity);

EXPECT_NE(nullptr, _systemInfoComp);
if (nullptr == _systemInfoComp)
return true;

auto pluginsMsg = _systemInfoComp->Data();
EXPECT_EQ(1, pluginsMsg.plugins().size());
if (1u != pluginsMsg.plugins().size())
return true;

auto pluginMsg = pluginsMsg.plugins(0);
EXPECT_EQ("plum", pluginMsg.filename());
EXPECT_EQ("peach", pluginMsg.name());
EXPECT_NE(pluginMsg.innerxml().find("<avocado>0.5</avocado>"),
std::string::npos);

entityCount++;
return true;
});
EXPECT_EQ(1, entityCount);
}

2 changes: 2 additions & 0 deletions src/gui/plugins/component_inspector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ gz_add_gui_plugin(ComponentInspector
SOURCES
ComponentInspector.cc
Pose3d.cc
SystemInfo.cc
QT_HEADERS
ComponentInspector.hh
Pose3d.hh
SystemInfo.hh
)
6 changes: 6 additions & 0 deletions src/gui/plugins/component_inspector/ComponentInspector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#include "ignition/gazebo/components/SourceFilePath.hh"
#include "ignition/gazebo/components/SphericalCoordinates.hh"
#include "ignition/gazebo/components/Static.hh"
#include "ignition/gazebo/components/SystemInfo.hh"
#include "ignition/gazebo/components/ThreadPitch.hh"
#include "ignition/gazebo/components/Transparency.hh"
#include "ignition/gazebo/components/Visual.hh"
Expand All @@ -73,6 +74,7 @@

#include "ComponentInspector.hh"
#include "Pose3d.hh"
#include "SystemInfo.hh"

namespace ignition::gazebo
{
Expand Down Expand Up @@ -114,6 +116,9 @@ namespace ignition::gazebo

/// \brief Handles all components displayed as a 3D pose.
public: std::unique_ptr<inspector::Pose3d> pose3d;

/// \brief Handles all system info components.
public: std::unique_ptr<inspector::SystemInfo> systemInfo;
};
}

Expand Down Expand Up @@ -475,6 +480,7 @@ void ComponentInspector::LoadConfig(const tinyxml2::XMLElement *)

// Type-specific handlers
this->dataPtr->pose3d = std::make_unique<inspector::Pose3d>(this);
this->dataPtr->systemInfo = std::make_unique<inspector::SystemInfo>(this);
}

//////////////////////////////////////////////////
Expand Down
8 changes: 8 additions & 0 deletions src/gui/plugins/component_inspector/ComponentInspector.qml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ Rectangle {

delegate: Loader {
id: loader

/**
* Most items can access model.data directly, but items like ListView,
* which have their own `model` property, can't. They can use
* `componentData` instead.
*/
property var componentData: model.data

source: delegateQml(model)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<file>Pose3d.qml</file>
<file>SphericalCoordinates.qml</file>
<file>String.qml</file>
<file>SystemInfo.qml</file>
<file>TypeHeader.qml</file>
<file>Vector3d.qml</file>
<file>plottable_icon.svg</file>
Expand Down
Loading