diff --git a/include/ignition/gazebo/EntityComponentManager.hh b/include/ignition/gazebo/EntityComponentManager.hh index da70f606ea..768432498d 100644 --- a/include/ignition/gazebo/EntityComponentManager.hh +++ b/include/ignition/gazebo/EntityComponentManager.hh @@ -214,6 +214,19 @@ namespace ignition public: template ComponentTypeT *Component(const ComponentKey &_key); + /// \brief Get a mutable component assigned to an entity based on a + /// component type. If the component doesn't exist, create it and + /// initialize with the given default value. + /// \param[in] _entity The entity. + /// \param[in] _default The value that should be used to construct + /// the component in case the component doesn't exist. + /// \return The component of the specified type assigned to the specified + /// entity. + public: template + ComponentTypeT *ComponentDefault(Entity _entity, + const typename ComponentTypeT::Type &_default = + typename ComponentTypeT::Type()); + /// \brief Get the data from a component. /// * If the component type doesn't hold any data, this won't compile. /// * If the entity doesn't have that component, it will return nullopt. diff --git a/include/ignition/gazebo/detail/EntityComponentManager.hh b/include/ignition/gazebo/detail/EntityComponentManager.hh index 880dba745c..dcdb37324b 100644 --- a/include/ignition/gazebo/detail/EntityComponentManager.hh +++ b/include/ignition/gazebo/detail/EntityComponentManager.hh @@ -127,6 +127,20 @@ ComponentTypeT *EntityComponentManager::Component(const ComponentKey &_key) this->ComponentImplementation(_key)); } +////////////////////////////////////////////////// +template +ComponentTypeT *EntityComponentManager::ComponentDefault(Entity _entity, + const typename ComponentTypeT::Type &_default) +{ + auto comp = this->Component(_entity); + if (!comp) + { + this->CreateComponent(_entity, ComponentTypeT(_default)); + comp = this->Component(_entity); + } + return comp; +} + ////////////////////////////////////////////////// template std::optional diff --git a/src/EntityComponentManager_TEST.cc b/src/EntityComponentManager_TEST.cc index b29fb53aef..cf42727bdd 100644 --- a/src/EntityComponentManager_TEST.cc +++ b/src/EntityComponentManager_TEST.cc @@ -437,6 +437,31 @@ TEST_P(EntityComponentManagerFixture, EntitiesAndComponents) EXPECT_FALSE(manager.EntityHasComponentType(entity, DoubleComponent::typeId)); EXPECT_FALSE(manager.EntityHasComponentType(entity2, IntComponent::typeId)); + // Query non-existing component, the default value is default-constructed + BoolComponent *boolComp = manager.ComponentDefault(entity); + ASSERT_NE(nullptr, boolComp); + EXPECT_TRUE(manager.HasComponentType(BoolComponent::typeId)); + EXPECT_TRUE(manager.EntityHasComponentType(entity, BoolComponent::typeId)); + EXPECT_EQ(false, boolComp->Data()); + + // Query non-existing component, the default value is used + DoubleComponent *doubleComp = + manager.ComponentDefault(entity, 1.0); + ASSERT_NE(nullptr, doubleComp); + EXPECT_TRUE(manager.HasComponentType(DoubleComponent::typeId)); + EXPECT_TRUE(manager.EntityHasComponentType(entity, IntComponent::typeId)); + EXPECT_TRUE(manager.EntityHasComponentType(entity, DoubleComponent::typeId)); + EXPECT_FALSE( + manager.EntityHasComponentType(entity2, DoubleComponent::typeId)); + EXPECT_FLOAT_EQ(1.0, doubleComp->Data()); + + // Query existing component, the default value is not used + IntComponent *intComp = manager.ComponentDefault(entity, 124); + ASSERT_NE(nullptr, intComp); + EXPECT_TRUE(manager.HasComponentType(IntComponent::typeId)); + EXPECT_TRUE(manager.EntityHasComponentType(entity, IntComponent::typeId)); + EXPECT_EQ(123, intComp->Data()); + // Remove all entities manager.RequestRemoveEntities(); EXPECT_EQ(3u, manager.EntityCount());