Skip to content

Commit ae1a048

Browse files
adlarkinchapulina
andauthored
Add support for cloning entities (#959)
Signed-off-by: Ashton Larkin <[email protected]> Signed-off-by: Louise Poubel <[email protected]> Co-authored-by: Louise Poubel <[email protected]>
1 parent 2c2605f commit ae1a048

File tree

11 files changed

+589
-63
lines changed

11 files changed

+589
-63
lines changed

include/ignition/gazebo/EntityComponentManager.hh

+48
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <typeinfo>
2929
#include <type_traits>
3030
#include <unordered_set>
31+
#include <unordered_map>
3132
#include <utility>
3233
#include <vector>
3334

@@ -74,6 +75,38 @@ namespace ignition
7475
/// \return An id for the Entity, or kNullEntity on failure.
7576
public: Entity CreateEntity();
7677

78+
/// \brief Clone an entity and its components. If the entity has any child
79+
/// entities, they will also be cloned.
80+
/// When cloning entities, the following rules apply:
81+
/// 1. The name component of a cloned entity will consist of a unique
82+
/// name, since all entities should have a unique name.
83+
/// 2. Cloned entities that have a canonical link will have their
84+
/// canonical link set to the cloned canonical link, not the original
85+
/// canonical link.
86+
/// 3. Child entities that are cloned will have their parent set to the
87+
/// cloned parent entity.
88+
/// 4. Aside from the changes listed above, all other cloned components
89+
/// remain unchanged.
90+
/// \param[in] _entity The entity to clone.
91+
/// \param[in] _parent The parent of the cloned entity. Set this to
92+
/// kNullEntity if the cloned entity should not have a parent.
93+
/// \param[in] _name The name that should be given to the cloned entity.
94+
/// Set this to an empty string if the cloned entity name should be
95+
/// auto-generated to something unique.
96+
/// \param[in] _allowRename True if _name can be modified to be a unique
97+
/// name if it isn't already a unique name. False if _name cannot be
98+
/// modified to be a unique name. If _allowRename is set to False, and
99+
/// _name is not unique, _entity will not be cloned. If _name is an
100+
/// empty string, _allowRename is ignored since the cloned entity will
101+
/// have an auto-generated unique name.
102+
/// \return The cloned entity, which will have a unique name. kNullEntity
103+
/// is returned if cloning failed. Failure could occur if _entity does not
104+
/// exist, or if a unique name could not be generated for the entity to be
105+
/// cloned.
106+
/// \sa Clone
107+
public: Entity Clone(Entity _entity, Entity _parent,
108+
const std::string &_name, bool _allowRename);
109+
77110
/// \brief Get the number of entities on the server.
78111
/// \return Entity count.
79112
public: size_t EntityCount() const;
@@ -333,6 +366,21 @@ namespace ignition
333366
private: template <typename T>
334367
struct identity; // NOLINT
335368

369+
/// \brief Helper function for cloning an entity and its children (this
370+
/// includes cloning components attached to these entities). This method
371+
/// should never be called directly - it is called internally from the
372+
/// public Clone method.
373+
/// \param[in] _entity The entity to clone.
374+
/// \param[in] _parent The parent of the cloned entity.
375+
/// \param[in] _name The name that should be given to the cloned entity.
376+
/// \param[in] _allowRename True if _name can be modified to be a unique
377+
/// name if it isn't already a unique name. False if _name cannot be
378+
/// modified to be a unique name.
379+
/// \return The cloned entity. kNullEntity is returned if cloning failed.
380+
/// \sa Clone
381+
private: Entity CloneImpl(Entity _entity, Entity _parent,
382+
const std::string &_name, bool _allowRename);
383+
336384
/// \brief A version of Each() that doesn't use a cache. The cached
337385
/// version, Each(), is preferred.
338386
/// Get all entities which contain given component types, as well

include/ignition/gazebo/components/Component.hh

+28
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ namespace components
279279
/// Factory registration and is guaranteed to be the same across compilers
280280
/// and runs.
281281
public: virtual ComponentTypeId TypeId() const = 0;
282+
283+
/// \brief Clone the component.
284+
/// \return A pointer to the component.
285+
public: virtual std::unique_ptr<BaseComponent> Clone() = 0;
282286
};
283287

284288
/// \brief A component type that wraps any data type. The intention is for
@@ -342,6 +346,9 @@ namespace components
342346
/// \return True if different.
343347
public: bool operator!=(const Component &_component) const;
344348

349+
// Documentation inherited
350+
public: std::unique_ptr<BaseComponent> Clone() override;
351+
345352
// Documentation inherited
346353
public: ComponentTypeId TypeId() const override;
347354

@@ -408,6 +415,9 @@ namespace components
408415
public: bool operator!=(const Component<NoData, Identifier,
409416
Serializer> &_component) const;
410417

418+
// Documentation inherited
419+
public: std::unique_ptr<BaseComponent> Clone() override;
420+
411421
// Documentation inherited
412422
public: ComponentTypeId TypeId() const override;
413423

