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 code incorporates portions of Open Dynamics Engine
19  *     (Copyright (c) 2001-2004, Russell L. Smith. All rights
20  *     reserved.) and portions of FCL (Copyright (c) 2011, Willow
21  *     Garage, Inc. All rights reserved.), which were released under
22  *     the same BSD license as below
23  *
24  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
25  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
26  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
29  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
32  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
33  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  *   POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include "dart/simulation/World.hpp"
40 
41 #include <iostream>
42 #include <string>
43 #include <vector>
44 
45 #include "dart/collision/CollisionGroup.hpp"
46 #include "dart/common/Console.hpp"
47 #include "dart/constraint/BoxedLcpConstraintSolver.hpp"
48 #include "dart/constraint/ConstrainedGroup.hpp"
49 #include "dart/dynamics/Skeleton.hpp"
50 #include "dart/integration/SemiImplicitEulerIntegrator.hpp"
51 
52 namespace dart {
53 namespace simulation {
54 
55 //==============================================================================
create(const std::string & name)56 std::shared_ptr<World> World::create(const std::string& name)
57 {
58   return std::make_shared<World>(name);
59 }
60 
61 //==============================================================================
World(const std::string & _name)62 World::World(const std::string& _name)
63   : mName(_name),
64     mNameMgrForSkeletons("World::Skeleton | " + _name, "skeleton"),
65     mNameMgrForSimpleFrames("World::SimpleFrame | " + _name, "frame"),
66     mGravity(0.0, 0.0, -9.81),
67     mTimeStep(0.001),
68     mTime(0.0),
69     mFrame(0),
70     mRecording(new Recording(mSkeletons)),
71     onNameChanged(mNameChangedSignal)
72 {
73   mIndices.push_back(0);
74 
75   auto solver = std::make_unique<constraint::BoxedLcpConstraintSolver>();
76   setConstraintSolver(std::move(solver));
77 }
78 
79 //==============================================================================
~World()80 World::~World()
81 {
82   delete mRecording;
83 
84   for (common::Connection& connection : mNameConnectionsForSkeletons)
85     connection.disconnect();
86 
87   for (common::Connection& connection : mNameConnectionsForSimpleFrames)
88     connection.disconnect();
89 }
90 
91 //==============================================================================
clone() const92 WorldPtr World::clone() const
93 {
94   WorldPtr worldClone = World::create(mName);
95 
96   worldClone->setGravity(mGravity);
97   worldClone->setTimeStep(mTimeStep);
98 
99   auto cd = getConstraintSolver()->getCollisionDetector();
100   worldClone->getConstraintSolver()->setCollisionDetector(
101       cd->cloneWithoutCollisionObjects());
102 
103   // Clone and add each Skeleton
104   for (std::size_t i = 0; i < mSkeletons.size(); ++i)
105   {
106     worldClone->addSkeleton(mSkeletons[i]->cloneSkeleton());
107   }
108 
109   // Clone and add each SimpleFrame
110   for (std::size_t i = 0; i < mSimpleFrames.size(); ++i)
111   {
112     worldClone->addSimpleFrame(
113         mSimpleFrames[i]->clone(mSimpleFrames[i]->getParentFrame()));
114   }
115 
116   // For each newly cloned SimpleFrame, try to make its parent Frame be one of
117   // the new clones if there is a match. This is meant to minimize any possible
118   // interdependencies between the kinematics of different worlds.
119   for (std::size_t i = 0; i < worldClone->getNumSimpleFrames(); ++i)
120   {
121     dynamics::Frame* current_parent
122         = worldClone->getSimpleFrame(i)->getParentFrame();
123 
124     dynamics::SimpleFramePtr parent_candidate
125         = worldClone->getSimpleFrame(current_parent->getName());
126 
127     if (parent_candidate)
128       worldClone->getSimpleFrame(i)->setParentFrame(parent_candidate.get());
129   }
130 
131   return worldClone;
132 }
133 
134 //==============================================================================
setTimeStep(double _timeStep)135 void World::setTimeStep(double _timeStep)
136 {
137   if (_timeStep <= 0.0)
138   {
139     dtwarn << "[World] Attempting to set negative timestep. Ignoring this "
140            << "request because it can lead to undefined behavior.\n";
141     return;
142   }
143 
144   mTimeStep = _timeStep;
145   assert(mConstraintSolver);
146   mConstraintSolver->setTimeStep(_timeStep);
147   for (auto& skel : mSkeletons)
148     skel->setTimeStep(_timeStep);
149 }
150 
151 //==============================================================================
getTimeStep() const152 double World::getTimeStep() const
153 {
154   return mTimeStep;
155 }
156 
157 //==============================================================================
reset()158 void World::reset()
159 {
160   mTime = 0.0;
161   mFrame = 0;
162   mRecording->clear();
163   mConstraintSolver->clearLastCollisionResult();
164 }
165 
166 //==============================================================================
step(bool _resetCommand)167 void World::step(bool _resetCommand)
168 {
169   // Integrate velocity for unconstrained skeletons
170   for (auto& skel : mSkeletons)
171   {
172     if (!skel->isMobile())
173       continue;
174 
175     skel->computeForwardDynamics();
176     skel->integrateVelocities(mTimeStep);
177   }
178 
179   // Detect activated constraints and compute constraint impulses
180   mConstraintSolver->solve();
181 
182   // Compute velocity changes given constraint impulses
183   for (auto& skel : mSkeletons)
184   {
185     if (!skel->isMobile())
186       continue;
187 
188     if (skel->isImpulseApplied())
189     {
190       skel->computeImpulseForwardDynamics();
191       skel->setImpulseApplied(false);
192     }
193 
194     skel->integratePositions(mTimeStep);
195 
196     if (_resetCommand)
197     {
198       skel->clearInternalForces();
199       skel->clearExternalForces();
200       skel->resetCommands();
201     }
202   }
203 
204   mTime += mTimeStep;
205   mFrame++;
206 }
207 
208 //==============================================================================
setTime(double _time)209 void World::setTime(double _time)
210 {
211   mTime = _time;
212 }
213 
214 //==============================================================================
getTime() const215 double World::getTime() const
216 {
217   return mTime;
218 }
219 
220 //==============================================================================
getSimFrames() const221 int World::getSimFrames() const
222 {
223   return mFrame;
224 }
225 
226 //==============================================================================
setName(const std::string & _newName)227 const std::string& World::setName(const std::string& _newName)
228 {
229   if (_newName == mName)
230     return mName;
231 
232   const std::string oldName = mName;
233   mName = _newName;
234 
235   mNameChangedSignal.raise(oldName, mName);
236 
237   mNameMgrForSkeletons.setManagerName("World::Skeleton | " + mName);
238   mNameMgrForSimpleFrames.setManagerName("World::SimpleFrame | " + mName);
239 
240   return mName;
241 }
242 
243 //==============================================================================
getName() const244 const std::string& World::getName() const
245 {
246   return mName;
247 }
248 
249 //==============================================================================
setGravity(const Eigen::Vector3d & _gravity)250 void World::setGravity(const Eigen::Vector3d& _gravity)
251 {
252   mGravity = _gravity;
253   for (std::vector<dynamics::SkeletonPtr>::iterator it = mSkeletons.begin();
254        it != mSkeletons.end();
255        ++it)
256   {
257     (*it)->setGravity(_gravity);
258   }
259 }
260 
261 //==============================================================================
getGravity() const262 const Eigen::Vector3d& World::getGravity() const
263 {
264   return mGravity;
265 }
266 
267 //==============================================================================
getSkeleton(std::size_t _index) const268 dynamics::SkeletonPtr World::getSkeleton(std::size_t _index) const
269 {
270   if (_index < mSkeletons.size())
271     return mSkeletons[_index];
272 
273   return nullptr;
274 }
275 
276 //==============================================================================
getSkeleton(const std::string & _name) const277 dynamics::SkeletonPtr World::getSkeleton(const std::string& _name) const
278 {
279   return mNameMgrForSkeletons.getObject(_name);
280 }
281 
282 //==============================================================================
getNumSkeletons() const283 std::size_t World::getNumSkeletons() const
284 {
285   return mSkeletons.size();
286 }
287 
288 //==============================================================================
addSkeleton(const dynamics::SkeletonPtr & _skeleton)289 std::string World::addSkeleton(const dynamics::SkeletonPtr& _skeleton)
290 {
291   if (nullptr == _skeleton)
292   {
293     dtwarn << "[World::addSkeleton] Attempting to add a nullptr Skeleton to "
294            << "the world!\n";
295     return "";
296   }
297 
298   // If mSkeletons already has _skeleton, then we do nothing.
299   if (find(mSkeletons.begin(), mSkeletons.end(), _skeleton) != mSkeletons.end())
300   {
301     dtwarn << "[World::addSkeleton] Skeleton named [" << _skeleton->getName()
302            << "] is already in the world." << std::endl;
303     return _skeleton->getName();
304   }
305 
306   mSkeletons.push_back(_skeleton);
307   mMapForSkeletons[_skeleton] = _skeleton;
308 
309   mNameConnectionsForSkeletons.push_back(_skeleton->onNameChanged.connect(
310       [=](dynamics::ConstMetaSkeletonPtr skel,
311           const std::string&,
312           const std::string&) { this->handleSkeletonNameChange(skel); }));
313 
314   _skeleton->setName(
315       mNameMgrForSkeletons.issueNewNameAndAdd(_skeleton->getName(), _skeleton));
316 
317   _skeleton->setTimeStep(mTimeStep);
318   _skeleton->setGravity(mGravity);
319 
320   mIndices.push_back(mIndices.back() + _skeleton->getNumDofs());
321   mConstraintSolver->addSkeleton(_skeleton);
322 
323   // Update recording
324   mRecording->updateNumGenCoords(mSkeletons);
325 
326   return _skeleton->getName();
327 }
328 
329 //==============================================================================
removeSkeleton(const dynamics::SkeletonPtr & _skeleton)330 void World::removeSkeleton(const dynamics::SkeletonPtr& _skeleton)
331 {
332   assert(
333       _skeleton != nullptr
334       && "Attempted to remove nullptr Skeleton from world");
335 
336   if (nullptr == _skeleton)
337   {
338     dtwarn << "[World::removeSkeleton] Attempting to remove a nullptr Skeleton "
339            << "from the world!\n";
340     return;
341   }
342 
343   // Find index of _skeleton in mSkeleton.
344   std::size_t index = 0;
345   for (; index < mSkeletons.size(); ++index)
346   {
347     if (mSkeletons[index] == _skeleton)
348       break;
349   }
350 
351   // If i is equal to the number of skeletons, then _skeleton is not in
352   // mSkeleton. We do nothing.
353   if (index == mSkeletons.size())
354   {
355     dtwarn << "[World::removeSkeleton] Skeleton [" << _skeleton->getName()
356            << "] is not in the world.\n";
357     return;
358   }
359 
360   // Update mIndices.
361   for (std::size_t i = index + 1; i < mSkeletons.size() - 1; ++i)
362     mIndices[i] = mIndices[i + 1] - _skeleton->getNumDofs();
363   mIndices.pop_back();
364 
365   // Remove _skeleton from constraint handler.
366   mConstraintSolver->removeSkeleton(_skeleton);
367 
368   // Remove _skeleton from mSkeletons
369   mSkeletons.erase(
370       remove(mSkeletons.begin(), mSkeletons.end(), _skeleton),
371       mSkeletons.end());
372 
373   // Disconnect the name change monitor
374   mNameConnectionsForSkeletons[index].disconnect();
375   mNameConnectionsForSkeletons.erase(
376       mNameConnectionsForSkeletons.begin() + index);
377 
378   // Update recording
379   mRecording->updateNumGenCoords(mSkeletons);
380 
381   // Remove from NameManager
382   mNameMgrForSkeletons.removeName(_skeleton->getName());
383 
384   // Remove from the pointer map
385   mMapForSkeletons.erase(_skeleton);
386 }
387 
388 //==============================================================================
removeAllSkeletons()389 std::set<dynamics::SkeletonPtr> World::removeAllSkeletons()
390 {
391   std::set<dynamics::SkeletonPtr> ptrs;
392   for (std::vector<dynamics::SkeletonPtr>::iterator it = mSkeletons.begin(),
393                                                     end = mSkeletons.end();
394        it != end;
395        ++it)
396     ptrs.insert(*it);
397 
398   while (getNumSkeletons() > 0)
399     removeSkeleton(getSkeleton(0));
400 
401   return ptrs;
402 }
403 
404 //==============================================================================
hasSkeleton(const dynamics::ConstSkeletonPtr & skeleton) const405 bool World::hasSkeleton(const dynamics::ConstSkeletonPtr& skeleton) const
406 {
407   return std::find(mSkeletons.begin(), mSkeletons.end(), skeleton)
408          != mSkeletons.end();
409 }
410 
411 //==============================================================================
hasSkeleton(const std::string & skeletonName) const412 bool World::hasSkeleton(const std::string& skeletonName) const
413 {
414   return mNameMgrForSkeletons.hasName(skeletonName);
415 }
416 
417 //==============================================================================
getIndex(int _index) const418 int World::getIndex(int _index) const
419 {
420   return mIndices[_index];
421 }
422 
423 //==============================================================================
getSimpleFrame(std::size_t _index) const424 dynamics::SimpleFramePtr World::getSimpleFrame(std::size_t _index) const
425 {
426   if (_index < mSimpleFrames.size())
427     return mSimpleFrames[_index];
428 
429   return nullptr;
430 }
431 
432 //==============================================================================
getSimpleFrame(const std::string & _name) const433 dynamics::SimpleFramePtr World::getSimpleFrame(const std::string& _name) const
434 {
435   return mNameMgrForSimpleFrames.getObject(_name);
436 }
437 
438 //==============================================================================
getNumSimpleFrames() const439 std::size_t World::getNumSimpleFrames() const
440 {
441   return mSimpleFrames.size();
442 }
443 
444 //==============================================================================
addSimpleFrame(const dynamics::SimpleFramePtr & _frame)445 std::string World::addSimpleFrame(const dynamics::SimpleFramePtr& _frame)
446 {
447   assert(_frame != nullptr && "Attempted to add nullptr SimpleFrame to world");
448 
449   if (nullptr == _frame)
450   {
451     dtwarn << "[World::addFrame] Attempting to add a nullptr SimpleFrame to "
452               "the world!\n";
453     return "";
454   }
455 
456   if (find(mSimpleFrames.begin(), mSimpleFrames.end(), _frame)
457       != mSimpleFrames.end())
458   {
459     dtwarn << "[World::addFrame] SimpleFrame named [" << _frame->getName()
460            << "] is already in the world.\n";
461     return _frame->getName();
462   }
463 
464   mSimpleFrames.push_back(_frame);
465   mSimpleFrameToShared[_frame.get()] = _frame;
466 
467   mNameConnectionsForSimpleFrames.push_back(_frame->onNameChanged.connect(
468       [=](const dynamics::Entity* _entity,
469           const std::string&,
470           const std::string&) { this->handleSimpleFrameNameChange(_entity); }));
471 
472   _frame->setName(
473       mNameMgrForSimpleFrames.issueNewNameAndAdd(_frame->getName(), _frame));
474 
475   return _frame->getName();
476 }
477 
478 //==============================================================================
removeSimpleFrame(const dynamics::SimpleFramePtr & _frame)479 void World::removeSimpleFrame(const dynamics::SimpleFramePtr& _frame)
480 {
481   assert(
482       _frame != nullptr
483       && "Attempted to remove nullptr SimpleFrame from world");
484 
485   std::vector<dynamics::SimpleFramePtr>::iterator it
486       = find(mSimpleFrames.begin(), mSimpleFrames.end(), _frame);
487 
488   if (it == mSimpleFrames.end())
489   {
490     dtwarn << "[World::removeFrame] Frame named [" << _frame->getName()
491            << "] is not in the world.\n";
492     return;
493   }
494 
495   std::size_t index = it - mSimpleFrames.begin();
496 
497   // Remove the frame
498   mSimpleFrames.erase(mSimpleFrames.begin() + index);
499 
500   // Disconnect the name change monitor
501   mNameConnectionsForSimpleFrames[index].disconnect();
502   mNameConnectionsForSimpleFrames.erase(
503       mNameConnectionsForSimpleFrames.begin() + index);
504 
505   // Remove from NameManager
506   mNameMgrForSimpleFrames.removeName(_frame->getName());
507 
508   // Remove from the pointer map
509   mSimpleFrameToShared.erase(_frame.get());
510 }
511 
512 //==============================================================================
removeAllSimpleFrames()513 std::set<dynamics::SimpleFramePtr> World::removeAllSimpleFrames()
514 {
515   std::set<dynamics::SimpleFramePtr> ptrs;
516   for (std::vector<dynamics::SimpleFramePtr>::iterator it
517        = mSimpleFrames.begin(),
518        end = mSimpleFrames.end();
519        it != end;
520        ++it)
521     ptrs.insert(*it);
522 
523   while (getNumSimpleFrames() > 0)
524     removeSimpleFrame(getSimpleFrame(0));
525 
526   return ptrs;
527 }
528 
529 //==============================================================================
checkCollision(bool checkAllCollisions)530 bool World::checkCollision(bool checkAllCollisions)
531 {
532   collision::CollisionOption option;
533 
534   if (checkAllCollisions)
535     option.maxNumContacts = 1e+3;
536   else
537     option.maxNumContacts = 1u;
538 
539   return checkCollision(option);
540 }
541 
542 //==============================================================================
checkCollision(const collision::CollisionOption & option,collision::CollisionResult * result)543 bool World::checkCollision(
544     const collision::CollisionOption& option,
545     collision::CollisionResult* result)
546 {
547   return mConstraintSolver->getCollisionGroup()->collide(option, result);
548 }
549 
550 //==============================================================================
getLastCollisionResult() const551 const collision::CollisionResult& World::getLastCollisionResult() const
552 {
553   return mConstraintSolver->getLastCollisionResult();
554 }
555 
556 //==============================================================================
setConstraintSolver(constraint::UniqueConstraintSolverPtr solver)557 void World::setConstraintSolver(constraint::UniqueConstraintSolverPtr solver)
558 {
559   if (!solver)
560   {
561     dtwarn << "[World::setConstraintSolver] nullptr for constraint solver is "
562            << "not allowed. Doing nothing.";
563     return;
564   }
565 
566   if (mConstraintSolver)
567     solver->setFromOtherConstraintSolver(*mConstraintSolver);
568 
569   mConstraintSolver = std::move(solver);
570   mConstraintSolver->setTimeStep(mTimeStep);
571 }
572 
573 //==============================================================================
getConstraintSolver()574 constraint::ConstraintSolver* World::getConstraintSolver()
575 {
576   return mConstraintSolver.get();
577 }
578 
579 //==============================================================================
getConstraintSolver() const580 const constraint::ConstraintSolver* World::getConstraintSolver() const
581 {
582   return mConstraintSolver.get();
583 }
584 
585 //==============================================================================
bake()586 void World::bake()
587 {
588   const auto collisionResult = getConstraintSolver()->getLastCollisionResult();
589   const auto nContacts = static_cast<int>(collisionResult.getNumContacts());
590   const auto nSkeletons = getNumSkeletons();
591 
592   Eigen::VectorXd state(getIndex(nSkeletons) + 6 * nContacts);
593   for (auto i = 0u; i < getNumSkeletons(); ++i)
594   {
595     state.segment(getIndex(i), getSkeleton(i)->getNumDofs())
596         = getSkeleton(i)->getPositions();
597   }
598 
599   for (auto i = 0; i < nContacts; ++i)
600   {
601     auto begin = getIndex(nSkeletons) + i * 6;
602     state.segment(begin, 3) = collisionResult.getContact(i).point;
603     state.segment(begin + 3, 3) = collisionResult.getContact(i).force;
604   }
605 
606   mRecording->addState(state);
607 }
608 
609 //==============================================================================
getRecording()610 Recording* World::getRecording()
611 {
612   return mRecording;
613 }
614 
615 //==============================================================================
handleSkeletonNameChange(const dynamics::ConstMetaSkeletonPtr & _skeleton)616 void World::handleSkeletonNameChange(
617     const dynamics::ConstMetaSkeletonPtr& _skeleton)
618 {
619   if (nullptr == _skeleton)
620   {
621     dterr << "[World::handleSkeletonNameChange] Received a name change "
622           << "callback for a nullptr Skeleton. This is most likely a bug. "
623           << "Please report this!\n";
624     assert(false);
625     return;
626   }
627 
628   // Get the new name of the Skeleton
629   const std::string& newName = _skeleton->getName();
630 
631   // Find the shared version of the Skeleton
632   std::map<dynamics::ConstMetaSkeletonPtr, dynamics::SkeletonPtr>::iterator it
633       = mMapForSkeletons.find(_skeleton);
634   if (it == mMapForSkeletons.end())
635   {
636     dterr << "[World::handleSkeletonNameChange] Could not find Skeleton named ["
637           << _skeleton->getName() << "] in the shared_ptr map of World ["
638           << getName() << "]. This is most likely a bug. Please report this!\n";
639     assert(false);
640     return;
641   }
642   dynamics::SkeletonPtr sharedSkel = it->second;
643 
644   // Inform the NameManager of the change
645   std::string issuedName
646       = mNameMgrForSkeletons.changeObjectName(sharedSkel, newName);
647 
648   // If the name issued by the NameManger does not match, reset the name of the
649   // Skeleton to match the newly issued name.
650   if ((!issuedName.empty()) && (newName != issuedName))
651   {
652     sharedSkel->setName(issuedName);
653   }
654   else if (issuedName.empty())
655   {
656     dterr << "[World::handleSkeletonNameChange] Skeleton named ["
657           << sharedSkel->getName() << "] (" << sharedSkel << ") does not exist "
658           << "in the NameManager of World [" << getName() << "]. This is most "
659           << "likely a bug. Please report this!\n";
660     assert(false);
661     return;
662   }
663 }
664 
665 //==============================================================================
handleSimpleFrameNameChange(const dynamics::Entity * _entity)666 void World::handleSimpleFrameNameChange(const dynamics::Entity* _entity)
667 {
668   // Check that this is actually a SimpleFrame
669   const dynamics::SimpleFrame* frame
670       = dynamic_cast<const dynamics::SimpleFrame*>(_entity);
671 
672   if (nullptr == frame)
673   {
674     dterr << "[World::handleFrameNameChange] Received a callback for a nullptr "
675           << "enity. This is most likely a bug. Please report this!\n";
676     assert(false);
677     return;
678   }
679 
680   // Get the new name of the Frame
681   const std::string& newName = frame->getName();
682 
683   // Find the shared version of the Frame
684   std::map<const dynamics::SimpleFrame*, dynamics::SimpleFramePtr>::iterator it
685       = mSimpleFrameToShared.find(frame);
686   if (it == mSimpleFrameToShared.end())
687   {
688     dterr << "[World::handleFrameNameChange] Could not find SimpleFrame named ["
689           << frame->getName() << "] in the shared_ptr map of World ["
690           << getName() << "]. This is most likely a bug. Please report this!\n";
691     assert(false);
692     return;
693   }
694   dynamics::SimpleFramePtr sharedFrame = it->second;
695 
696   std::string issuedName
697       = mNameMgrForSimpleFrames.changeObjectName(sharedFrame, newName);
698 
699   if ((!issuedName.empty()) && (newName != issuedName))
700   {
701     sharedFrame->setName(issuedName);
702   }
703   else if (issuedName.empty())
704   {
705     dterr << "[World::handleFrameNameChange] SimpleFrame named ["
706           << frame->getName() << "] (" << frame << ") does not exist in the "
707           << "NameManager of World [" << getName() << "]. This is most likely "
708           << "a bug. Please report this!\n";
709     assert(false);
710     return;
711   }
712 }
713 
714 } // namespace simulation
715 } // namespace dart
716