1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "dart/dynamics/Frame.hpp"
34 
35 #include "dart/common/Console.hpp"
36 #include "dart/dynamics/Shape.hpp"
37 
38 namespace dart {
39 namespace dynamics {
40 
41 typedef std::set<Entity*> EntityPtrSet;
42 typedef std::set<Frame*> FramePtrSet;
43 
44 //==============================================================================
~Frame()45 Frame::~Frame()
46 {
47   if (isWorld())
48     return;
49 
50   changeParentFrame(nullptr);
51 
52   // Inform all child entities that this Frame is disappearing by setting their
53   // reference frames to the World frame.
54   EntityPtrSet::iterator it = mChildEntities.begin(),
55                          end = mChildEntities.end();
56   while (it != end)
57     (*(it++))->changeParentFrame(Frame::World());
58   // Note: When we instruct an Entity to change its parent Frame, it will erase
59   // itself from this Frame's mChildEntities list. This would invalidate the
60   // 'it' and clobber our attempt to iterate through the std::set if we applied
61   // changeParentFrame() directly to the 'it' iterator. So instead we use the
62   // post-increment operator to iterate 'it' forward and we apply
63   // changeParentFrame() to the temporary iterator created by the
64   // post-increment operator. Put simply: we increment 'it' forward once and
65   // then apply changeParentFrame() to the pointer that 'it' held just before
66   // it incremented.
67 
68   // The entity destructor takes care of informing the parent Frame that this
69   // one is disappearing
70 }
71 
72 //==============================================================================
World()73 Frame* Frame::World()
74 {
75   static WorldFrame world;
76   return &world;
77 }
78 
79 //==============================================================================
WorldShared()80 std::shared_ptr<Frame> Frame::WorldShared()
81 {
82   struct EnableMakeShared : WorldFrame
83   {
84     EnableMakeShared() : Entity(nullptr, true), WorldFrame()
85     {
86     }
87   };
88   static auto sharedWorld = std::make_shared<EnableMakeShared>();
89   return sharedWorld;
90 }
91 
92 //==============================================================================
getWorldTransform() const93 const Eigen::Isometry3d& Frame::getWorldTransform() const
94 {
95   if (mAmWorld)
96     return mWorldTransform;
97 
98   if (mNeedTransformUpdate)
99   {
100     mWorldTransform
101         = mParentFrame->getWorldTransform() * getRelativeTransform();
102     mNeedTransformUpdate = false;
103   }
104 
105   return mWorldTransform;
106 }
107 
108 //==============================================================================
getTransform(const Frame * _withRespectTo) const109 Eigen::Isometry3d Frame::getTransform(const Frame* _withRespectTo) const
110 {
111   if (_withRespectTo->isWorld())
112     return getWorldTransform();
113   else if (_withRespectTo == mParentFrame)
114     return getRelativeTransform();
115   else if (_withRespectTo == this)
116     return Eigen::Isometry3d::Identity();
117 
118   return _withRespectTo->getWorldTransform().inverse() * getWorldTransform();
119 }
120 
121 //==============================================================================
getTransform(const Frame * withRespectTo,const Frame * inCoordinatesOf) const122 Eigen::Isometry3d Frame::getTransform(
123     const Frame* withRespectTo, const Frame* inCoordinatesOf) const
124 {
125   assert(nullptr != withRespectTo);
126   assert(nullptr != inCoordinatesOf);
127 
128   if (withRespectTo == inCoordinatesOf)
129     return getTransform(withRespectTo);
130 
131   // Rotation from "inCoordinatesOf" to "withRespecTo"
132   Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
133   T.linear() = inCoordinatesOf->getWorldTransform().linear().transpose()
134                * withRespectTo->getWorldTransform().linear();
135 
136   return T * getTransform(withRespectTo);
137 }
138 
139 //==============================================================================
getSpatialVelocity() const140 const Eigen::Vector6d& Frame::getSpatialVelocity() const
141 {
142   if (mAmWorld)
143     return mVelocity;
144 
145   if (mNeedVelocityUpdate)
146   {
147     mVelocity
148         = math::AdInvT(
149               getRelativeTransform(), getParentFrame()->getSpatialVelocity())
150           + getRelativeSpatialVelocity();
151 
152     mNeedVelocityUpdate = false;
153   }
154 
155   return mVelocity;
156 }
157 
158 //==============================================================================
getSpatialVelocity(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const159 Eigen::Vector6d Frame::getSpatialVelocity(
160     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
161 {
162   if (this == _relativeTo)
163     return Eigen::Vector6d::Zero();
164 
165   if (_relativeTo->isWorld())
166   {
167     if (this == _inCoordinatesOf)
168       return getSpatialVelocity();
169 
170     if (_inCoordinatesOf->isWorld())
171       return math::AdR(getWorldTransform(), getSpatialVelocity());
172 
173     return math::AdR(getTransform(_inCoordinatesOf), getSpatialVelocity());
174   }
175 
176   const Eigen::Vector6d& result = (getSpatialVelocity()
177                                    - math::AdT(
178                                          _relativeTo->getTransform(this),
179                                          _relativeTo->getSpatialVelocity()))
180                                       .eval();
181 
182   if (this == _inCoordinatesOf)
183     return result;
184 
185   return math::AdR(getTransform(_inCoordinatesOf), result);
186 }
187 
188 //==============================================================================
getSpatialVelocity(const Eigen::Vector3d & _offset) const189 Eigen::Vector6d Frame::getSpatialVelocity(const Eigen::Vector3d& _offset) const
190 {
191   return getSpatialVelocity(_offset, Frame::World(), this);
192 }
193 
194 //==============================================================================
getSpatialVelocity(const Eigen::Vector3d & _offset,const Frame * _relativeTo,const Frame * _inCoordinatesOf) const195 Eigen::Vector6d Frame::getSpatialVelocity(
196     const Eigen::Vector3d& _offset,
197     const Frame* _relativeTo,
198     const Frame* _inCoordinatesOf) const
199 {
200   if (this == _relativeTo)
201     return Eigen::Vector6d::Zero();
202 
203   Eigen::Vector6d v = getSpatialVelocity();
204   v.tail<3>().noalias() += v.head<3>().cross(_offset);
205 
206   if (_relativeTo->isWorld())
207   {
208     if (this == _inCoordinatesOf)
209       return v;
210 
211     return math::AdR(getTransform(_inCoordinatesOf), v);
212   }
213 
214   Eigen::Vector6d v_0 = math::AdT(
215       _relativeTo->getTransform(this), _relativeTo->getSpatialVelocity());
216   v_0.tail<3>().noalias() += v_0.head<3>().cross(_offset);
217 
218   v = v - v_0;
219 
220   if (this == _inCoordinatesOf)
221     return v;
222 
223   return math::AdR(getTransform(_inCoordinatesOf), v);
224 }
225 
226 //==============================================================================
getLinearVelocity(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const227 Eigen::Vector3d Frame::getLinearVelocity(
228     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
229 {
230   return getSpatialVelocity(_relativeTo, _inCoordinatesOf).tail<3>();
231 }
232 
233 //==============================================================================
getLinearVelocity(const Eigen::Vector3d & _offset,const Frame * _relativeTo,const Frame * _inCoordinatesOf) const234 Eigen::Vector3d Frame::getLinearVelocity(
235     const Eigen::Vector3d& _offset,
236     const Frame* _relativeTo,
237     const Frame* _inCoordinatesOf) const
238 {
239   return getSpatialVelocity(_offset, _relativeTo, _inCoordinatesOf).tail<3>();
240 }
241 
242 //==============================================================================
getAngularVelocity(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const243 Eigen::Vector3d Frame::getAngularVelocity(
244     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
245 {
246   return getSpatialVelocity(_relativeTo, _inCoordinatesOf).head<3>();
247 }
248 
249 //==============================================================================
getSpatialAcceleration() const250 const Eigen::Vector6d& Frame::getSpatialAcceleration() const
251 {
252   if (mAmWorld)
253     return mAcceleration;
254 
255   if (mNeedAccelerationUpdate)
256   {
257     mAcceleration = math::AdInvT(
258                         getRelativeTransform(),
259                         getParentFrame()->getSpatialAcceleration())
260                     + getPrimaryRelativeAcceleration()
261                     + getPartialAcceleration();
262 
263     mNeedAccelerationUpdate = false;
264   }
265 
266   return mAcceleration;
267 }
268 
269 //==============================================================================
getSpatialAcceleration(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const270 Eigen::Vector6d Frame::getSpatialAcceleration(
271     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
272 {
273   // Frame 2: this, Frame 1: _relativeTo, Frame O: _inCoordinatesOf
274   // Acceleration of Frame 2 relative to Frame 1 in coordinates of O: a_21[O]
275   // Total acceleration of Frame 2 in coordinates of Frame 2: a_2[2]
276   // Velocity of Frame 2 relative to Frame 1 in coordinates of Frame 2: v_21[2]
277 
278   // a_21[O] = R_O2*( a_2[2] - X_21*a_1[1] - v_2[2] x v_21[2] )
279 
280   if (this == _relativeTo)
281     return Eigen::Vector6d::Zero();
282 
283   if (_relativeTo->isWorld())
284   {
285     if (this == _inCoordinatesOf)
286       return getSpatialAcceleration();
287 
288     if (_inCoordinatesOf->isWorld())
289       return math::AdR(getWorldTransform(), getSpatialAcceleration());
290 
291     return math::AdR(getTransform(_inCoordinatesOf), getSpatialAcceleration());
292   }
293 
294   const Eigen::Vector6d& result
295       = (getSpatialAcceleration()
296          - math::AdT(
297                _relativeTo->getTransform(this),
298                _relativeTo->getSpatialAcceleration())
299          + math::ad(
300                getSpatialVelocity(),
301                math::AdT(
302                    _relativeTo->getTransform(this),
303                    _relativeTo->getSpatialVelocity())))
304             .eval();
305 
306   if (this == _inCoordinatesOf)
307     return result;
308 
309   return math::AdR(getTransform(_inCoordinatesOf), result);
310 }
311 
312 //==============================================================================
getSpatialAcceleration(const Eigen::Vector3d & _offset) const313 Eigen::Vector6d Frame::getSpatialAcceleration(
314     const Eigen::Vector3d& _offset) const
315 {
316   return getSpatialAcceleration(_offset, Frame::World(), this);
317 }
318 
319 //==============================================================================
getSpatialAcceleration(const Eigen::Vector3d & _offset,const Frame * _relativeTo,const Frame * _inCoordinatesOf) const320 Eigen::Vector6d Frame::getSpatialAcceleration(
321     const Eigen::Vector3d& _offset,
322     const Frame* _relativeTo,
323     const Frame* _inCoordinatesOf) const
324 {
325   if (this == _relativeTo)
326     return Eigen::Vector6d::Zero();
327 
328   // Compute spatial acceleration of the point
329   Eigen::Vector6d a = getSpatialAcceleration();
330   a.tail<3>().noalias() += a.head<3>().cross(_offset);
331 
332   if (_relativeTo->isWorld())
333   {
334     if (this == _inCoordinatesOf)
335       return a;
336 
337     return math::AdR(getTransform(_inCoordinatesOf), a);
338   }
339 
340   // Compute the spatial velocity of the point
341   Eigen::Vector6d v = getSpatialVelocity();
342   v.tail<3>().noalias() += v.head<3>().cross(_offset);
343 
344   // Compute the acceleration of the reference Frame
345   Eigen::Vector6d a_ref = math::AdT(
346       _relativeTo->getTransform(this), _relativeTo->getSpatialAcceleration());
347   a_ref.tail<3>().noalias() += a_ref.head<3>().cross(_offset);
348 
349   // Compute the relative velocity of the point
350   const Eigen::Vector6d& v_rel = getSpatialVelocity(_offset, _relativeTo, this);
351 
352   a = a - a_ref - math::ad(v, v_rel);
353 
354   if (this == _inCoordinatesOf)
355     return a;
356 
357   return math::AdR(getTransform(_inCoordinatesOf), a);
358 }
359 
360 //==============================================================================
getLinearAcceleration(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const361 Eigen::Vector3d Frame::getLinearAcceleration(
362     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
363 {
364   if (this == _relativeTo)
365     return Eigen::Vector3d::Zero();
366 
367   const Eigen::Vector6d& v_rel = getSpatialVelocity(_relativeTo, this);
368 
369   // r'' = a + w x v
370   const Eigen::Vector3d& a
371       = (getSpatialAcceleration(_relativeTo, this).tail<3>()
372          + v_rel.head<3>().cross(v_rel.tail<3>()))
373             .eval();
374 
375   if (this == _inCoordinatesOf)
376     return a;
377 
378   return getTransform(_inCoordinatesOf).linear() * a;
379 }
380 
381 //==============================================================================
getLinearAcceleration(const Eigen::Vector3d & _offset,const Frame * _relativeTo,const Frame * _inCoordinatesOf) const382 Eigen::Vector3d Frame::getLinearAcceleration(
383     const Eigen::Vector3d& _offset,
384     const Frame* _relativeTo,
385     const Frame* _inCoordinatesOf) const
386 {
387   if (this == _relativeTo)
388     return Eigen::Vector3d::Zero();
389 
390   const Eigen::Vector6d& v_rel = getSpatialVelocity(_offset, _relativeTo, this);
391   const Eigen::Vector3d& a
392       = (getSpatialAcceleration(_offset, _relativeTo, this).tail<3>()
393          + v_rel.head<3>().cross(v_rel.tail<3>()))
394             .eval();
395 
396   if (this == _inCoordinatesOf)
397     return a;
398 
399   return getTransform(_inCoordinatesOf).linear() * a;
400 }
401 
402 //==============================================================================
getAngularAcceleration(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const403 Eigen::Vector3d Frame::getAngularAcceleration(
404     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
405 {
406   return getSpatialAcceleration(_relativeTo, _inCoordinatesOf).head<3>();
407 }
408 
409 //==============================================================================
410 template <typename T>
convertToConstSet(const std::set<T * > & _set)411 static std::set<const T*> convertToConstSet(const std::set<T*>& _set)
412 {
413   std::set<const T*> const_set;
414   for (const auto& element : _set)
415     const_set.insert(element);
416 
417   return const_set;
418 }
419 
420 //==============================================================================
getChildEntities()421 const std::set<Entity*>& Frame::getChildEntities()
422 {
423   return mChildEntities;
424 }
425 
426 //==============================================================================
getChildEntities() const427 const std::set<const Entity*> Frame::getChildEntities() const
428 {
429   return convertToConstSet<Entity>(mChildEntities);
430 }
431 
432 //==============================================================================
getNumChildEntities() const433 std::size_t Frame::getNumChildEntities() const
434 {
435   return mChildEntities.size();
436 }
437 
438 //==============================================================================
getChildFrames()439 const std::set<Frame*>& Frame::getChildFrames()
440 {
441   return mChildFrames;
442 }
443 
444 //==============================================================================
getChildFrames() const445 std::set<const Frame*> Frame::getChildFrames() const
446 {
447   return convertToConstSet<Frame>(mChildFrames);
448 }
449 
450 //==============================================================================
getNumChildFrames() const451 std::size_t Frame::getNumChildFrames() const
452 {
453   return mChildFrames.size();
454 }
455 
456 //==============================================================================
isShapeFrame() const457 bool Frame::isShapeFrame() const
458 {
459   return mAmShapeFrame;
460 }
461 
462 //==============================================================================
asShapeFrame()463 ShapeFrame* Frame::asShapeFrame()
464 {
465   return nullptr;
466 }
467 
468 //==============================================================================
asShapeFrame() const469 const ShapeFrame* Frame::asShapeFrame() const
470 {
471   return nullptr;
472 }
473 
474 //==============================================================================
isWorld() const475 bool Frame::isWorld() const
476 {
477   return mAmWorld;
478 }
479 
480 //==============================================================================
dirtyTransform()481 void Frame::dirtyTransform()
482 {
483   dirtyVelocity(); // Global Velocity depends on the Global Transform
484 
485   // Always trigger the signal, in case a new subscriber has registered in the
486   // time since the last signal
487   mTransformUpdatedSignal.raise(this);
488 
489   // If we already know we need to update, just quit
490   if (mNeedTransformUpdate)
491     return;
492 
493   mNeedTransformUpdate = true;
494 
495   for (Entity* entity : mChildEntities)
496     entity->dirtyTransform();
497 }
498 
499 //==============================================================================
dirtyVelocity()500 void Frame::dirtyVelocity()
501 {
502   dirtyAcceleration(); // Global Acceleration depends on Global Velocity
503 
504   // Always trigger the signal, in case a new subscriber has registered in the
505   // time since the last signal
506   mVelocityChangedSignal.raise(this);
507 
508   // If we already know we need to update, just quit
509   if (mNeedVelocityUpdate)
510     return;
511 
512   mNeedVelocityUpdate = true;
513 
514   for (Entity* entity : mChildEntities)
515     entity->dirtyVelocity();
516 }
517 
518 //==============================================================================
dirtyAcceleration()519 void Frame::dirtyAcceleration()
520 {
521   // Always trigger the signal, in case a new subscriber has registered in the
522   // time since the last signal
523   mAccelerationChangedSignal.raise(this);
524 
525   // If we already know we need to update, just quit
526   if (mNeedAccelerationUpdate)
527     return;
528 
529   mNeedAccelerationUpdate = true;
530 
531   for (Entity* entity : mChildEntities)
532     entity->dirtyAcceleration();
533 }
534 
535 //==============================================================================
Frame(Frame * _refFrame)536 Frame::Frame(Frame* _refFrame)
537   : Entity(ConstructFrame),
538     mWorldTransform(Eigen::Isometry3d::Identity()),
539     mVelocity(Eigen::Vector6d::Zero()),
540     mAcceleration(Eigen::Vector6d::Zero()),
541     mAmWorld(false),
542     mAmShapeFrame(false)
543 {
544   mAmFrame = true;
545   changeParentFrame(_refFrame);
546 }
547 
548 //==============================================================================
Frame()549 Frame::Frame() : Frame(ConstructAbstract)
550 {
551   // Delegated to Frame(ConstructAbstract)
552 }
553 
554 //==============================================================================
Frame(ConstructAbstractTag)555 Frame::Frame(ConstructAbstractTag)
556   : Entity(Entity::ConstructAbstract), mAmWorld(false), mAmShapeFrame(false)
557 {
558   dterr << "[Frame::constructor] You are calling a constructor for the Frame "
559         << "class which is only meant to be used by pure abstract classes. If "
560         << "you are seeing this, then there is a bug!\n";
561   assert(false);
562 }
563 
564 //==============================================================================
changeParentFrame(Frame * _newParentFrame)565 void Frame::changeParentFrame(Frame* _newParentFrame)
566 {
567   if (mParentFrame == _newParentFrame)
568     return;
569 
570   if (_newParentFrame)
571   {
572     if (_newParentFrame->descendsFrom(this))
573     {
574       if (!(this->isWorld() && _newParentFrame->isWorld()))
575       // We make an exception here for the World Frame, because it's
576       // special/unique
577       {
578         dtwarn << "[Frame::changeParentFrame] Attempting to create a circular "
579                << "kinematic dependency by making Frame '" << getName()
580                << "' a child of Frame '" << _newParentFrame->getName() << "'. "
581                << "This will not be allowed.\n";
582         return;
583       }
584     }
585   }
586 
587   if (mParentFrame && !mParentFrame->isWorld())
588   {
589     FramePtrSet::iterator it = mParentFrame->mChildFrames.find(this);
590     if (it != mParentFrame->mChildFrames.end())
591       mParentFrame->mChildFrames.erase(it);
592   }
593 
594   if (nullptr == _newParentFrame)
595   {
596     Entity::changeParentFrame(_newParentFrame);
597     return;
598   }
599 
600   if (!mAmQuiet && !_newParentFrame->isWorld())
601     _newParentFrame->mChildFrames.insert(this);
602 
603   Entity::changeParentFrame(_newParentFrame);
604 }
605 
606 //==============================================================================
processNewEntity(Entity *)607 void Frame::processNewEntity(Entity*)
608 {
609   // Do nothing
610 }
611 
612 //==============================================================================
processRemovedEntity(Entity *)613 void Frame::processRemovedEntity(Entity*)
614 {
615   // Do nothing
616 }
617 
618 //==============================================================================
Frame(ConstructWorldTag)619 Frame::Frame(ConstructWorldTag)
620   : Entity(this, true),
621     mWorldTransform(Eigen::Isometry3d::Identity()),
622     mVelocity(Eigen::Vector6d::Zero()),
623     mAcceleration(Eigen::Vector6d::Zero()),
624     mAmWorld(true),
625     mAmShapeFrame(false)
626 {
627   mAmFrame = true;
628 }
629 
630 //==============================================================================
631 const Eigen::Vector6d WorldFrame::mZero = Eigen::Vector6d::Zero();
632 
633 //==============================================================================
getRelativeTransform() const634 const Eigen::Isometry3d& WorldFrame::getRelativeTransform() const
635 {
636   return mRelativeTf;
637 }
638 
639 //==============================================================================
getRelativeSpatialVelocity() const640 const Eigen::Vector6d& WorldFrame::getRelativeSpatialVelocity() const
641 {
642   return mZero;
643 }
644 
645 //==============================================================================
getRelativeSpatialAcceleration() const646 const Eigen::Vector6d& WorldFrame::getRelativeSpatialAcceleration() const
647 {
648   return mZero;
649 }
650 
651 //==============================================================================
getPrimaryRelativeAcceleration() const652 const Eigen::Vector6d& WorldFrame::getPrimaryRelativeAcceleration() const
653 {
654   return mZero;
655 }
656 
657 //==============================================================================
getPartialAcceleration() const658 const Eigen::Vector6d& WorldFrame::getPartialAcceleration() const
659 {
660   return mZero;
661 }
662 
663 //==============================================================================
setName(const std::string & name)664 const std::string& WorldFrame::setName(const std::string& name)
665 {
666   dterr << "[WorldFrame::setName] attempting to change name of World frame to ["
667         << name << "], but this is not allowed!\n";
668   static const std::string worldName = "World";
669   return worldName;
670 }
671 
672 //==============================================================================
getName() const673 const std::string& WorldFrame::getName() const
674 {
675   static const std::string worldName = "World";
676   return worldName;
677 }
678 
679 //==============================================================================
WorldFrame()680 WorldFrame::WorldFrame()
681   : Entity(nullptr, true),
682     Frame(ConstructWorld),
683     mRelativeTf(Eigen::Isometry3d::Identity())
684 {
685   changeParentFrame(this);
686 }
687 
688 } // namespace dynamics
689 } // namespace dart
690