@@ -490,6 +500,16 @@ namespace components
490500
Serializer::Deserialize(_in, this->Data());
491501
}
492502

503+
//////////////////////////////////////////////////
504+
template <typename DataType, typename Identifier, typename Serializer>
505+
std::unique_ptr<BaseComponent>
506+
Component<DataType, Identifier, Serializer>::Clone()
507+
{
508+
Component<DataType, Identifier, Serializer> clonedComp(this->Data());
509+
return std::make_unique<Component<DataType, Identifier, Serializer>>(
510+
clonedComp);
511+
}
512+
493513
//////////////////////////////////////////////////
494514
template <typename DataType, typename Identifier, typename Serializer>
495515
ComponentTypeId Component<DataType, Identifier, Serializer>::TypeId() const
@@ -513,6 +533,14 @@ namespace components
513533
return false;
514534
}
515535

536+
//////////////////////////////////////////////////
537+
template <typename Identifier, typename Serializer>
538+
std::unique_ptr<BaseComponent>
539+
Component<NoData, Identifier, Serializer>::Clone()
540+
{
541+
return std::make_unique<Component<NoData, Identifier, Serializer>>();
542+
}
543+
516544
//////////////////////////////////////////////////
517545
template <typename Identifier, typename Serializer>
518546
ComponentTypeId Component<NoData, Identifier, Serializer>::TypeId() const

include/ignition/gazebo/rendering/SceneManager.hh

+7-3
Original file line numberDiff line numberDiff line change
@@ -177,26 +177,30 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {
177177
/// \brief Create an actor
178178
/// \param[in] _id Unique actor id
179179
/// \param[in] _actor Actor sdf dom
180+
/// \param[in] _name Actor's name
180181
/// \param[in] _parentId Parent id
181182
/// \return Actor object created from the sdf dom
182183
public: rendering::VisualPtr CreateActor(Entity _id,
183-
const sdf::Actor &_actor, Entity _parentId = 0);
184+
const sdf::Actor &_actor, const std::string &_name,
185+
Entity _parentId = 0);
184186

185187
/// \brief Create a light
186188
/// \param[in] _id Unique light id
187189
/// \param[in] _light Light sdf dom
190+
/// \param[in] _name Light's name
188191
/// \param[in] _parentId Parent id
189192
/// \return Light object created from the sdf dom
190193
public: rendering::LightPtr CreateLight(Entity _id,
191-
const sdf::Light &_light, Entity _parentId);
194+
const sdf::Light &_light, const std::string &_name, Entity _parentId);
192195

193196
/// \brief Create a light
194197
/// \param[in] _id Unique light id
195198
/// \param[in] _light Light sdf dom
199+
/// \param[in] _name Light's name
196200
/// \param[in] _parentId Parent id
197201
/// \return Light object created from the sdf dom
198202
public: rendering::VisualPtr CreateLightVisual(Entity _id,
199-
const sdf::Light &_light, Entity _parentId);
203+
const sdf::Light &_light, const std::string &_name, Entity _parentId);
200204

201205
/// \brief Create a particle emitter.
202206
/// \param[in] _id Unique particle emitter id

src/Component_TEST.cc

+42
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ class NoSerialize : public components::BaseComponent
177177
{
178178
return 0;
179179
}
180+
181+
public: std::unique_ptr<BaseComponent> Clone() override
182+
{
183+
return nullptr;
184+
}
180185
};
181186

182187
//////////////////////////////////////////////////
@@ -550,3 +555,40 @@ TEST_F(ComponentTest, TypeName)
550555
EXPECT_EQ("123456", comp.typeName);
551556
}
552557
}
558+
559+
//////////////////////////////////////////////////
560+
TEST_F(ComponentTest, Clone)
561+
{
562+
// Component with data
563+
{
564+
using Custom = components::Component<int, class CustomTag>;
565+
566+
// create a component and a clone of it. The clone should initially have the
567+
// same data as the original component
568+
Custom comp(5);
569+
auto clonedComp = comp.Clone();
570+
auto derivedClone = static_cast<Custom *>(clonedComp.get());
571+
EXPECT_EQ(comp, *derivedClone);
572+
573+
// modify the data of the cloned component, and make sure that only the
574+
// cloned component is modified, not the original component
575+
derivedClone->Data() = 10;
576+
EXPECT_NE(comp, *derivedClone);
577+
EXPECT_EQ(5, comp.Data());
578+
EXPECT_EQ(10, derivedClone->Data());
579+
}
580+
581+
// Component without data
582+
{
583+
using Custom = components::Component<components::NoData, class CustomTag>;
584+
585+
Custom comp;
586+
auto clonedComp = comp.Clone();
587+
auto derivedClone = static_cast<Custom *>(clonedComp.get());
588+
589+
// since this component has no data, we cannot do the same check as we did
590+
// above for a component with data. However, we can make sure that the
591+
// pointers for the components are different
592+
EXPECT_NE(&comp, derivedClone);
593+
}
594+
}

0 commit comments

Comments
 (0)