Gazebo Sim

API Reference

8.15.0
EntityFeatureMap.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2021 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #ifndef GZ_SIM_SYSTEMS_PHYSICS_ENTITY_FEATURE_MAP_HH_
19 #define GZ_SIM_SYSTEMS_PHYSICS_ENTITY_FEATURE_MAP_HH_
20 
21 #include <tuple>
22 #include <type_traits>
23 #include <unordered_map>
24 
25 #include <gz/physics/Entity.hh>
26 #include <gz/physics/FindFeatures.hh>
27 #include <gz/physics/FeatureList.hh>
28 #include <gz/physics/RequestFeatures.hh>
29 
30 #include "gz/sim/Entity.hh"
31 
32 namespace gz::sim
33 {
34 inline namespace GZ_SIM_VERSION_NAMESPACE {
35 namespace systems::physics_system
36 {
37  // \brief Helper class that associates Gazebo entities with Physics entities
38  // with required and optional features. It can be used to cast a physics
39  // entity with the required features to another physics entity with one of
40  // the optional features. This class was created to keep all physics entities
41  // in one place so that when a gazebo entity is removed, all the mapped
42  // physics entitities can be removed at the same time. This ensures that
43  // reference counts are properly zeroed out in the underlying physics engines
44  // and the memory associated with the physics entities can be freed.
45  //
46  // DEV WARNING: There is an implicit conversion between physics EntityPtr and
47  // std::size_t in gz-physics. This seems also implicitly convert between
48  // EntityPtr and gazebo Entity. Therefore, any member function that takes a
49  // gazebo Entity can accidentally take an EntityPtr. To prevent this, for
50  // every function that takes a gazebo Entity, we should always have an
51  // overload that also takes an EntityPtr with required features. We can do
52  // this because there's a 1:1 mapping between the two in maps contained in
53  // this class.
54  //
55  // \tparam PhysicsEntityT Type of entity, such as World, Model, or Link
56  // \tparam PolicyT Policy of the physics engine (2D, 3D)
57  // \tparam RequiredFeatureList Required features of the physics entity
58  // \tparam OptionalFeatureLists One or more optional feature lists of the
59  // physics entity.
60  template <template <typename, typename> class PhysicsEntityT,
61  typename PolicyT, typename RequiredFeatureList,
62  typename... OptionalFeatureLists>
64  {
67  public: template <typename T>
68  using PhysicsEntityPtr = physics::EntityPtr<PhysicsEntityT<PolicyT, T>>;
69 
72 
75  public: template <typename T>
77  std::disjunction<std::is_same<T, OptionalFeatureLists>...>;
78 
82  private: using ValueType =
85 
95  public: template <typename ToFeatureList>
97  EntityCast(sim::Entity _entity) const
98  {
99  // Using constexpr to limit compiler error message to the static_assert
100  // cppcheck-suppress syntaxError
101  if constexpr (!HasFeatureList<ToFeatureList>::value) // NOLINT
102  {
104  "Trying to cast to a FeatureList not included in the "
105  "optional FeatureLists of this map.");
106  return nullptr;
107  }
108  else
109  {
110  using ToEntityPtr = PhysicsEntityPtr<ToFeatureList>;
111  // Has already been cast
112  auto castIt = this->castCache.find(_entity);
113  if (castIt != this->castCache.end())
114  {
115  auto castEntity = std::get<ToEntityPtr>(castIt->second.entities);
116  if (nullptr != castEntity)
117  {
118  return castEntity;
119  }
120  // A failed cast means the engine doesn't implement ToFeatureList,
121  // which can't change at runtime. Don't retry it on every call: a
122  // cast instantiates a plugin and looks up its interfaces by name.
123  if (std::get<FailedCast<ToFeatureList>>(castIt->second.failed).value)
124  {
125  return nullptr;
126  }
127  }
128 
129  auto reqEntity = this->Get(_entity);
130  if (nullptr == reqEntity)
131  {
132  return nullptr;
133  }
134 
135  // Cast
136  auto castEntity = physics::RequestFeatures<ToFeatureList>::From(
137  this->Get(_entity));
138 
139  auto &cached = this->castCache[_entity];
140  if (castEntity)
141  {
142  std::get<ToEntityPtr>(cached.entities) = castEntity;
143  }
144  else
145  {
146  std::get<FailedCast<ToFeatureList>>(cached.failed).value = true;
147  }
148 
149  return castEntity;
150  }
151  }
152 
161  public: template <typename ToFeatureList>
162  PhysicsEntityPtr<ToFeatureList>
163  EntityCast(const RequiredEntityPtr &_physicsEntity) const
164  {
165  auto gzEntity = this->Get(_physicsEntity);
166  if (kNullEntity == gzEntity)
167  {
168  return nullptr;
169  }
170  return this->EntityCast<ToFeatureList>(gzEntity);
171  }
172 
178  public: RequiredEntityPtr Get(const Entity &_entity) const
179  {
180  auto it = this->entityMap.find(_entity);
181  if (it != this->entityMap.end())
182  {
183  return it->second;
184  }
185  return nullptr;
186  }
187 
193  public: Entity Get(const RequiredEntityPtr &_physEntity) const
194  {
195  auto it = this->reverseMap.find(_physEntity);
196  if (it != this->reverseMap.end())
197  {
198  return it->second;
199  }
200  return kNullEntity;
201  }
202 
209  {
210  auto it = this->physEntityById.find(_id);
211  if (it != this->physEntityById.end())
212  {
213  return it->second;
214  }
215  return nullptr;
216  }
217 
222  public: Entity GetByPhysicsId(std::size_t _id) const
223  {
224  auto it = this->entityByPhysId.find(_id);
225  if (it != this->entityByPhysId.end())
226  {
227  return it->second;
228  }
229  return kNullEntity;
230  }
231 
237  public: bool HasEntity(const Entity &_entity) const
238  {
239  return this->entityMap.find(_entity) != this->entityMap.end();
240  }
241 
247  public: bool HasEntity(const RequiredEntityPtr &_physicsEntity) const
248  {
249  return this->reverseMap.find(_physicsEntity) != this->reverseMap.end();
250  }
251 
255  public: void AddEntity(const Entity &_entity,
256  const RequiredEntityPtr &_physicsEntity)
257  {
258  this->entityMap[_entity] = _physicsEntity;
259  this->reverseMap[_physicsEntity] = _entity;
260  this->physEntityById[_physicsEntity->EntityID()] = _physicsEntity;
261  this->entityByPhysId[_physicsEntity->EntityID()] = _entity;
262  }
263 
267  public: bool Remove(Entity _entity)
268  {
269  auto it = this->entityMap.find(_entity);
270  if (it != this->entityMap.end())
271  {
272  this->reverseMap.erase(it->second);
273  this->physEntityById.erase(it->second->EntityID());
274  this->entityByPhysId.erase(it->second->EntityID());
275  this->castCache.erase(_entity);
276  this->entityMap.erase(it);
277  return true;
278  }
279  return false;
280  }
281 
285  public: bool Remove(const RequiredEntityPtr &_physicsEntity)
286  {
287  auto it = this->reverseMap.find(_physicsEntity);
288  if (it != this->reverseMap.end())
289  {
290  this->entityMap.erase(it->second);
291  this->physEntityById.erase(it->first->EntityID());
292  this->entityByPhysId.erase(it->first->EntityID());
293  this->castCache.erase(it->second);
294  this->reverseMap.erase(it);
295  return true;
296  }
297  return false;
298  }
299 
304  {
305  return this->entityMap;
306  }
307 
312  {
313  return this->entityMap.size() + this->reverseMap.size() +
314  this->castCache.size() + this->physEntityById.size() +
315  this->entityByPhysId.size();
316  }
317 
320 
323 
327 
329  private: std::unordered_map<std::size_t, Entity> entityByPhysId;
330 
333  private: template <typename T>
334  struct FailedCast
335  {
336  bool value{false};
337  };
338 
341  private: struct CastCacheEntry
342  {
343  ValueType entities;
345  };
346 
349  private: mutable std::unordered_map<Entity, CastCacheEntry> castCache;
350  };
351 
354  template <template <typename, typename> class PhysicsEntityT,
355  typename RequiredFeatureList, typename... OptionalFeatureLists>
357  EntityFeatureMap<PhysicsEntityT, physics::FeaturePolicy3d,
358  RequiredFeatureList, OptionalFeatureLists...>;
359 }
360 }
361 }
362 #endif