Gazebo Sim

API Reference

10.5.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>
29
30#include "gz/sim/Entity.hh"
31
32namespace gz::sim
33{
34inline namespace GZ_SIM_VERSION_NAMESPACE {
35namespace 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 entities 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>
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
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
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>
358 RequiredFeatureList, OptionalFeatureLists...>;
359}
360}
361}
362#endif