ARGoS 3
A parallel, multi-engine simulator for swarm robotics
embodied_entity.cpp
Go to the documentation of this file.
1
7#include "embodied_entity.h"
8#include "composable_entity.h"
9#include <argos3/core/simulator/space/space.h>
10#include <argos3/core/simulator/simulator.h>
11#include <argos3/core/utility/string_utilities.h>
12#include <argos3/core/utility/math/matrix/rotationmatrix3.h>
13
14namespace argos {
15
16 /****************************************/
17 /****************************************/
18
20 CEntity(pc_parent),
21 m_bMovable(true),
22 m_sBoundingBox(nullptr),
23 m_psOriginAnchor(nullptr) {}
24
25 /****************************************/
26 /****************************************/
27
29 const std::string& str_id,
30 const CVector3& c_position,
31 const CQuaternion& c_orientation,
32 bool b_movable) :
33 CEntity(pc_parent, str_id),
34 m_bMovable(b_movable),
35 m_sBoundingBox(nullptr),
36 m_psOriginAnchor(new SAnchor(*this,
37 "origin",
38 0,
39 CVector3(),
41 c_position,
42 c_orientation)),
43 m_cInitOriginPosition(c_position),
44 m_cInitOriginOrientation(c_orientation) {
45 /* Add anchor to map and enable it */
47 EnableAnchor("origin");
48 }
49
50 /****************************************/
51 /****************************************/
52
54 if(!m_bMovable && m_sBoundingBox != nullptr) {
55 delete m_sBoundingBox;
56 }
57 for(auto it = m_mapAnchors.begin();
58 it != m_mapAnchors.end(); ++it) {
59 /* it->second points to the current anchor */
60 delete it->second;
61 }
62 m_mapAnchors.clear();
63 }
64
65 /****************************************/
66 /****************************************/
67
69 try {
70 /* Initialize base entity */
71 CEntity::Init(t_tree);
72 /* Get the position of the entity */
74 /* Get the orientation of the entity */
76 /* Create origin anchor */
77 m_psOriginAnchor = new SAnchor(*this,
78 "origin",
79 0,
80 CVector3(),
84 /* Add anchor to map and enable it */
86 EnableAnchor("origin");
87 /* Embodied entities are movable by default */
88 m_bMovable = true;
89 }
90 catch(CARGoSException& ex) {
91 THROW_ARGOSEXCEPTION_NESTED("Failed to initialize embodied entity \"" << GetContext() << GetId() << "\".", ex);
92 }
93 }
94
95 /****************************************/
96 /****************************************/
97
99 /* Reset origin anchor first */
102 /* Reset other anchors */
103 SAnchor* psAnchor;
104 for(auto it = m_mapAnchors.begin();
105 it != m_mapAnchors.end(); ++it) {
106 /* it->second points to the current anchor */
107 psAnchor = it->second;
108 if(psAnchor->Index > 0) {
109 /* Calculate global position and orientation */
110 psAnchor->Position = psAnchor->OffsetPosition;
112 psAnchor->Position += m_cInitOriginPosition;
114 }
115 }
116 }
117
118 /****************************************/
119 /****************************************/
120
121 SAnchor& CEmbodiedEntity::AddAnchor(const std::string& str_id,
122 const CVector3& c_offset_position,
123 const CQuaternion& c_offset_orientation) {
124 /* Make sure the anchor id is unique */
125 if(m_mapAnchors.count(str_id) > 0 ) {
126 THROW_ARGOSEXCEPTION("Embodied entity \"" << GetContext() + GetId() << "\" already has an anchor with id " << str_id);
127 }
128 /* Calculate anchor position */
129 CVector3 cPos = c_offset_position;
131 cPos += m_psOriginAnchor->Position;
132 /* Calculate anchor orientation */
133 CQuaternion cOrient = m_psOriginAnchor->Orientation * c_offset_orientation;
134 /* Create anchor */
135 auto* psAnchor = new SAnchor(*this,
136 str_id,
137 m_mapAnchors.size(),
138 c_offset_position,
139 c_offset_orientation,
140 cPos,
141 cOrient);
142 /* Add anchor to map */
143 m_mapAnchors[str_id] = psAnchor;
144 return *psAnchor;
145 }
146
147 /****************************************/
148 /****************************************/
149
150 void CEmbodiedEntity::EnableAnchor(const std::string& str_id) {
151 /* Lookup the anchor id */
152 auto it = m_mapAnchors.find(str_id);
153 /* Found? */
154 if(it == m_mapAnchors.end()) {
155 THROW_ARGOSEXCEPTION("Embodied entity \"" << GetContext() + GetId() << "\" has no anchor with id " << str_id);
156 }
157 /* Now it->second points to the requested anchor */
158 /* Increase the in-use count */
159 ++(it->second->InUseCount);
160 /* Add to vector of enabled anchors if necessary */
161 if(it->second->InUseCount == 1) {
162 m_vecEnabledAnchors.push_back(it->second);
163 }
164 }
165
166 /****************************************/
167 /****************************************/
168
169 void CEmbodiedEntity::DisableAnchor(const std::string& str_id) {
170 /* Cannot disable the origin anchor */
171 if(str_id == "origin") return;
172 /* Lookup the anchor id */
173 auto it = std::find(m_vecEnabledAnchors.begin(),
175 str_id);
176 /* Found? */
177 if(it == m_vecEnabledAnchors.end()) return;
178 /* Now *it points to the requested anchor */
179 /* Decrease the in-use count */
180 --((*it)->InUseCount);
181 /* Remove from vector of enabled anchors if necessary */
182 if((*it)->InUseCount == 0) {
183 m_vecEnabledAnchors.erase(it);
184 }
185 }
186
187 /****************************************/
188 /****************************************/
189
190 const SAnchor& CEmbodiedEntity::GetAnchor(const std::string& str_id) const {
191 /* Lookup the anchor id */
192 auto it = m_mapAnchors.find(str_id);
193 /* Found? */
194 if(it == m_mapAnchors.end()) {
195 THROW_ARGOSEXCEPTION("Embodied entity \"" << GetContext() + GetId() << "\" has no anchor with id " << str_id);
196 }
197 /* Now it->second points to the requested anchor */
198 return *(it->second);
199 }
200
201 /****************************************/
202 /****************************************/
203
204 SAnchor& CEmbodiedEntity::GetAnchor(const std::string& str_id) {
205 /* Lookup the anchor id */
206 auto it = m_mapAnchors.find(str_id);
207 /* Found? */
208 if(it == m_mapAnchors.end()) {
209 THROW_ARGOSEXCEPTION("Embodied entity \"" << GetContext() + GetId() << "\" has no anchor with id " << str_id);
210 }
211 /* Now it->second points to the requested anchor */
212 return *(it->second);
213 }
214
215 /****************************************/
216 /****************************************/
217
218 bool CEmbodiedEntity::IsAnchorEnabled(const std::string& str_id) {
219 /* Lookup the anchor id */
220 std::map<std::string, SAnchor*>::const_iterator it = m_mapAnchors.find(str_id);
221 /* Found? */
222 if(it == m_mapAnchors.end()) {
223 THROW_ARGOSEXCEPTION("Embodied entity \"" << GetContext() + GetId() << "\" has no anchor with id " << str_id);
224 }
225 /* Now it->second points to the requested anchor */
226 return (it->second->InUseCount > 0);
227 }
228
229 /****************************************/
230 /****************************************/
231
233 if(GetPhysicsModelsNum() == 0) {
234 /* No engine associated to this entity */
235 THROW_ARGOSEXCEPTION("CEmbodiedEntity::GetBoundingBox() : entity \"" << GetContext() << GetId() << "\" is not associated to any engine");
236 }
237 return *m_sBoundingBox;
238 }
239
240 /****************************************/
241 /****************************************/
242
246
247 /****************************************/
248 /****************************************/
249
250 void CEmbodiedEntity::AddPhysicsModel(const std::string& str_engine_id,
251 CPhysicsModel& c_physics_model) {
252 if(m_bMovable && GetPhysicsModelsNum() > 0) {
253 THROW_ARGOSEXCEPTION(GetContext() << GetId() << " is a movable embodied entity and can't have more than 1 physics engine entity associated");
254 }
255 m_tPhysicsModelMap[str_engine_id] = &c_physics_model;
256 m_tPhysicsModelVector.push_back(&c_physics_model);
258 }
259
260 /****************************************/
261 /****************************************/
262
263 void CEmbodiedEntity::RemovePhysicsModel(const std::string& str_engine_id) {
264 auto itMap = m_tPhysicsModelMap.find(str_engine_id);
265 if(itMap == m_tPhysicsModelMap.end()) {
266 THROW_ARGOSEXCEPTION("Entity \"" << GetContext() << GetId() << "\" has no associated entity in physics engine " << str_engine_id);
267 }
268 auto itVec = std::find(m_tPhysicsModelVector.begin(),
270 itMap->second);
271 m_tPhysicsModelMap.erase(itMap);
272 m_tPhysicsModelVector.erase(itVec);
274 }
275
276 /****************************************/
277 /****************************************/
278
280 if(un_idx > m_tPhysicsModelVector.size()) {
281 THROW_ARGOSEXCEPTION("CEmbodiedEntity::GetPhysicsModel: entity \"" << GetContext() << GetId() << "\": the passed index " << un_idx << " is out of bounds, the max allowed is " << m_tPhysicsModelVector.size());
282 }
283 return *m_tPhysicsModelVector[un_idx];
284 }
285
286 /****************************************/
287 /****************************************/
288
290 if(un_idx > m_tPhysicsModelVector.size()) {
291 THROW_ARGOSEXCEPTION("CEmbodiedEntity::GetPhysicsModel: entity \"" << GetContext() << GetId() << "\": the passed index " << un_idx << " is out of bounds, the max allowed is " << m_tPhysicsModelVector.size());
292 }
293 return *m_tPhysicsModelVector[un_idx];
294 }
295
296 /****************************************/
297 /****************************************/
298
299 const CPhysicsModel& CEmbodiedEntity::GetPhysicsModel(const std::string& str_engine_id) const {
300 auto it = m_tPhysicsModelMap.find(str_engine_id);
301 if(it == m_tPhysicsModelMap.end()) {
302 THROW_ARGOSEXCEPTION("Entity \"" << GetContext() << GetId() << "\" has no associated entity in physics engine \"" << str_engine_id << "\"");
303 }
304 return *(it->second);
305 }
306
307 /****************************************/
308 /****************************************/
309
310 CPhysicsModel& CEmbodiedEntity::GetPhysicsModel(const std::string& str_engine_id) {
311 auto it = m_tPhysicsModelMap.find(str_engine_id);
312 if(it == m_tPhysicsModelMap.end()) {
313 THROW_ARGOSEXCEPTION("Entity \"" << GetContext() << GetId() << "\" has no associated entity in physics engine \"" << str_engine_id << "\"");
314 }
315 return *(it->second);
316 }
317
318 /****************************************/
319 /****************************************/
320
321 bool CEmbodiedEntity::MoveTo(const CVector3& c_position,
322 const CQuaternion& c_orientation,
323 bool b_check_only,
324 bool b_ignore_collisions) {
325 /* Can't move an entity with no model associated */
326 if(GetPhysicsModelsNum() == 0) return false;
327 /* Save current position and orientation */
328 CVector3 cOriginalPosition = m_psOriginAnchor->Position;
329 CQuaternion cOriginalOrientation = m_psOriginAnchor->Orientation;
330 /* Treat specially the case of movable entity */
331 if(m_bMovable) {
332 /* Move entity and check for collisions */
333 m_tPhysicsModelVector[0]->MoveTo(c_position, c_orientation);
334 bool bNoCollision = b_ignore_collisions || (! m_tPhysicsModelVector[0]->IsCollidingWithSomething());
335 /* Depending on the presence of collisions... */
336 if(bNoCollision && !b_check_only) {
337 /* No collision and not a simple check */
338 /* Tell the caller that we managed to move the entity */
339 return true;
340 }
341 else {
342 /* Collision or just a check, undo changes */
343 m_tPhysicsModelVector[0]->MoveTo(cOriginalPosition, cOriginalOrientation);
344 /* Tell the caller about collisions */
345 return bNoCollision;
346 }
347 }
348 else {
349 /* The entity is not movable, go through all the models */
350 size_t i;
351 bool bNoCollision = true;
352 for(i = 0; i < m_tPhysicsModelVector.size() && bNoCollision; ++i) {
353 m_tPhysicsModelVector[i]->MoveTo(c_position, c_orientation);
354 bNoCollision = b_ignore_collisions || !m_tPhysicsModelVector[i]->IsCollidingWithSomething();
355 }
356 if(bNoCollision && !b_check_only) {
357 /* No collision and not a simple check */
359 /* Tell the caller that we managed to move the entity */
360 return true;
361 }
362 else {
363 /* No collision or just a check, undo changes */
364 for(size_t j = 0; j < i; ++j) {
365 m_tPhysicsModelVector[j]->MoveTo(cOriginalPosition, cOriginalOrientation);
366 }
367 /* Tell the caller about collisions */
368 return bNoCollision;
369 }
370 }
371 }
372
373 /****************************************/
374 /****************************************/
375
376#define CHECK_CORNER(MINMAX, COORD, OP) \
377 if(m_sBoundingBox->MINMAX ## Corner.Get ## COORD() OP sBBox.MINMAX ## Corner.Get ## COORD()) { \
378 m_sBoundingBox->MINMAX ## Corner.Set ## COORD(sBBox.MINMAX ## Corner.Get ## COORD()); \
379 }
380
382 if(GetPhysicsModelsNum() > 0) {
383 /*
384 * There is at least one physics engine entity associated
385 */
386 if(m_bMovable) {
387 /* The bounding box points directly to the associated model bounding box */
388 m_sBoundingBox = &m_tPhysicsModelVector[0]->GetBoundingBox();
389 }
390 else {
391 /* The bounding box is obtained taking the extrema of all the bboxes of all the engines */
392 if(m_sBoundingBox == nullptr) {
394 }
395 *m_sBoundingBox = m_tPhysicsModelVector[0]->GetBoundingBox();
396 for(size_t i = 1; i < GetPhysicsModelsNum(); ++i) {
397 const SBoundingBox& sBBox = m_tPhysicsModelVector[0]->GetBoundingBox();
398 CHECK_CORNER(Min, X, >);
399 CHECK_CORNER(Min, Y, >);
400 CHECK_CORNER(Min, Z, >);
401 CHECK_CORNER(Max, X, <);
402 CHECK_CORNER(Max, Y, <);
403 CHECK_CORNER(Max, Z, <);
404 }
405 }
406 }
407 else {
408 /*
409 * No physics engine entity associated
410 */
411 if(! m_bMovable && m_sBoundingBox != nullptr) {
412 /* A non-movable entity has its own bounding box, delete it */
413 delete m_sBoundingBox;
414 }
415 m_sBoundingBox = nullptr;
416 }
417 }
418
419 /****************************************/
420 /****************************************/
421
423 /* If no model is associated, you can't call this function */
424 if(m_tPhysicsModelVector.empty()) {
425 THROW_ARGOSEXCEPTION("CEmbodiedEntity::IsCollidingWithSomething() called on entity \"" <<
426 GetContext() << GetId() <<
427 "\", but this entity has not been added to any physics engine.");
428 }
429 /* Special case: if there is only one model, check that directly */
430 if(m_tPhysicsModelVector.size() == 1) {
431 return m_tPhysicsModelVector[0]->IsCollidingWithSomething();
432 }
433 /* Multiple associations, go through them */
434 else {
435 /* Return true at the first detected collision */
436 for(size_t i = 0; i < m_tPhysicsModelVector.size(); ++i) {
438 return true;
439 }
440 }
441 /* If you get here it's because there are collisions */
442 return false;
443 }
444 }
445
446 /****************************************/
447 /****************************************/
448
449 bool operator==(const SAnchor* ps_anchor,
450 const std::string& str_id) {
451 return (ps_anchor->Id == str_id);
452 }
453
454 /****************************************/
455 /****************************************/
456
457 void CEmbodiedEntitySpaceHashUpdater::operator()(CAbstractSpaceHash<CEmbodiedEntity>& c_space_hash,
458 CEmbodiedEntity& c_element) {
459 /* Translate the min corner of the bounding box into the map's coordinate */
460 c_space_hash.SpaceToHashTable(m_nMinX, m_nMinY, m_nMinZ, c_element.GetBoundingBox().MinCorner);
461 /* Translate the max corner of the bounding box into the map's coordinate */
462 c_space_hash.SpaceToHashTable(m_nMaxX, m_nMaxY, m_nMaxZ, c_element.GetBoundingBox().MaxCorner);
463 /* Finally, go through the affected cells and update them */
464 for(SInt32 nK = m_nMinZ; nK <= m_nMaxZ; ++nK) {
465 for(SInt32 nJ = m_nMinY; nJ <= m_nMaxY; ++nJ) {
466 for(SInt32 nI = m_nMinX; nI <= m_nMaxX; ++nI) {
467 c_space_hash.UpdateCell(nI, nJ, nK, c_element);
468 }
469 }
470 }
471 }
472
473 /****************************************/
474 /****************************************/
475
478
480 try {
481 /* Get cell of bb min corner, clamping it if is out of bounds */
482 m_cGrid.PositionToCell(m_nMinI, m_nMinJ, m_nMinK, c_entity.GetBoundingBox().MinCorner);
483 m_cGrid.ClampCoordinates(m_nMinI, m_nMinJ, m_nMinK);
484 /* Get cell of bb max corner, clamping it if is out of bounds */
485 m_cGrid.PositionToCell(m_nMaxI, m_nMaxJ, m_nMaxK, c_entity.GetBoundingBox().MaxCorner);
486 m_cGrid.ClampCoordinates(m_nMaxI, m_nMaxJ, m_nMaxK);
487 /* Go through cells */
488 for(SInt32 m_nK = m_nMinK; m_nK <= m_nMaxK; ++m_nK) {
489 for(SInt32 m_nJ = m_nMinJ; m_nJ <= m_nMaxJ; ++m_nJ) {
490 for(SInt32 m_nI = m_nMinI; m_nI <= m_nMaxI; ++m_nI) {
491 m_cGrid.UpdateCell(m_nI, m_nJ, m_nK, c_entity);
492 }
493 }
494 }
495 /* Continue with the other entities */
496 return true;
497 }
498 catch(CARGoSException& ex) {
499 THROW_ARGOSEXCEPTION_NESTED("While updating the embodied entity grid for embodied entity \"" << c_entity.GetContext() << c_entity.GetId() << "\"", ex);
500 }
501 }
502
503 /****************************************/
504 /****************************************/
505
509 class CSpaceOperationAddEmbodiedEntity : public CSpaceOperationAddEntity {
510 public:
511 void ApplyTo(CSpace& c_space, CEmbodiedEntity& c_entity) {
512 /* Add entity to space */
513 c_space.AddEntity(c_entity);
514 /* Try to add entity to physics engine(s) */
515 c_space.AddEntityToPhysicsEngine(c_entity);
516 }
517 };
518 REGISTER_SPACE_OPERATION(CSpaceOperationAddEntity, CSpaceOperationAddEmbodiedEntity, CEmbodiedEntity);
519
520 class CSpaceOperationRemoveEmbodiedEntity : public CSpaceOperationRemoveEntity {
521 public:
522 void ApplyTo(CSpace& c_space, CEmbodiedEntity& c_entity) {
523 /* Get a reference to the root entity */
524 CEntity* pcRoot = &c_entity;
525 while(pcRoot->HasParent()) {
526 pcRoot = &pcRoot->GetParent();
527 }
528 /* Remove entity from all physics engines */
529 try {
530 while(c_entity.GetPhysicsModelsNum() > 0) {
531 c_entity.GetPhysicsModel(0).GetEngine().RemoveEntity(*pcRoot);
532 }
533 }
534 catch(CARGoSException& ex) {
535 /*
536 * It is safe to ignore errors because they happen only when an entity
537 * is completely removed from the space. In this case, the body is
538 * first removed from the composable entity, and then the embodied entity
539 * is asked to clear up the physics models. In turn, this last operation
540 * searches for the body component, which is not there anymore.
541 *
542 * It is anyway useful to search for the body component because, when robots
543 * are transferred from an engine to another, only the physics model is to be
544 * removed.
545 */
546 }
547 /* Remove entity from space */
548 c_space.RemoveEntity(c_entity);
549 }
550 };
551 REGISTER_SPACE_OPERATION(CSpaceOperationRemoveEntity, CSpaceOperationRemoveEmbodiedEntity, CEmbodiedEntity);
556 /****************************************/
557 /****************************************/
558
559}
signed int SInt32
32-bit signed integer.
Definition datatypes.h:93
unsigned int UInt32
32-bit unsigned integer.
Definition datatypes.h:97
#define THROW_ARGOSEXCEPTION_NESTED(message, nested)
This macro throws an ARGoS exception with the passed message and nesting the passed exception.
#define THROW_ARGOSEXCEPTION(message)
This macro throws an ARGoS exception with the passed message.
#define REGISTER_SPACE_OPERATION(ACTION, OPERATION, ENTITY)
Definition space.h:549
#define CHECK_CORNER(MINMAX, COORD, OP)
The namespace containing all the ARGoS related code.
Definition ci_actuator.h:12
bool operator==(const SAnchor *ps_anchor, const std::string &str_id)
Returns true if the anchor id matches the given id.
void GetNodeAttributeOrDefault(TConfigurationNode &t_node, const std::string &str_attribute, T &t_buffer, const T &t_default)
Returns the value of a node's attribute, or the passed default value.
ticpp::Element TConfigurationNode
The ARGoS configuration XML node.
T Max(const T &t_v1, const T &t_v2)
Returns the bigger of the two passed arguments.
Definition general.h:95
T Min(const T &t_v1, const T &t_v2)
Returns the smaller of the two passed arguments.
Definition general.h:77
Basic class for an entity that contains other entities.
This entity is a link to a body in the physics engine.
CQuaternion m_cInitOriginOrientation
void DisableAnchor(const std::string &str_id)
Disables an anchor.
virtual void AddPhysicsModel(const std::string &str_engine_id, CPhysicsModel &c_physics_model)
Adds a new physics model to this embodied entity.
bool IsAnchorEnabled(const std::string &str_id)
Returns true if the given anchor is enabled, false otherwise.
void RemovePhysicsModel(const std::string &str_engine_id)
Removes a physics model from this embodied entity.
CEmbodiedEntity(CComposableEntity *pc_parent)
Class constructor.
const SAnchor & GetAnchor(const std::string &str_id) const
Returns the wanted anchor as a const reference.
const SBoundingBox & GetBoundingBox() const
Returns the bounding box of this embodied entity.
CPhysicsModel::TVector m_tPhysicsModelVector
std::map< std::string, SAnchor * > m_mapAnchors
void CalculateBoundingBox()
Calculates the bounding box of this entity.
std::vector< SAnchor * > m_vecEnabledAnchors
virtual bool IsCollidingWithSomething() const
Returns true if this entity is colliding with another object.
virtual ~CEmbodiedEntity()
Class destructor.
const CPhysicsModel & GetPhysicsModel(size_t un_idx) const
Returns a physics model associated to this entity.
UInt32 GetPhysicsModelsNum() const
Returns the number of physics models associated to this entity.
SBoundingBox * m_sBoundingBox
virtual bool MoveTo(const CVector3 &c_position, const CQuaternion &c_orientation, bool b_check_only=false, bool b_ignore_collisions=false)
Moves the entity to the wanted position and orientation.
virtual void Init(TConfigurationNode &t_tree)
Initializes the state of the entity from the XML configuration tree.
CPhysicsModel::TMap m_tPhysicsModelMap
void EnableAnchor(const std::string &str_id)
Enables an anchor.
SAnchor & AddAnchor(const std::string &str_id, const CVector3 &c_rel_position=CVector3(), const CQuaternion &c_rel_orientation=CQuaternion())
Adds an anchor to the embodied entity.
virtual void Reset()
Resets the state of the entity to whatever it was after Init() or the standalone constructor was call...
virtual bool operator()(CEmbodiedEntity &c_entity)
CEmbodiedEntityGridUpdater(CGrid< CEmbodiedEntity > &c_grid)
The basic entity type.
Definition entity.h:90
const std::string & GetId() const
Returns the id of this entity.
Definition entity.h:157
std::string GetContext() const
Returns the context of this entity.
Definition entity.cpp:79
virtual void Init(TConfigurationNode &t_tree)
Initializes the state of the entity from the XML configuration tree.
Definition entity.cpp:40
An anchor related to the body of an entity.
CQuaternion Orientation
The orientation of the anchor wrt the global coordinate system.
CQuaternion OffsetOrientation
The initial orientation of the anchor wrt the body coordinate system.
std::string Id
The id of the anchor.
UInt32 Index
The index of the anchor assigned by the embodied entity.
CVector3 Position
The position of the anchor wrt the global coordinate system.
CVector3 OffsetPosition
The initial position of the anchor wrt the body coordinate system.
void AddEntity(ENTITY &c_entity)
Adds an entity of the given type.
Definition space.h:274
virtual void AddEntityToPhysicsEngine(CEmbodiedEntity &c_entity)
Definition space.cpp:186
The exception that wraps all errors in ARGoS.
A 3D vector class.
Definition vector3.h:31
CVector3 & Rotate(const CQuaternion &c_quaternion)
Rotates this vector by the given quaternion.
Definition vector3.cpp:23