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/BodyNode.hpp"
34 
35 #include <algorithm>
36 #include <string>
37 #include <vector>
38 
39 #include "dart/common/Console.hpp"
40 #include "dart/common/StlHelpers.hpp"
41 #include "dart/dynamics/Chain.hpp"
42 #include "dart/dynamics/EndEffector.hpp"
43 #include "dart/dynamics/Joint.hpp"
44 #include "dart/dynamics/Marker.hpp"
45 #include "dart/dynamics/Shape.hpp"
46 #include "dart/dynamics/Skeleton.hpp"
47 #include "dart/dynamics/SoftBodyNode.hpp"
48 #include "dart/math/Helpers.hpp"
49 
50 namespace dart {
51 namespace dynamics {
52 
53 //==============================================================================
54 template <
55     class DataType,
56     std::unique_ptr<DataType> (Node::*getData)() const,
57     typename VectorType = common::CloneableVector<std::unique_ptr<DataType> >,
58     typename DataMap = std::map<std::type_index, std::unique_ptr<VectorType> > >
extractDataFromNodeTypeMap(DataMap & dataMap,const BodyNode::NodeMap & nodeMap)59 static void extractDataFromNodeTypeMap(
60     DataMap& dataMap, const BodyNode::NodeMap& nodeMap)
61 {
62   for (const auto& node_it : nodeMap)
63   {
64     const std::vector<Node*>& nodes = node_it.second;
65 
66     std::pair<typename DataMap::iterator, bool> insertion
67         = dataMap.insert(typename DataMap::value_type(node_it.first, nullptr));
68 
69     typename DataMap::iterator& it = insertion.first;
70 
71     std::unique_ptr<VectorType>& data = it->second;
72     if (!data)
73       data = std::make_unique<VectorType>();
74 
75     data->getVector().resize(nodes.size());
76 
77     for (std::size_t i = 0; i < nodes.size(); ++i)
78     {
79       std::unique_ptr<DataType>& datum = data->getVector()[i];
80       datum = (nodes[i]->*getData)();
81     }
82   }
83 }
84 
85 //==============================================================================
86 template <
87     class DataType,
88     void (Node::*setData)(const DataType&),
89     typename VectorType = common::CloneableVector<std::unique_ptr<DataType> >,
90     typename DataMap = std::map<std::type_index, std::unique_ptr<VectorType> > >
setNodesFromDataTypeMap(BodyNode::NodeMap & nodeMap,const DataMap & dataMap)91 static void setNodesFromDataTypeMap(
92     BodyNode::NodeMap& nodeMap, const DataMap& dataMap)
93 {
94   typename BodyNode::NodeMap::iterator node_it = nodeMap.begin();
95   typename DataMap::const_iterator data_it = dataMap.begin();
96 
97   while (nodeMap.end() != node_it && dataMap.end() != data_it)
98   {
99     if (node_it->first == data_it->first)
100     {
101       const std::vector<Node*>& node_vec = node_it->second;
102       const std::vector<std::unique_ptr<DataType> >& data_vec
103           = data_it->second->getVector();
104 
105       // TODO(MXG): Should we report if the dimensions are mismatched?
106       std::size_t stop = std::min(node_vec.size(), data_vec.size());
107       for (std::size_t i = 0; i < stop; ++i)
108       {
109         if (data_vec[i])
110           (node_vec[i]->*setData)(*data_vec[i]);
111       }
112 
113       ++node_it;
114       ++data_it;
115     }
116     else if (node_it->first < data_it->first)
117     {
118       ++node_it;
119     }
120     else
121     {
122       ++data_it;
123     }
124   }
125 }
126 
127 //==============================================================================
SkeletonRefCountingBase()128 SkeletonRefCountingBase::SkeletonRefCountingBase()
129   : mReferenceCount(0),
130     mLockedSkeleton(std::make_shared<MutexedWeakSkeletonPtr>())
131 {
132   // Do nothing
133 }
134 
135 //==============================================================================
incrementReferenceCount() const136 void SkeletonRefCountingBase::incrementReferenceCount() const
137 {
138   int previous = std::atomic_fetch_add(&mReferenceCount, 1);
139   if (0 == previous)
140     mReferenceSkeleton = mSkeleton.lock();
141 }
142 
143 //==============================================================================
decrementReferenceCount() const144 void SkeletonRefCountingBase::decrementReferenceCount() const
145 {
146   int previous = std::atomic_fetch_sub(&mReferenceCount, 1);
147   if (1 == previous)
148     mReferenceSkeleton = nullptr;
149 }
150 
151 //==============================================================================
getSkeleton()152 SkeletonPtr SkeletonRefCountingBase::getSkeleton()
153 {
154   return mSkeleton.lock();
155 }
156 
157 //==============================================================================
getSkeleton() const158 ConstSkeletonPtr SkeletonRefCountingBase::getSkeleton() const
159 {
160   return mSkeleton.lock();
161 }
162 
163 /// SKEL_SET_FLAGS : Lock a Skeleton pointer and activate dirty flags of X for
164 /// the tree that this BodyNode belongs to, as well as the flag for the Skeleton
165 /// overall
166 #define SKEL_SET_FLAGS(X)                                                      \
167   {                                                                            \
168     SkeletonPtr skel = getSkeleton();                                          \
169     if (skel)                                                                  \
170     {                                                                          \
171       skel->mTreeCache[mTreeIndex].mDirty.X = true;                            \
172       skel->mSkelCache.mDirty.X = true;                                        \
173     }                                                                          \
174   }
175 
176 /// SET_FLAGS : A version of SKEL_SET_FLAGS that assumes a SkeletonPtr named
177 /// 'skel' has already been locked
178 #define SET_FLAGS(X)                                                           \
179   skel->mTreeCache[mTreeIndex].mDirty.X = true;                                \
180   skel->mSkelCache.mDirty.X = true;
181 
182 /// CHECK_FLAG : Check if the dirty flag X for the tree of this BodyNode is
183 /// active
184 #define CHECK_FLAG(X) skel->mTreeCache[mTreeIndex].mDirty.X
185 
186 //==============================================================================
187 typedef std::set<Entity*> EntityPtrSet;
188 
189 //==============================================================================
190 std::size_t BodyNode::msBodyNodeCount = 0;
191 
192 namespace detail {
193 
194 //==============================================================================
setAllNodeStates(BodyNode * bodyNode,const AllNodeStates & states)195 void setAllNodeStates(BodyNode* bodyNode, const AllNodeStates& states)
196 {
197   bodyNode->setAllNodeStates(states);
198 }
199 
200 //==============================================================================
getAllNodeStates(const BodyNode * bodyNode)201 AllNodeStates getAllNodeStates(const BodyNode* bodyNode)
202 {
203   return bodyNode->getAllNodeStates();
204 }
205 
206 //==============================================================================
setAllNodeProperties(BodyNode * bodyNode,const AllNodeProperties & properties)207 void setAllNodeProperties(
208     BodyNode* bodyNode, const AllNodeProperties& properties)
209 {
210   bodyNode->setAllNodeProperties(properties);
211 }
212 
213 //==============================================================================
getAllNodeProperties(const BodyNode * bodyNode)214 AllNodeProperties getAllNodeProperties(const BodyNode* bodyNode)
215 {
216   return bodyNode->getAllNodeProperties();
217 }
218 
219 //==============================================================================
BodyNodeState(const Eigen::Vector6d & Fext)220 BodyNodeState::BodyNodeState(const Eigen::Vector6d& Fext) : mFext(Fext)
221 {
222   // Do nothing
223 }
224 
225 //==============================================================================
BodyNodeAspectProperties(const std::string & name,const Inertia & _inertia,bool _isCollidable,double _frictionCoeff,double _restitutionCoeff,bool _gravityMode)226 BodyNodeAspectProperties::BodyNodeAspectProperties(
227     const std::string& name,
228     const Inertia& _inertia,
229     bool _isCollidable,
230     double _frictionCoeff,
231     double _restitutionCoeff,
232     bool _gravityMode)
233   : mName(name),
234     mInertia(_inertia),
235     mIsCollidable(_isCollidable),
236     mFrictionCoeff(_frictionCoeff),
237     mRestitutionCoeff(_restitutionCoeff),
238     mGravityMode(_gravityMode)
239 {
240   // Do nothing
241 }
242 
243 //==============================================================================
BodyNodeAspectProperties(const std::string & name,const Inertia & inertia,bool isCollidable,bool gravityMode)244 BodyNodeAspectProperties::BodyNodeAspectProperties(
245     const std::string& name,
246     const Inertia& inertia,
247     bool isCollidable,
248     bool gravityMode)
249   : mName(name),
250     mInertia(inertia),
251     mIsCollidable(isCollidable),
252     mFrictionCoeff(DART_DEFAULT_FRICTION_COEFF),
253     mRestitutionCoeff(DART_DEFAULT_RESTITUTION_COEFF),
254     mGravityMode(gravityMode)
255 {
256   // Do nothing
257 }
258 
259 } // namespace detail
260 
261 //==============================================================================
~BodyNode()262 BodyNode::~BodyNode()
263 {
264   // Delete all Nodes
265   mNodeMap.clear();
266   mNodeDestructors.clear();
267 
268   delete mParentJoint;
269 }
270 
271 //==============================================================================
asSoftBodyNode()272 SoftBodyNode* BodyNode::asSoftBodyNode()
273 {
274   return nullptr;
275 }
276 
277 //==============================================================================
asSoftBodyNode() const278 const SoftBodyNode* BodyNode::asSoftBodyNode() const
279 {
280   return nullptr;
281 }
282 
283 //==============================================================================
setAllNodeStates(const AllNodeStates & states)284 void BodyNode::setAllNodeStates(const AllNodeStates& states)
285 {
286   setNodesFromDataTypeMap<Node::State, &Node::setNodeState>(
287       mNodeMap, states.getMap());
288 }
289 
290 //==============================================================================
getAllNodeStates() const291 BodyNode::AllNodeStates BodyNode::getAllNodeStates() const
292 {
293   detail::NodeStateMap nodeStates;
294   extractDataFromNodeTypeMap<Node::State, &Node::getNodeState>(
295       nodeStates, mNodeMap);
296   return nodeStates;
297 }
298 
299 //==============================================================================
setAllNodeProperties(const AllNodeProperties & properties)300 void BodyNode::setAllNodeProperties(const AllNodeProperties& properties)
301 {
302   setNodesFromDataTypeMap<Node::Properties, &Node::setNodeProperties>(
303       mNodeMap, properties.getMap());
304 }
305 
306 //==============================================================================
getAllNodeProperties() const307 BodyNode::AllNodeProperties BodyNode::getAllNodeProperties() const
308 {
309   // TODO(MXG): Make a version of this function that will fill in a
310   // NodeProperties instance instead of creating a new one
311   detail::NodePropertiesMap nodeProperties;
312   extractDataFromNodeTypeMap<Node::Properties, &Node::getNodeProperties>(
313       nodeProperties, mNodeMap);
314   return nodeProperties;
315 }
316 
317 //==============================================================================
setProperties(const CompositeProperties & _properties)318 void BodyNode::setProperties(const CompositeProperties& _properties)
319 {
320   setCompositeProperties(_properties);
321 }
322 
323 //==============================================================================
setProperties(const AspectProperties & _properties)324 void BodyNode::setProperties(const AspectProperties& _properties)
325 {
326   setAspectProperties(_properties);
327 }
328 
329 //==============================================================================
setAspectState(const AspectState & state)330 void BodyNode::setAspectState(const AspectState& state)
331 {
332   if (mAspectState.mFext != state.mFext)
333   {
334     mAspectState.mFext = state.mFext;
335     SKEL_SET_FLAGS(mExternalForces);
336   }
337 }
338 
339 //==============================================================================
setAspectProperties(const AspectProperties & properties)340 void BodyNode::setAspectProperties(const AspectProperties& properties)
341 {
342   setName(properties.mName);
343   setInertia(properties.mInertia);
344   setGravityMode(properties.mGravityMode);
345   DART_SUPPRESS_DEPRECATED_BEGIN
346   setFrictionCoeff(properties.mFrictionCoeff);
347   setRestitutionCoeff(properties.mRestitutionCoeff);
348   DART_SUPPRESS_DEPRECATED_END
349 }
350 
351 //==============================================================================
getBodyNodeProperties() const352 BodyNode::Properties BodyNode::getBodyNodeProperties() const
353 {
354   return getCompositeProperties();
355 }
356 
357 //==============================================================================
copy(const BodyNode & otherBodyNode)358 void BodyNode::copy(const BodyNode& otherBodyNode)
359 {
360   if (this == &otherBodyNode)
361     return;
362 
363   setCompositeProperties(otherBodyNode.getCompositeProperties());
364 }
365 
366 //==============================================================================
copy(const BodyNode * otherBodyNode)367 void BodyNode::copy(const BodyNode* otherBodyNode)
368 {
369   if (nullptr == otherBodyNode)
370     return;
371 
372   copy(*otherBodyNode);
373 }
374 
375 //==============================================================================
operator =(const BodyNode & otherBodyNode)376 BodyNode& BodyNode::operator=(const BodyNode& otherBodyNode)
377 {
378   copy(otherBodyNode);
379   return *this;
380 }
381 
382 //==============================================================================
duplicateNodes(const BodyNode * otherBodyNode)383 void BodyNode::duplicateNodes(const BodyNode* otherBodyNode)
384 {
385   if (nullptr == otherBodyNode)
386   {
387     dterr << "[BodyNode::duplicateNodes] You have asked to duplicate the Nodes "
388           << "of a nullptr, which is not allowed!\n";
389     assert(false);
390     return;
391   }
392 
393   const NodeMap& otherMap = otherBodyNode->mNodeMap;
394   for (const auto& vec : otherMap)
395   {
396     for (const auto& node : vec.second)
397       node->cloneNode(this)->attach();
398   }
399 }
400 
401 //==============================================================================
matchNodes(const BodyNode * otherBodyNode)402 void BodyNode::matchNodes(const BodyNode* otherBodyNode)
403 {
404   if (nullptr == otherBodyNode)
405   {
406     dterr << "[BodyNode::matchNodes] You have asked to match the Nodes of a "
407           << "nullptr, which is not allowed!\n";
408     assert(false);
409     return;
410   }
411 
412   for (auto& cleaner : mNodeDestructors)
413     cleaner->getNode()->stageForRemoval();
414 
415   duplicateNodes(otherBodyNode);
416 }
417 
418 //==============================================================================
setName(const std::string & _name)419 const std::string& BodyNode::setName(const std::string& _name)
420 {
421   // If it already has the requested name, do nothing
422   if (mAspectProperties.mName == _name)
423     return mAspectProperties.mName;
424 
425   const std::string oldName = mAspectProperties.mName;
426 
427   // If the BodyNode belongs to a Skeleton, consult the Skeleton's NameManager
428   const SkeletonPtr& skel = getSkeleton();
429   if (skel)
430   {
431     skel->mNameMgrForBodyNodes.removeName(mAspectProperties.mName);
432     SoftBodyNode* softnode = dynamic_cast<SoftBodyNode*>(this);
433     if (softnode)
434       skel->mNameMgrForSoftBodyNodes.removeName(mAspectProperties.mName);
435 
436     mAspectProperties.mName = _name;
437     skel->addEntryToBodyNodeNameMgr(this);
438 
439     if (softnode)
440       skel->addEntryToSoftBodyNodeNameMgr(softnode);
441   }
442   else
443   {
444     mAspectProperties.mName = _name;
445   }
446 
447   incrementVersion();
448   Entity::mNameChangedSignal.raise(this, oldName, mAspectProperties.mName);
449 
450   // Return the final name (which might have been altered by the Skeleton's
451   // NameManager)
452   return mAspectProperties.mName;
453 }
454 
455 //==============================================================================
getName() const456 const std::string& BodyNode::getName() const
457 {
458   return mAspectProperties.mName;
459 }
460 
461 //==============================================================================
setGravityMode(bool _gravityMode)462 void BodyNode::setGravityMode(bool _gravityMode)
463 {
464   if (mAspectProperties.mGravityMode == _gravityMode)
465     return;
466 
467   mAspectProperties.mGravityMode = _gravityMode;
468 
469   SKEL_SET_FLAGS(mGravityForces);
470   SKEL_SET_FLAGS(mCoriolisAndGravityForces);
471 
472   incrementVersion();
473 }
474 
475 //==============================================================================
getGravityMode() const476 bool BodyNode::getGravityMode() const
477 {
478   return mAspectProperties.mGravityMode;
479 }
480 
481 //==============================================================================
isCollidable() const482 bool BodyNode::isCollidable() const
483 {
484   return mAspectProperties.mIsCollidable;
485 }
486 
487 //==============================================================================
setCollidable(bool _isCollidable)488 void BodyNode::setCollidable(bool _isCollidable)
489 {
490   mAspectProperties.mIsCollidable = _isCollidable;
491 }
492 
493 //==============================================================================
checkMass(const BodyNode & bodyNode,const double mass)494 void checkMass(const BodyNode& bodyNode, const double mass)
495 {
496   if (mass <= 0.0)
497   {
498     dtwarn << "[BodyNode] A negative or zero mass [" << mass
499            << "] is set to BodyNode [" << bodyNode.getName()
500            << "], which can cause invalid physical behavior or segfault. "
501            << "Consider setting positive value instead.\n";
502   }
503 }
504 
505 //==============================================================================
setMass(const double mass)506 void BodyNode::setMass(const double mass)
507 {
508   checkMass(*this, mass);
509 
510   mAspectProperties.mInertia.setMass(mass);
511 
512   dirtyArticulatedInertia();
513   const SkeletonPtr& skel = getSkeleton();
514   if (skel)
515     skel->updateTotalMass();
516 }
517 
518 //==============================================================================
getMass() const519 double BodyNode::getMass() const
520 {
521   return mAspectProperties.mInertia.getMass();
522 }
523 
524 //==============================================================================
setMomentOfInertia(double _Ixx,double _Iyy,double _Izz,double _Ixy,double _Ixz,double _Iyz)525 void BodyNode::setMomentOfInertia(
526     double _Ixx,
527     double _Iyy,
528     double _Izz,
529     double _Ixy,
530     double _Ixz,
531     double _Iyz)
532 {
533   mAspectProperties.mInertia.setMoment(_Ixx, _Iyy, _Izz, _Ixy, _Ixz, _Iyz);
534 
535   dirtyArticulatedInertia();
536 }
537 
538 //==============================================================================
getMomentOfInertia(double & _Ixx,double & _Iyy,double & _Izz,double & _Ixy,double & _Ixz,double & _Iyz) const539 void BodyNode::getMomentOfInertia(
540     double& _Ixx,
541     double& _Iyy,
542     double& _Izz,
543     double& _Ixy,
544     double& _Ixz,
545     double& _Iyz) const
546 {
547   _Ixx = mAspectProperties.mInertia.getParameter(Inertia::I_XX);
548   _Iyy = mAspectProperties.mInertia.getParameter(Inertia::I_YY);
549   _Izz = mAspectProperties.mInertia.getParameter(Inertia::I_ZZ);
550 
551   _Ixy = mAspectProperties.mInertia.getParameter(Inertia::I_XY);
552   _Ixz = mAspectProperties.mInertia.getParameter(Inertia::I_XZ);
553   _Iyz = mAspectProperties.mInertia.getParameter(Inertia::I_YZ);
554 }
555 
556 //==============================================================================
getSpatialInertia() const557 const Eigen::Matrix6d& BodyNode::getSpatialInertia() const
558 {
559   return mAspectProperties.mInertia.getSpatialTensor();
560 }
561 
562 //==============================================================================
setInertia(const Inertia & inertia)563 void BodyNode::setInertia(const Inertia& inertia)
564 {
565   if (inertia == mAspectProperties.mInertia)
566     return;
567 
568   checkMass(*this, inertia.getMass());
569 
570   mAspectProperties.mInertia = inertia;
571 
572   dirtyArticulatedInertia();
573   const SkeletonPtr& skel = getSkeleton();
574   if (skel)
575     skel->updateTotalMass();
576 
577   incrementVersion();
578 }
579 
580 //==============================================================================
getInertia() const581 const Inertia& BodyNode::getInertia() const
582 {
583   return mAspectProperties.mInertia;
584 }
585 
586 //==============================================================================
getArticulatedInertia() const587 const math::Inertia& BodyNode::getArticulatedInertia() const
588 {
589   const ConstSkeletonPtr& skel = getSkeleton();
590   if (skel && CHECK_FLAG(mArticulatedInertia))
591     skel->updateArticulatedInertia(mTreeIndex);
592 
593   return mArtInertia;
594 }
595 
596 //==============================================================================
getArticulatedInertiaImplicit() const597 const math::Inertia& BodyNode::getArticulatedInertiaImplicit() const
598 {
599   const ConstSkeletonPtr& skel = getSkeleton();
600   if (skel && CHECK_FLAG(mArticulatedInertia))
601     skel->updateArticulatedInertia(mTreeIndex);
602 
603   return mArtInertiaImplicit;
604 }
605 
606 //==============================================================================
setLocalCOM(const Eigen::Vector3d & _com)607 void BodyNode::setLocalCOM(const Eigen::Vector3d& _com)
608 {
609   mAspectProperties.mInertia.setLocalCOM(_com);
610 
611   dirtyArticulatedInertia();
612 }
613 
614 //==============================================================================
getLocalCOM() const615 const Eigen::Vector3d& BodyNode::getLocalCOM() const
616 {
617   return mAspectProperties.mInertia.getLocalCOM();
618 }
619 
620 //==============================================================================
getCOM(const Frame * _withRespectTo) const621 Eigen::Vector3d BodyNode::getCOM(const Frame* _withRespectTo) const
622 {
623   return getTransform(_withRespectTo) * getLocalCOM();
624 }
625 
626 //==============================================================================
getCOMLinearVelocity(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const627 Eigen::Vector3d BodyNode::getCOMLinearVelocity(
628     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
629 {
630   return getLinearVelocity(getLocalCOM(), _relativeTo, _inCoordinatesOf);
631 }
632 
633 //==============================================================================
getCOMSpatialVelocity() const634 Eigen::Vector6d BodyNode::getCOMSpatialVelocity() const
635 {
636   return getSpatialVelocity(getLocalCOM());
637 }
638 
639 //==============================================================================
getCOMSpatialVelocity(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const640 Eigen::Vector6d BodyNode::getCOMSpatialVelocity(
641     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
642 {
643   return getSpatialVelocity(getLocalCOM(), _relativeTo, _inCoordinatesOf);
644 }
645 
646 //==============================================================================
getCOMLinearAcceleration(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const647 Eigen::Vector3d BodyNode::getCOMLinearAcceleration(
648     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
649 {
650   return getLinearAcceleration(getLocalCOM(), _relativeTo, _inCoordinatesOf);
651 }
652 
653 //==============================================================================
getCOMSpatialAcceleration() const654 Eigen::Vector6d BodyNode::getCOMSpatialAcceleration() const
655 {
656   return getSpatialAcceleration(getLocalCOM());
657 }
658 
659 //==============================================================================
getCOMSpatialAcceleration(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const660 Eigen::Vector6d BodyNode::getCOMSpatialAcceleration(
661     const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
662 {
663   return getSpatialAcceleration(getLocalCOM(), _relativeTo, _inCoordinatesOf);
664 }
665 
666 //==============================================================================
setFrictionCoeff(double _coeff)667 void BodyNode::setFrictionCoeff(double _coeff)
668 {
669   // Below code block is to set the friction coefficients of all the current
670   // dynamics aspects of this BodyNode as a stopgap solution. However, this
671   // won't help for new ShapeNodes that get added later.
672   auto shapeNodes = getShapeNodesWith<DynamicsAspect>();
673   for (auto& shapeNode : shapeNodes)
674   {
675     auto* dynamicsAspect = shapeNode->getDynamicsAspect();
676     dynamicsAspect->setFrictionCoeff(_coeff);
677   }
678 
679   if (mAspectProperties.mFrictionCoeff == _coeff)
680     return;
681 
682   assert(
683       0.0 <= _coeff && "Coefficient of friction should be non-negative value.");
684   mAspectProperties.mFrictionCoeff = _coeff;
685 
686   incrementVersion();
687 }
688 
689 //==============================================================================
getFrictionCoeff() const690 double BodyNode::getFrictionCoeff() const
691 {
692   return mAspectProperties.mFrictionCoeff;
693 }
694 
695 //==============================================================================
setRestitutionCoeff(double _coeff)696 void BodyNode::setRestitutionCoeff(double _coeff)
697 {
698   // Below code block is to set the restitution coefficients of all the current
699   // dynamics aspects of this BodyNode as a stopgap solution. However, this
700   // won't help for new ShapeNodes that get added later.
701   auto shapeNodes = getShapeNodesWith<DynamicsAspect>();
702   for (auto& shapeNode : shapeNodes)
703   {
704     auto* dynamicsAspect = shapeNode->getDynamicsAspect();
705     dynamicsAspect->setFrictionCoeff(_coeff);
706   }
707 
708   if (_coeff == mAspectProperties.mRestitutionCoeff)
709     return;
710 
711   assert(
712       0.0 <= _coeff && _coeff <= 1.0
713       && "Coefficient of restitution should be in range of [0, 1].");
714   mAspectProperties.mRestitutionCoeff = _coeff;
715 
716   incrementVersion();
717 }
718 
719 //==============================================================================
getRestitutionCoeff() const720 double BodyNode::getRestitutionCoeff() const
721 {
722   return mAspectProperties.mRestitutionCoeff;
723 }
724 
725 //==============================================================================
getIndexInSkeleton() const726 std::size_t BodyNode::getIndexInSkeleton() const
727 {
728   return mIndexInSkeleton;
729 }
730 
731 //==============================================================================
getIndexInTree() const732 std::size_t BodyNode::getIndexInTree() const
733 {
734   return mIndexInTree;
735 }
736 
737 //==============================================================================
getTreeIndex() const738 std::size_t BodyNode::getTreeIndex() const
739 {
740   return mTreeIndex;
741 }
742 
743 //==============================================================================
checkSkeletonNodeAgreement(const BodyNode * _bodyNode,const ConstSkeletonPtr & _newSkeleton,const BodyNode * _newParent,const std::string & _function,const std::string & _operation)744 static bool checkSkeletonNodeAgreement(
745     const BodyNode* _bodyNode,
746     const ConstSkeletonPtr& _newSkeleton,
747     const BodyNode* _newParent,
748     const std::string& _function,
749     const std::string& _operation)
750 {
751   if (nullptr == _newSkeleton)
752   {
753     dterr << "[BodyNode::" << _function << "] Attempting to " << _operation
754           << " a BodyNode tree starting "
755           << "from [" << _bodyNode->getName() << "] in the Skeleton named ["
756           << _bodyNode->getSkeleton()->getName()
757           << "] into a nullptr Skeleton.\n";
758     return false;
759   }
760 
761   if (_newParent && _newSkeleton != _newParent->getSkeleton())
762   {
763     dterr << "[BodyNode::" << _function << "] Mismatch between the specified "
764           << "Skeleton [" << _newSkeleton->getName() << "] (" << _newSkeleton
765           << ") and the specified new parent BodyNode ["
766           << _newParent->getName() << "] whose actual Skeleton is named ["
767           << _newParent->getSkeleton()->getName() << "] ("
768           << _newParent->getSkeleton() << ") while attempting to " << _operation
769           << " the BodyNode [" << _bodyNode->getName() << "] from the "
770           << "Skeleton named [" << _bodyNode->getSkeleton()->getName() << "] ("
771           << _bodyNode->getSkeleton() << ").\n";
772     return false;
773   }
774 
775   return true;
776 }
777 
778 //==============================================================================
remove(const std::string & _name)779 SkeletonPtr BodyNode::remove(const std::string& _name)
780 {
781   return split(_name);
782 }
783 
784 //==============================================================================
moveTo(BodyNode * _newParent)785 bool BodyNode::moveTo(BodyNode* _newParent)
786 {
787   if (nullptr == _newParent)
788     return getSkeleton()->moveBodyNodeTree(
789         getParentJoint(), this, getSkeleton(), nullptr);
790   else
791     return getSkeleton()->moveBodyNodeTree(
792         getParentJoint(), this, _newParent->getSkeleton(), _newParent);
793 }
794 
795 //==============================================================================
moveTo(const SkeletonPtr & _newSkeleton,BodyNode * _newParent)796 bool BodyNode::moveTo(const SkeletonPtr& _newSkeleton, BodyNode* _newParent)
797 {
798   if (checkSkeletonNodeAgreement(
799           this, _newSkeleton, _newParent, "moveTo", "move"))
800   {
801     return getSkeleton()->moveBodyNodeTree(
802         getParentJoint(), this, _newSkeleton, _newParent);
803   }
804 
805   return false;
806 }
807 
808 //==============================================================================
split(const std::string & _skeletonName)809 SkeletonPtr BodyNode::split(const std::string& _skeletonName)
810 {
811   const SkeletonPtr& skel
812       = Skeleton::create(getSkeleton()->getAspectProperties());
813   skel->setName(_skeletonName);
814   moveTo(skel, nullptr);
815   return skel;
816 }
817 
818 //==============================================================================
copyTo(BodyNode * _newParent,bool _recursive)819 std::pair<Joint*, BodyNode*> BodyNode::copyTo(
820     BodyNode* _newParent, bool _recursive)
821 {
822   if (nullptr == _newParent)
823     return getSkeleton()->cloneBodyNodeTree(
824         nullptr, this, getSkeleton(), nullptr, _recursive);
825   else
826     return getSkeleton()->cloneBodyNodeTree(
827         nullptr, this, _newParent->getSkeleton(), _newParent, _recursive);
828 }
829 
830 //==============================================================================
copyTo(const SkeletonPtr & _newSkeleton,BodyNode * _newParent,bool _recursive) const831 std::pair<Joint*, BodyNode*> BodyNode::copyTo(
832     const SkeletonPtr& _newSkeleton,
833     BodyNode* _newParent,
834     bool _recursive) const
835 {
836   if (checkSkeletonNodeAgreement(
837           this, _newSkeleton, _newParent, "copyTo", "copy"))
838   {
839     return getSkeleton()->cloneBodyNodeTree(
840         nullptr, this, _newSkeleton, _newParent, _recursive);
841   }
842 
843   return std::pair<Joint*, BodyNode*>(nullptr, nullptr);
844 }
845 
846 //==============================================================================
copyAs(const std::string & _skeletonName,bool _recursive) const847 SkeletonPtr BodyNode::copyAs(
848     const std::string& _skeletonName, bool _recursive) const
849 {
850   const SkeletonPtr& skel
851       = Skeleton::create(getSkeleton()->getAspectProperties());
852   skel->setName(_skeletonName);
853   copyTo(skel, nullptr, _recursive);
854   return skel;
855 }
856 
857 //==============================================================================
getSkeleton()858 SkeletonPtr BodyNode::getSkeleton()
859 {
860   return mSkeleton.lock();
861 }
862 
863 //==============================================================================
getSkeleton() const864 ConstSkeletonPtr BodyNode::getSkeleton() const
865 {
866   return mSkeleton.lock();
867 }
868 
869 //==============================================================================
getParentJoint()870 Joint* BodyNode::getParentJoint()
871 {
872   return mParentJoint;
873 }
874 
875 //==============================================================================
getParentJoint() const876 const Joint* BodyNode::getParentJoint() const
877 {
878   return mParentJoint;
879 }
880 
881 //==============================================================================
getParentBodyNode()882 BodyNode* BodyNode::getParentBodyNode()
883 {
884   return mParentBodyNode;
885 }
886 
887 //==============================================================================
getParentBodyNode() const888 const BodyNode* BodyNode::getParentBodyNode() const
889 {
890   return mParentBodyNode;
891 }
892 
893 //==============================================================================
addChildBodyNode(BodyNode * _body)894 void BodyNode::addChildBodyNode(BodyNode* _body)
895 {
896   assert(_body != nullptr);
897 
898   if (std::find(mChildBodyNodes.begin(), mChildBodyNodes.end(), _body)
899       != mChildBodyNodes.end())
900   {
901     dtwarn << "[BodyNode::addChildBodyNode] Attempting to add a BodyNode '"
902            << _body->getName() << "' as a child BodyNode of '" << getName()
903            << "', which is already its parent." << std::endl;
904     return;
905   }
906 
907   mChildBodyNodes.push_back(_body);
908   _body->mParentBodyNode = this;
909   _body->changeParentFrame(this);
910 }
911 
912 //==============================================================================
getNumChildBodyNodes() const913 std::size_t BodyNode::getNumChildBodyNodes() const
914 {
915   return mChildBodyNodes.size();
916 }
917 
918 //==============================================================================
getChildBodyNode(std::size_t _index)919 BodyNode* BodyNode::getChildBodyNode(std::size_t _index)
920 {
921   return common::getVectorObjectIfAvailable<BodyNode*>(_index, mChildBodyNodes);
922 }
923 
924 //==============================================================================
getChildBodyNode(std::size_t _index) const925 const BodyNode* BodyNode::getChildBodyNode(std::size_t _index) const
926 {
927   return common::getVectorObjectIfAvailable<BodyNode*>(_index, mChildBodyNodes);
928 }
929 
930 //==============================================================================
getNumChildJoints() const931 std::size_t BodyNode::getNumChildJoints() const
932 {
933   return mChildBodyNodes.size();
934 }
935 
936 //==============================================================================
getChildJoint(std::size_t _index)937 Joint* BodyNode::getChildJoint(std::size_t _index)
938 {
939   BodyNode* childBodyNode = getChildBodyNode(_index);
940 
941   if (childBodyNode)
942     return childBodyNode->getParentJoint();
943   else
944     return nullptr;
945 }
946 
947 //==============================================================================
getChildJoint(std::size_t _index) const948 const Joint* BodyNode::getChildJoint(std::size_t _index) const
949 {
950   return const_cast<BodyNode*>(this)->getChildJoint(_index);
951 }
952 
953 //==============================================================================
DART_BAKE_SPECIALIZED_NODE_DEFINITIONS(BodyNode,ShapeNode) const954 DART_BAKE_SPECIALIZED_NODE_DEFINITIONS(BodyNode, ShapeNode)
955 
956 //==============================================================================
957 const std::vector<ShapeNode*> BodyNode::getShapeNodes()
958 {
959   const auto numShapeNodes = getNumShapeNodes();
960 
961   std::vector<ShapeNode*> shapeNodes(numShapeNodes);
962 
963   for (auto i = 0u; i < numShapeNodes; ++i)
964     shapeNodes[i] = getShapeNode(i);
965 
966   return shapeNodes;
967 }
968 
969 //==============================================================================
getShapeNodes() const970 const std::vector<const ShapeNode*> BodyNode::getShapeNodes() const
971 {
972   const auto numShapeNodes = getNumShapeNodes();
973 
974   std::vector<const ShapeNode*> shapeNodes(numShapeNodes);
975 
976   for (auto i = 0u; i < numShapeNodes; ++i)
977     shapeNodes[i] = getShapeNode(i);
978 
979   return shapeNodes;
980 }
981 
982 //==============================================================================
removeAllShapeNodes()983 void BodyNode::removeAllShapeNodes()
984 {
985   auto shapeNodes = getShapeNodes();
986   for (auto shapeNode : shapeNodes)
987     shapeNode->remove();
988 }
989 
990 //==============================================================================
DART_BAKE_SPECIALIZED_NODE_DEFINITIONS(BodyNode,EndEffector)991 DART_BAKE_SPECIALIZED_NODE_DEFINITIONS(BodyNode, EndEffector)
992 
993 //==============================================================================
994 EndEffector* BodyNode::createEndEffector(
995     const EndEffector::BasicProperties& _properties)
996 {
997   return createNode<EndEffector>(_properties);
998 }
999 
1000 //==============================================================================
createEndEffector(const std::string & _name)1001 EndEffector* BodyNode::createEndEffector(const std::string& _name)
1002 {
1003   EndEffector::BasicProperties properties;
1004   properties.mName = _name;
1005 
1006   return createNode<EndEffector>(properties);
1007 }
1008 
1009 //==============================================================================
createEndEffector(const char * _name)1010 EndEffector* BodyNode::createEndEffector(const char* _name)
1011 {
1012   return createEndEffector(std::string(_name));
1013 }
1014 
1015 //==============================================================================
DART_BAKE_SPECIALIZED_NODE_DEFINITIONS(BodyNode,Marker)1016 DART_BAKE_SPECIALIZED_NODE_DEFINITIONS(BodyNode, Marker)
1017 
1018 //==============================================================================
1019 Marker* BodyNode::createMarker(
1020     const std::string& name,
1021     const Eigen::Vector3d& position,
1022     const Eigen::Vector4d& color)
1023 {
1024   Marker::BasicProperties properties;
1025   properties.mName = name;
1026   properties.mRelativeTf.translation() = position;
1027   properties.mColor = color;
1028 
1029   return createNode<Marker>(properties);
1030 }
1031 
1032 //==============================================================================
createMarker(const Marker::BasicProperties & properties)1033 Marker* BodyNode::createMarker(const Marker::BasicProperties& properties)
1034 {
1035   return createNode<Marker>(properties);
1036 }
1037 
1038 //==============================================================================
dependsOn(std::size_t _genCoordIndex) const1039 bool BodyNode::dependsOn(std::size_t _genCoordIndex) const
1040 {
1041   return std::binary_search(
1042       mDependentGenCoordIndices.begin(),
1043       mDependentGenCoordIndices.end(),
1044       _genCoordIndex);
1045 }
1046 
1047 //==============================================================================
getNumDependentGenCoords() const1048 std::size_t BodyNode::getNumDependentGenCoords() const
1049 {
1050   return mDependentGenCoordIndices.size();
1051 }
1052 
1053 //==============================================================================
getDependentGenCoordIndex(std::size_t _arrayIndex) const1054 std::size_t BodyNode::getDependentGenCoordIndex(std::size_t _arrayIndex) const
1055 {
1056   assert(_arrayIndex < mDependentGenCoordIndices.size());
1057 
1058   return mDependentGenCoordIndices[_arrayIndex];
1059 }
1060 
1061 //==============================================================================
getDependentGenCoordIndices() const1062 const std::vector<std::size_t>& BodyNode::getDependentGenCoordIndices() const
1063 {
1064   return mDependentGenCoordIndices;
1065 }
1066 
1067 //==============================================================================
getNumDependentDofs() const1068 std::size_t BodyNode::getNumDependentDofs() const
1069 {
1070   return mDependentDofs.size();
1071 }
1072 
1073 //==============================================================================
getDependentDof(std::size_t _index)1074 DegreeOfFreedom* BodyNode::getDependentDof(std::size_t _index)
1075 {
1076   return common::getVectorObjectIfAvailable<DegreeOfFreedom*>(
1077       _index, mDependentDofs);
1078 }
1079 
1080 //==============================================================================
getDependentDof(std::size_t _index) const1081 const DegreeOfFreedom* BodyNode::getDependentDof(std::size_t _index) const
1082 {
1083   return common::getVectorObjectIfAvailable<DegreeOfFreedom*>(
1084       _index, mDependentDofs);
1085 }
1086 
1087 //==============================================================================
getDependentDofs()1088 const std::vector<DegreeOfFreedom*>& BodyNode::getDependentDofs()
1089 {
1090   return mDependentDofs;
1091 }
1092 
1093 //==============================================================================
getDependentDofs() const1094 const std::vector<const DegreeOfFreedom*>& BodyNode::getDependentDofs() const
1095 {
1096   return mConstDependentDofs;
1097 }
1098 
1099 //==============================================================================
getChainDofs() const1100 const std::vector<const DegreeOfFreedom*> BodyNode::getChainDofs() const
1101 {
1102   // TODO(MXG): Consider templating the Criteria for const BodyNodes so that we
1103   // don't need a const_cast here. That said, the const_cast isn't hurting
1104   // anything, because the Criteria function would work just as well operating
1105   // on const BodyNodes.
1106   Chain::Criteria criteria(const_cast<BodyNode*>(this), nullptr);
1107   std::vector<BodyNode*> bn_chain = criteria.satisfy();
1108   std::vector<const DegreeOfFreedom*> dofs;
1109   dofs.reserve(getNumDependentGenCoords());
1110   for (std::vector<BodyNode*>::reverse_iterator rit = bn_chain.rbegin();
1111        rit != bn_chain.rend();
1112        ++rit)
1113   {
1114     std::size_t nDofs = (*rit)->getParentJoint()->getNumDofs();
1115     for (std::size_t i = 0; i < nDofs; ++i)
1116       dofs.push_back((*rit)->getParentJoint()->getDof(i));
1117   }
1118 
1119   return dofs;
1120 }
1121 
1122 //==============================================================================
getRelativeTransform() const1123 const Eigen::Isometry3d& BodyNode::getRelativeTransform() const
1124 {
1125   return mParentJoint->getRelativeTransform();
1126 }
1127 
1128 //==============================================================================
getRelativeSpatialVelocity() const1129 const Eigen::Vector6d& BodyNode::getRelativeSpatialVelocity() const
1130 {
1131   return mParentJoint->getRelativeSpatialVelocity();
1132 }
1133 
1134 //==============================================================================
getRelativeSpatialAcceleration() const1135 const Eigen::Vector6d& BodyNode::getRelativeSpatialAcceleration() const
1136 {
1137   return mParentJoint->getRelativeSpatialAcceleration();
1138 }
1139 
1140 //==============================================================================
getPrimaryRelativeAcceleration() const1141 const Eigen::Vector6d& BodyNode::getPrimaryRelativeAcceleration() const
1142 {
1143   return mParentJoint->getRelativePrimaryAcceleration();
1144 }
1145 
1146 //==============================================================================
getPartialAcceleration() const1147 const Eigen::Vector6d& BodyNode::getPartialAcceleration() const
1148 {
1149   if (mIsPartialAccelerationDirty)
1150     updatePartialAcceleration();
1151 
1152   return mPartialAcceleration;
1153 }
1154 
1155 //==============================================================================
getJacobian() const1156 const math::Jacobian& BodyNode::getJacobian() const
1157 {
1158   if (mIsBodyJacobianDirty)
1159     updateBodyJacobian();
1160 
1161   return mBodyJacobian;
1162 }
1163 
1164 //==============================================================================
getWorldJacobian() const1165 const math::Jacobian& BodyNode::getWorldJacobian() const
1166 {
1167   if (mIsWorldJacobianDirty)
1168     updateWorldJacobian();
1169 
1170   return mWorldJacobian;
1171 }
1172 
1173 //==============================================================================
getJacobianSpatialDeriv() const1174 const math::Jacobian& BodyNode::getJacobianSpatialDeriv() const
1175 {
1176   if (mIsBodyJacobianSpatialDerivDirty)
1177     updateBodyJacobianSpatialDeriv();
1178 
1179   return mBodyJacobianSpatialDeriv;
1180 }
1181 
1182 //==============================================================================
getJacobianClassicDeriv() const1183 const math::Jacobian& BodyNode::getJacobianClassicDeriv() const
1184 {
1185   if (mIsWorldJacobianClassicDerivDirty)
1186     updateWorldJacobianClassicDeriv();
1187 
1188   return mWorldJacobianClassicDeriv;
1189 }
1190 
1191 //==============================================================================
getBodyVelocityChange() const1192 const Eigen::Vector6d& BodyNode::getBodyVelocityChange() const
1193 {
1194   return mDelV;
1195 }
1196 
1197 //==============================================================================
setColliding(bool _isColliding)1198 void BodyNode::setColliding(bool _isColliding)
1199 {
1200   mIsColliding = _isColliding;
1201 }
1202 
1203 //==============================================================================
isColliding()1204 bool BodyNode::isColliding()
1205 {
1206   return mIsColliding;
1207 }
1208 
1209 //==============================================================================
addExtForce(const Eigen::Vector3d & _force,const Eigen::Vector3d & _offset,bool _isForceLocal,bool _isOffsetLocal)1210 void BodyNode::addExtForce(
1211     const Eigen::Vector3d& _force,
1212     const Eigen::Vector3d& _offset,
1213     bool _isForceLocal,
1214     bool _isOffsetLocal)
1215 {
1216   Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
1217   Eigen::Vector6d F = Eigen::Vector6d::Zero();
1218   const Eigen::Isometry3d& W = getWorldTransform();
1219 
1220   if (_isOffsetLocal)
1221     T.translation() = _offset;
1222   else
1223     T.translation() = W.inverse() * _offset;
1224 
1225   if (_isForceLocal)
1226     F.tail<3>() = _force;
1227   else
1228     F.tail<3>() = W.linear().transpose() * _force;
1229 
1230   mAspectState.mFext += math::dAdInvT(T, F);
1231 
1232   SKEL_SET_FLAGS(mExternalForces);
1233 }
1234 
1235 //==============================================================================
setExtForce(const Eigen::Vector3d & _force,const Eigen::Vector3d & _offset,bool _isForceLocal,bool _isOffsetLocal)1236 void BodyNode::setExtForce(
1237     const Eigen::Vector3d& _force,
1238     const Eigen::Vector3d& _offset,
1239     bool _isForceLocal,
1240     bool _isOffsetLocal)
1241 {
1242   Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
1243   Eigen::Vector6d F = Eigen::Vector6d::Zero();
1244   const Eigen::Isometry3d& W = getWorldTransform();
1245 
1246   if (_isOffsetLocal)
1247     T.translation() = _offset;
1248   else
1249     T.translation() = W.inverse() * _offset;
1250 
1251   if (_isForceLocal)
1252     F.tail<3>() = _force;
1253   else
1254     F.tail<3>() = W.linear().transpose() * _force;
1255 
1256   mAspectState.mFext = math::dAdInvT(T, F);
1257 
1258   SKEL_SET_FLAGS(mExternalForces);
1259 }
1260 
1261 //==============================================================================
addExtTorque(const Eigen::Vector3d & _torque,bool _isLocal)1262 void BodyNode::addExtTorque(const Eigen::Vector3d& _torque, bool _isLocal)
1263 {
1264   if (_isLocal)
1265     mAspectState.mFext.head<3>() += _torque;
1266   else
1267     mAspectState.mFext.head<3>()
1268         += getWorldTransform().linear().transpose() * _torque;
1269 
1270   SKEL_SET_FLAGS(mExternalForces);
1271 }
1272 
1273 //==============================================================================
setExtTorque(const Eigen::Vector3d & _torque,bool _isLocal)1274 void BodyNode::setExtTorque(const Eigen::Vector3d& _torque, bool _isLocal)
1275 {
1276   if (_isLocal)
1277     mAspectState.mFext.head<3>() = _torque;
1278   else
1279     mAspectState.mFext.head<3>()
1280         = getWorldTransform().linear().transpose() * _torque;
1281 
1282   SKEL_SET_FLAGS(mExternalForces);
1283 }
1284 
1285 //==============================================================================
BodyNode(BodyNode * _parentBodyNode,Joint * _parentJoint,const Properties & _properties)1286 BodyNode::BodyNode(
1287     BodyNode* _parentBodyNode,
1288     Joint* _parentJoint,
1289     const Properties& _properties)
1290   : Entity(ConstructFrame),
1291     Frame(Frame::World()),
1292     TemplatedJacobianNode<BodyNode>(this),
1293     mID(BodyNode::msBodyNodeCount++),
1294     mIsColliding(false),
1295     mParentJoint(_parentJoint),
1296     mParentBodyNode(nullptr),
1297     mPartialAcceleration(Eigen::Vector6d::Zero()),
1298     mIsPartialAccelerationDirty(true),
1299     mF(Eigen::Vector6d::Zero()),
1300     mFgravity(Eigen::Vector6d::Zero()),
1301     mArtInertia(Eigen::Matrix6d::Identity()),
1302     mArtInertiaImplicit(Eigen::Matrix6d::Identity()),
1303     mBiasForce(Eigen::Vector6d::Zero()),
1304     mCg_dV(Eigen::Vector6d::Zero()),
1305     mCg_F(Eigen::Vector6d::Zero()),
1306     mG_F(Eigen::Vector6d::Zero()),
1307     mFext_F(Eigen::Vector6d::Zero()),
1308     mM_dV(Eigen::Vector6d::Zero()),
1309     mM_F(Eigen::Vector6d::Zero()),
1310     mInvM_c(Eigen::Vector6d::Zero()),
1311     mInvM_U(Eigen::Vector6d::Zero()),
1312     mArbitrarySpatial(Eigen::Vector6d::Zero()),
1313     mDelV(Eigen::Vector6d::Zero()),
1314     mBiasImpulse(Eigen::Vector6d::Zero()),
1315     mConstraintImpulse(Eigen::Vector6d::Zero()),
1316     mImpF(Eigen::Vector6d::Zero()),
1317     onColShapeAdded(mColShapeAddedSignal),
1318     onColShapeRemoved(mColShapeRemovedSignal),
1319     onStructuralChange(mStructuralChangeSignal)
1320 {
1321   // Generate an inert destructor to make sure that it will not try to
1322   // double-delete this BodyNode when it gets destroyed.
1323   mSelfDestructor
1324       = std::shared_ptr<NodeDestructor>(new NodeDestructor(nullptr));
1325   mDestructor = mSelfDestructor;
1326   mAmAttached = true;
1327 
1328   mParentJoint->mChildBodyNode = this;
1329   setProperties(_properties);
1330 
1331   if (_parentBodyNode)
1332     _parentBodyNode->addChildBodyNode(this);
1333 
1334   createAspect<Aspect>();
1335   createAspect<detail::NodeVectorProxyAspect>();
1336 }
1337 
1338 //==============================================================================
BodyNode(const std::tuple<BodyNode *,Joint *,Properties> & args)1339 BodyNode::BodyNode(const std::tuple<BodyNode*, Joint*, Properties>& args)
1340   : BodyNode(std::get<0>(args), std::get<1>(args), std::get<2>(args))
1341 {
1342   // The initializer list is delegating the construction
1343 }
1344 
1345 //==============================================================================
clone(BodyNode * _parentBodyNode,Joint * _parentJoint,bool cloneNodes) const1346 BodyNode* BodyNode::clone(
1347     BodyNode* _parentBodyNode, Joint* _parentJoint, bool cloneNodes) const
1348 {
1349   BodyNode* clonedBn
1350       = new BodyNode(_parentBodyNode, _parentJoint, getBodyNodeProperties());
1351 
1352   clonedBn->matchAspects(this);
1353 
1354   if (cloneNodes)
1355     clonedBn->matchNodes(this);
1356 
1357   return clonedBn;
1358 }
1359 
1360 //==============================================================================
cloneNode(BodyNode *) const1361 Node* BodyNode::cloneNode(BodyNode* /*bn*/) const
1362 {
1363   dterr << "[BodyNode::cloneNode] This function should never be called! Please "
1364         << "report this as an error!\n";
1365   assert(false);
1366   return nullptr;
1367 }
1368 
1369 //==============================================================================
init(const SkeletonPtr & _skeleton)1370 void BodyNode::init(const SkeletonPtr& _skeleton)
1371 {
1372   mSkeleton = _skeleton;
1373   assert(_skeleton);
1374   if (mReferenceCount > 0)
1375   {
1376     mReferenceSkeleton = mSkeleton.lock();
1377   }
1378 
1379   setVersionDependentObject(
1380       dynamic_cast<common::VersionCounter*>(mSkeleton.lock().get()));
1381   mParentJoint->setVersionDependentObject(
1382       dynamic_cast<common::VersionCounter*>(mSkeleton.lock().get()));
1383 
1384   // Put the scope around this so that 'lock' releases the mutex immediately
1385   // after we're done with it
1386   {
1387     std::lock_guard<std::mutex> lock(mLockedSkeleton->mMutex);
1388     mLockedSkeleton->mSkeleton = mSkeleton;
1389   }
1390 
1391   //--------------------------------------------------------------------------
1392   // Fill the list of generalized coordinates this node depends on, and sort
1393   // it.
1394   //--------------------------------------------------------------------------
1395   if (mParentBodyNode)
1396     mDependentGenCoordIndices = mParentBodyNode->mDependentGenCoordIndices;
1397   else
1398     mDependentGenCoordIndices.clear();
1399 
1400   for (std::size_t i = 0; i < mParentJoint->getNumDofs(); i++)
1401     mDependentGenCoordIndices.push_back(mParentJoint->getIndexInSkeleton(i));
1402 
1403   // Sort
1404   std::sort(mDependentGenCoordIndices.begin(), mDependentGenCoordIndices.end());
1405 
1406   mDependentDofs.clear();
1407   mDependentDofs.reserve(mDependentGenCoordIndices.size());
1408   mConstDependentDofs.clear();
1409   mConstDependentDofs.reserve(mDependentGenCoordIndices.size());
1410   for (const std::size_t& index : mDependentGenCoordIndices)
1411   {
1412     mDependentDofs.push_back(_skeleton->getDof(index));
1413     mConstDependentDofs.push_back(_skeleton->getDof(index));
1414   }
1415 
1416 #ifndef NDEBUG
1417   // Check whether there is duplicated indices.
1418   std::size_t nDepGenCoordIndices = mDependentGenCoordIndices.size();
1419   for (std::size_t i = 0; i < nDepGenCoordIndices; ++i)
1420   {
1421     for (std::size_t j = i + 1; j < nDepGenCoordIndices; ++j)
1422     {
1423       assert(
1424           mDependentGenCoordIndices[i] != mDependentGenCoordIndices[j]
1425           && "Duplicated index is found in mDependentGenCoordIndices.");
1426     }
1427   }
1428 #endif // NDEBUG
1429 
1430   //--------------------------------------------------------------------------
1431   // Set dimensions of dynamics matrices and vectors.
1432   //--------------------------------------------------------------------------
1433   std::size_t numDepGenCoords = getNumDependentGenCoords();
1434   mBodyJacobian.setZero(6, numDepGenCoords);
1435   mWorldJacobian.setZero(6, numDepGenCoords);
1436   mBodyJacobianSpatialDeriv.setZero(6, numDepGenCoords);
1437   mWorldJacobianClassicDeriv.setZero(6, numDepGenCoords);
1438   dirtyTransform();
1439 }
1440 
1441 //==============================================================================
processNewEntity(Entity * _newChildEntity)1442 void BodyNode::processNewEntity(Entity* _newChildEntity)
1443 {
1444   // If the Entity is a JacobianNode, add it to the list of JacobianNodes
1445 
1446   // Dev Note (MXG): There are two places where child JacobianNodes get added.
1447   // This is one place, and the constructor of the JacobianNode class is another
1448   // place. They get added in two different places because:
1449   // 1. This location only works for child BodyNodes. When a non-BodyNode gets
1450   //    constructed, its Entity becomes a child of this BodyNode frame during
1451   //    the Entity construction, so it cannot be dynamically cast to a
1452   //    JacobianNode at that time. But this is not an issue for BodyNodes,
1453   //    because BodyNodes become children of this Frame after construction is
1454   //    finished.
1455   // 2. The JacobianNode constructor only works for non-BodyNodes. When a
1456   //    JacobianNode is being used as a base for a BodyNode, it does not know
1457   //    the parent BodyNode.
1458   //
1459   // We should consider doing something to unify these two pipelines that are
1460   // currently independent of each other.
1461   if (JacobianNode* node = dynamic_cast<JacobianNode*>(_newChildEntity))
1462     mChildJacobianNodes.insert(node);
1463 
1464   // Here we want to sort out whether the Entity that has been added is a child
1465   // BodyNode or not
1466 
1467   // Check if it's a child BodyNode (if not, then it's just some other arbitrary
1468   // type of Entity)
1469   if (std::find(mChildBodyNodes.begin(), mChildBodyNodes.end(), _newChildEntity)
1470       != mChildBodyNodes.end())
1471     return;
1472 
1473   // Check if it's already accounted for in our Non-BodyNode Entities
1474   if (mNonBodyNodeEntities.find(_newChildEntity) != mNonBodyNodeEntities.end())
1475   {
1476     dtwarn << "[BodyNode::processNewEntity] Attempting to add an Entity ["
1477            << _newChildEntity->getName() << "] as a child Entity of ["
1478            << getName() << "], which is already its parent." << std::endl;
1479     return;
1480   }
1481 
1482   // Add it to the Non-BodyNode Entities
1483   mNonBodyNodeEntities.insert(_newChildEntity);
1484 }
1485 
1486 //==============================================================================
processRemovedEntity(Entity * _oldChildEntity)1487 void BodyNode::processRemovedEntity(Entity* _oldChildEntity)
1488 {
1489   std::vector<BodyNode*>::iterator it = std::find(
1490       mChildBodyNodes.begin(), mChildBodyNodes.end(), _oldChildEntity);
1491   if (it != mChildBodyNodes.end())
1492     mChildBodyNodes.erase(it);
1493 
1494   if (JacobianNode* node = dynamic_cast<JacobianNode*>(_oldChildEntity))
1495     mChildJacobianNodes.erase(node);
1496 
1497   if (std::find(
1498           mNonBodyNodeEntities.begin(),
1499           mNonBodyNodeEntities.end(),
1500           _oldChildEntity)
1501       != mNonBodyNodeEntities.end())
1502     mNonBodyNodeEntities.erase(_oldChildEntity);
1503 }
1504 
1505 //==============================================================================
dirtyTransform()1506 void BodyNode::dirtyTransform()
1507 {
1508   dirtyVelocity(); // Global Velocity depends on the Global Transform
1509 
1510   if (mNeedTransformUpdate)
1511     return;
1512 
1513   mNeedTransformUpdate = true;
1514 
1515   const SkeletonPtr& skel = getSkeleton();
1516   if (skel)
1517   {
1518     // All of these depend on the world transform of this BodyNode, so they must
1519     // be dirtied whenever mNeedTransformUpdate is dirtied, and if
1520     // mTransformUpdate is already dirty, then these must already be dirty as
1521     // well
1522     SET_FLAGS(mCoriolisForces);
1523     SET_FLAGS(mGravityForces);
1524     SET_FLAGS(mCoriolisAndGravityForces);
1525     SET_FLAGS(mExternalForces);
1526   }
1527 
1528   // Child BodyNodes and other generic Entities are notified separately to allow
1529   // some optimizations
1530   for (std::size_t i = 0; i < mChildBodyNodes.size(); ++i)
1531     mChildBodyNodes[i]->dirtyTransform();
1532 
1533   for (Entity* entity : mNonBodyNodeEntities)
1534     entity->dirtyTransform();
1535 }
1536 
1537 //==============================================================================
dirtyVelocity()1538 void BodyNode::dirtyVelocity()
1539 {
1540   dirtyAcceleration(); // Global Acceleration depends on Global Velocity
1541 
1542   if (mNeedVelocityUpdate)
1543     return;
1544 
1545   mNeedVelocityUpdate = true;
1546   mIsPartialAccelerationDirty = true;
1547 
1548   const SkeletonPtr& skel = getSkeleton();
1549   if (skel)
1550   {
1551     SET_FLAGS(mCoriolisForces);
1552     SET_FLAGS(mCoriolisAndGravityForces);
1553   }
1554 
1555   // Child BodyNodes and other generic Entities are notified separately to allow
1556   // some optimizations
1557   for (std::size_t i = 0; i < mChildBodyNodes.size(); ++i)
1558     mChildBodyNodes[i]->dirtyVelocity();
1559 
1560   for (Entity* entity : mNonBodyNodeEntities)
1561     entity->dirtyVelocity();
1562 }
1563 
1564 //==============================================================================
dirtyAcceleration()1565 void BodyNode::dirtyAcceleration()
1566 {
1567   // If we already know we need to update, just quit
1568   if (mNeedAccelerationUpdate)
1569     return;
1570 
1571   mNeedAccelerationUpdate = true;
1572 
1573   for (std::size_t i = 0; i < mChildBodyNodes.size(); ++i)
1574     mChildBodyNodes[i]->dirtyAcceleration();
1575 
1576   for (Entity* entity : mNonBodyNodeEntities)
1577     entity->dirtyAcceleration();
1578 }
1579 
1580 //==============================================================================
notifyArticulatedInertiaUpdate()1581 void BodyNode::notifyArticulatedInertiaUpdate()
1582 {
1583   dirtyArticulatedInertia();
1584 }
1585 
1586 //==============================================================================
dirtyArticulatedInertia()1587 void BodyNode::dirtyArticulatedInertia()
1588 {
1589   const SkeletonPtr& skel = getSkeleton();
1590   if (skel)
1591     skel->dirtyArticulatedInertia(mTreeIndex);
1592 }
1593 
1594 //==============================================================================
notifyExternalForcesUpdate()1595 void BodyNode::notifyExternalForcesUpdate()
1596 {
1597   dirtyExternalForces();
1598 }
1599 
1600 //==============================================================================
dirtyExternalForces()1601 void BodyNode::dirtyExternalForces()
1602 {
1603   SKEL_SET_FLAGS(mExternalForces);
1604 }
1605 
1606 //==============================================================================
notifyCoriolisUpdate()1607 void BodyNode::notifyCoriolisUpdate()
1608 {
1609   dirtyCoriolisForces();
1610 }
1611 
1612 //==============================================================================
dirtyCoriolisForces()1613 void BodyNode::dirtyCoriolisForces()
1614 {
1615   SKEL_SET_FLAGS(mCoriolisForces);
1616   SKEL_SET_FLAGS(mCoriolisAndGravityForces);
1617 }
1618 
1619 //==============================================================================
updateTransform()1620 void BodyNode::updateTransform()
1621 {
1622   // Calling getWorldTransform will update the transform if an update is needed
1623   getWorldTransform();
1624   assert(math::verifyTransform(mWorldTransform));
1625 }
1626 
1627 //==============================================================================
updateVelocity()1628 void BodyNode::updateVelocity()
1629 {
1630   // Calling getSpatialVelocity will update the velocity if an update is needed
1631   getSpatialVelocity();
1632   assert(!math::isNan(mVelocity));
1633 }
1634 
1635 //==============================================================================
updatePartialAcceleration() const1636 void BodyNode::updatePartialAcceleration() const
1637 {
1638   // Compute partial acceleration
1639   mParentJoint->setPartialAccelerationTo(
1640       mPartialAcceleration, getSpatialVelocity());
1641   mIsPartialAccelerationDirty = false;
1642 }
1643 
1644 //==============================================================================
updateAccelerationID()1645 void BodyNode::updateAccelerationID()
1646 {
1647   // Note: auto-updating has replaced this function
1648   getSpatialAcceleration();
1649   // Verification
1650   assert(!math::isNan(mAcceleration));
1651 }
1652 
1653 //==============================================================================
updateTransmittedForceID(const Eigen::Vector3d & _gravity,bool _withExternalForces)1654 void BodyNode::updateTransmittedForceID(
1655     const Eigen::Vector3d& _gravity, bool _withExternalForces)
1656 {
1657   // Gravity force
1658   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
1659   if (mAspectProperties.mGravityMode == true)
1660     mFgravity.noalias()
1661         = mI * math::AdInvRLinear(getWorldTransform(), _gravity);
1662   else
1663     mFgravity.setZero();
1664 
1665   // Inertial force
1666   mF.noalias() = mI * getSpatialAcceleration();
1667 
1668   // External force
1669   if (_withExternalForces)
1670     mF -= mAspectState.mFext;
1671 
1672   // Verification
1673   assert(!math::isNan(mF));
1674 
1675   // Gravity force
1676   mF -= mFgravity;
1677 
1678   // Coriolis force
1679   const Eigen::Vector6d& V = getSpatialVelocity();
1680   mF -= math::dad(V, mI * V);
1681 
1682   //
1683   for (const auto& childBodyNode : mChildBodyNodes)
1684   {
1685     Joint* childJoint = childBodyNode->getParentJoint();
1686     assert(childJoint != nullptr);
1687 
1688     mF += math::dAdInvT(
1689         childJoint->getRelativeTransform(), childBodyNode->getBodyForce());
1690   }
1691 
1692   // Verification
1693   assert(!math::isNan(mF));
1694 }
1695 
1696 //==============================================================================
updateArtInertia(double _timeStep) const1697 void BodyNode::updateArtInertia(double _timeStep) const
1698 {
1699   // Set spatial inertia to the articulated body inertia
1700   mArtInertia = mAspectProperties.mInertia.getSpatialTensor();
1701   mArtInertiaImplicit = mArtInertia;
1702 
1703   // and add child articulated body inertia
1704   for (const auto& child : mChildBodyNodes)
1705   {
1706     Joint* childJoint = child->getParentJoint();
1707 
1708     childJoint->addChildArtInertiaTo(mArtInertia, child->mArtInertia);
1709     childJoint->addChildArtInertiaImplicitTo(
1710         mArtInertiaImplicit, child->mArtInertiaImplicit);
1711   }
1712 
1713   // Verification
1714   //  assert(!math::isNan(mArtInertia));
1715   assert(!math::isNan(mArtInertiaImplicit));
1716 
1717   // Update parent joint's inverse of projected articulated body inertia
1718   mParentJoint->updateInvProjArtInertia(mArtInertia);
1719   mParentJoint->updateInvProjArtInertiaImplicit(mArtInertiaImplicit, _timeStep);
1720 
1721   // Verification
1722   //  assert(!math::isNan(mArtInertia));
1723   assert(!math::isNan(mArtInertiaImplicit));
1724 }
1725 
1726 //==============================================================================
updateBiasForce(const Eigen::Vector3d & _gravity,double _timeStep)1727 void BodyNode::updateBiasForce(
1728     const Eigen::Vector3d& _gravity, double _timeStep)
1729 {
1730   // Gravity force
1731   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
1732   if (mAspectProperties.mGravityMode == true)
1733     mFgravity.noalias()
1734         = mI * math::AdInvRLinear(getWorldTransform(), _gravity);
1735   else
1736     mFgravity.setZero();
1737 
1738   // Set bias force
1739   const Eigen::Vector6d& V = getSpatialVelocity();
1740   mBiasForce = -math::dad(V, mI * V) - mAspectState.mFext - mFgravity;
1741 
1742   // Verification
1743   assert(!math::isNan(mBiasForce));
1744 
1745   // And add child bias force
1746   for (const auto& childBodyNode : mChildBodyNodes)
1747   {
1748     Joint* childJoint = childBodyNode->getParentJoint();
1749 
1750     childJoint->addChildBiasForceTo(
1751         mBiasForce,
1752         childBodyNode->getArticulatedInertiaImplicit(),
1753         childBodyNode->mBiasForce,
1754         childBodyNode->getPartialAcceleration());
1755   }
1756 
1757   // Verification
1758   assert(!math::isNan(mBiasForce));
1759 
1760   // Update parent joint's total force with implicit joint damping and spring
1761   // forces
1762   mParentJoint->updateTotalForce(
1763       getArticulatedInertiaImplicit() * getPartialAcceleration() + mBiasForce,
1764       _timeStep);
1765 }
1766 
1767 //==============================================================================
updateBiasImpulse()1768 void BodyNode::updateBiasImpulse()
1769 {
1770   // Update impulsive bias force
1771   mBiasImpulse = -mConstraintImpulse;
1772 
1773   // And add child bias impulse
1774   for (auto& childBodyNode : mChildBodyNodes)
1775   {
1776     Joint* childJoint = childBodyNode->getParentJoint();
1777 
1778     childJoint->addChildBiasImpulseTo(
1779         mBiasImpulse,
1780         childBodyNode->getArticulatedInertia(),
1781         childBodyNode->mBiasImpulse);
1782   }
1783 
1784   // Verification
1785   assert(!math::isNan(mBiasImpulse));
1786 
1787   // Update parent joint's total force
1788   mParentJoint->updateTotalImpulse(mBiasImpulse);
1789 }
1790 
1791 //==============================================================================
updateTransmittedForceFD()1792 void BodyNode::updateTransmittedForceFD()
1793 {
1794   mF = mBiasForce;
1795   mF.noalias() += getArticulatedInertiaImplicit() * getSpatialAcceleration();
1796 
1797   assert(!math::isNan(mF));
1798 }
1799 
1800 //==============================================================================
updateTransmittedImpulse()1801 void BodyNode::updateTransmittedImpulse()
1802 {
1803   mImpF = mBiasImpulse;
1804   mImpF.noalias() += getArticulatedInertia() * mDelV;
1805 
1806   assert(!math::isNan(mImpF));
1807 }
1808 
1809 //==============================================================================
updateAccelerationFD()1810 void BodyNode::updateAccelerationFD()
1811 {
1812   if (mParentBodyNode)
1813   {
1814     // Update joint acceleration
1815     mParentJoint->updateAcceleration(
1816         getArticulatedInertiaImplicit(),
1817         mParentBodyNode->getSpatialAcceleration());
1818   }
1819   else
1820   {
1821     // Update joint acceleration
1822     mParentJoint->updateAcceleration(
1823         getArticulatedInertiaImplicit(), Eigen::Vector6d::Zero());
1824   }
1825 
1826   // Verify the spatial acceleration of this body
1827   assert(!math::isNan(mAcceleration));
1828 }
1829 
1830 //==============================================================================
updateVelocityChangeFD()1831 void BodyNode::updateVelocityChangeFD()
1832 {
1833   if (mParentBodyNode)
1834   {
1835     // Update joint velocity change
1836     mParentJoint->updateVelocityChange(
1837         getArticulatedInertia(), mParentBodyNode->mDelV);
1838 
1839     // Transmit spatial acceleration of parent body to this body
1840     mDelV = math::AdInvT(
1841         mParentJoint->getRelativeTransform(), mParentBodyNode->mDelV);
1842   }
1843   else
1844   {
1845     // Update joint velocity change
1846     mParentJoint->updateVelocityChange(
1847         getArticulatedInertia(), Eigen::Vector6d::Zero());
1848 
1849     // Transmit spatial acceleration of parent body to this body
1850     mDelV.setZero();
1851   }
1852 
1853   // Add parent joint's acceleration to this body
1854   mParentJoint->addVelocityChangeTo(mDelV);
1855 
1856   // Verify the spatial velocity change of this body
1857   assert(!math::isNan(mDelV));
1858 }
1859 
1860 //==============================================================================
updateJointForceID(double _timeStep,bool _withDampingForces,bool _withSpringForces)1861 void BodyNode::updateJointForceID(
1862     double _timeStep, bool _withDampingForces, bool _withSpringForces)
1863 {
1864   assert(mParentJoint != nullptr);
1865   mParentJoint->updateForceID(
1866       mF, _timeStep, _withDampingForces, _withSpringForces);
1867 }
1868 
1869 //==============================================================================
updateJointForceFD(double _timeStep,bool _withDampingForces,bool _withSpringForces)1870 void BodyNode::updateJointForceFD(
1871     double _timeStep, bool _withDampingForces, bool _withSpringForces)
1872 {
1873   assert(mParentJoint != nullptr);
1874   mParentJoint->updateForceFD(
1875       mF, _timeStep, _withDampingForces, _withSpringForces);
1876 }
1877 
1878 //==============================================================================
updateJointImpulseFD()1879 void BodyNode::updateJointImpulseFD()
1880 {
1881   assert(mParentJoint != nullptr);
1882   mParentJoint->updateImpulseFD(mF);
1883 }
1884 
1885 //==============================================================================
updateConstrainedTerms(double _timeStep)1886 void BodyNode::updateConstrainedTerms(double _timeStep)
1887 {
1888   // 1. dq = dq + del_dq
1889   // 2. ddq = ddq + del_dq / dt
1890   // 3. tau = tau + imp / dt
1891   mParentJoint->updateConstrainedTerms(_timeStep);
1892 
1893   //
1894   mF += mImpF / _timeStep;
1895 }
1896 
1897 //==============================================================================
clearExternalForces()1898 void BodyNode::clearExternalForces()
1899 {
1900   mAspectState.mFext.setZero();
1901   SKEL_SET_FLAGS(mExternalForces);
1902 }
1903 
1904 //==============================================================================
clearInternalForces()1905 void BodyNode::clearInternalForces()
1906 {
1907   mParentJoint->resetForces();
1908 }
1909 
1910 //==============================================================================
getExternalForceLocal() const1911 const Eigen::Vector6d& BodyNode::getExternalForceLocal() const
1912 {
1913   return mAspectState.mFext;
1914 }
1915 
1916 //==============================================================================
getExternalForceGlobal() const1917 Eigen::Vector6d BodyNode::getExternalForceGlobal() const
1918 {
1919   return math::dAdInvT(getWorldTransform(), mAspectState.mFext);
1920 }
1921 
1922 //==============================================================================
addConstraintImpulse(const Eigen::Vector3d & _constImp,const Eigen::Vector3d & _offset,bool _isImpulseLocal,bool _isOffsetLocal)1923 void BodyNode::addConstraintImpulse(
1924     const Eigen::Vector3d& _constImp,
1925     const Eigen::Vector3d& _offset,
1926     bool _isImpulseLocal,
1927     bool _isOffsetLocal)
1928 {
1929   // TODO(JS): Add contact sensor data here (DART 4.1)
1930 
1931   Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
1932   Eigen::Vector6d F = Eigen::Vector6d::Zero();
1933   const Eigen::Isometry3d& W = getWorldTransform();
1934 
1935   if (_isOffsetLocal)
1936     T.translation() = _offset;
1937   else
1938     T.translation() = W.inverse() * _offset;
1939 
1940   if (_isImpulseLocal)
1941     F.tail<3>() = _constImp;
1942   else
1943     F.tail<3>() = W.linear().transpose() * _constImp;
1944 
1945   mConstraintImpulse += math::dAdInvT(T, F);
1946 }
1947 
1948 //==============================================================================
clearConstraintImpulse()1949 void BodyNode::clearConstraintImpulse()
1950 {
1951   mDelV.setZero();
1952   mBiasImpulse.setZero();
1953   mConstraintImpulse.setZero();
1954   mImpF.setZero();
1955 
1956   mParentJoint->resetConstraintImpulses();
1957   mParentJoint->resetTotalImpulses();
1958   mParentJoint->resetVelocityChanges();
1959 }
1960 
1961 //==============================================================================
getBodyForce() const1962 const Eigen::Vector6d& BodyNode::getBodyForce() const
1963 {
1964   return mF;
1965 }
1966 
1967 //==============================================================================
setConstraintImpulse(const Eigen::Vector6d & _constImp)1968 void BodyNode::setConstraintImpulse(const Eigen::Vector6d& _constImp)
1969 {
1970   assert(!math::isNan(_constImp));
1971   mConstraintImpulse = _constImp;
1972 }
1973 
1974 //==============================================================================
addConstraintImpulse(const Eigen::Vector6d & _constImp)1975 void BodyNode::addConstraintImpulse(const Eigen::Vector6d& _constImp)
1976 {
1977   assert(!math::isNan(_constImp));
1978   mConstraintImpulse += _constImp;
1979 }
1980 
1981 //==============================================================================
getConstraintImpulse() const1982 const Eigen::Vector6d& BodyNode::getConstraintImpulse() const
1983 {
1984   return mConstraintImpulse;
1985 }
1986 
1987 //==============================================================================
computeLagrangian(const Eigen::Vector3d & gravity) const1988 double BodyNode::computeLagrangian(const Eigen::Vector3d& gravity) const
1989 {
1990   return computeKineticEnergy() - computePotentialEnergy(gravity);
1991 }
1992 
1993 //==============================================================================
getKineticEnergy() const1994 double BodyNode::getKineticEnergy() const
1995 {
1996   return computeKineticEnergy();
1997 }
1998 
1999 //==============================================================================
computeKineticEnergy() const2000 double BodyNode::computeKineticEnergy() const
2001 {
2002   const Eigen::Vector6d& V = getSpatialVelocity();
2003   const Eigen::Matrix6d& G = mAspectProperties.mInertia.getSpatialTensor();
2004 
2005   return 0.5 * V.dot(G * V);
2006 }
2007 
2008 //==============================================================================
getPotentialEnergy(const Eigen::Vector3d & _gravity) const2009 double BodyNode::getPotentialEnergy(const Eigen::Vector3d& _gravity) const
2010 {
2011   return computePotentialEnergy(_gravity);
2012 }
2013 
2014 //==============================================================================
computePotentialEnergy(const Eigen::Vector3d & gravity) const2015 double BodyNode::computePotentialEnergy(const Eigen::Vector3d& gravity) const
2016 {
2017   return -getMass() * getWorldTransform().translation().dot(gravity);
2018 }
2019 
2020 //==============================================================================
getLinearMomentum() const2021 Eigen::Vector3d BodyNode::getLinearMomentum() const
2022 {
2023   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
2024   return (mI * getSpatialVelocity()).tail<3>();
2025 }
2026 
2027 //==============================================================================
getAngularMomentum(const Eigen::Vector3d & _pivot)2028 Eigen::Vector3d BodyNode::getAngularMomentum(const Eigen::Vector3d& _pivot)
2029 {
2030   Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
2031   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
2032   T.translation() = _pivot;
2033   return math::dAdT(T, mI * getSpatialVelocity()).head<3>();
2034 }
2035 
2036 //==============================================================================
isReactive() const2037 bool BodyNode::isReactive() const
2038 {
2039   const ConstSkeletonPtr& skel = getSkeleton();
2040   if (skel && skel->isMobile() && getNumDependentGenCoords() > 0)
2041   {
2042     // Check if all the ancestor joints are motion prescribed.
2043     const BodyNode* body = this;
2044     while (body != nullptr)
2045     {
2046       if (body->mParentJoint->isDynamic())
2047         return true;
2048 
2049       body = body->mParentBodyNode;
2050     }
2051     // TODO: Checking if all the ancestor joints are motion prescribed is
2052     // expensive. It would be good to evaluate this in advance and update only
2053     // when necessary.
2054 
2055     return false;
2056   }
2057   else
2058   {
2059     return false;
2060   }
2061 }
2062 
2063 //==============================================================================
aggregateCoriolisForceVector(Eigen::VectorXd & _C)2064 void BodyNode::aggregateCoriolisForceVector(Eigen::VectorXd& _C)
2065 {
2066   aggregateCombinedVector(_C, Eigen::Vector3d::Zero());
2067 }
2068 
2069 //==============================================================================
aggregateGravityForceVector(Eigen::VectorXd & _g,const Eigen::Vector3d & _gravity)2070 void BodyNode::aggregateGravityForceVector(
2071     Eigen::VectorXd& _g, const Eigen::Vector3d& _gravity)
2072 {
2073   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
2074   if (mAspectProperties.mGravityMode == true)
2075     mG_F = mI * math::AdInvRLinear(getWorldTransform(), _gravity);
2076   else
2077     mG_F.setZero();
2078 
2079   for (std::vector<BodyNode*>::const_iterator it = mChildBodyNodes.begin();
2080        it != mChildBodyNodes.end();
2081        ++it)
2082   {
2083     mG_F += math::dAdInvT(
2084         (*it)->mParentJoint->getRelativeTransform(), (*it)->mG_F);
2085   }
2086 
2087   std::size_t nGenCoords = mParentJoint->getNumDofs();
2088   if (nGenCoords > 0)
2089   {
2090     Eigen::VectorXd g
2091         = -(mParentJoint->getRelativeJacobian().transpose() * mG_F);
2092     std::size_t iStart = mParentJoint->getIndexInTree(0);
2093     _g.segment(iStart, nGenCoords) = g;
2094   }
2095 }
2096 
2097 //==============================================================================
updateCombinedVector()2098 void BodyNode::updateCombinedVector()
2099 {
2100   if (mParentBodyNode)
2101   {
2102     mCg_dV = math::AdInvT(
2103                  mParentJoint->getRelativeTransform(), mParentBodyNode->mCg_dV)
2104              + getPartialAcceleration();
2105   }
2106   else
2107   {
2108     mCg_dV = getPartialAcceleration();
2109   }
2110 }
2111 
2112 //==============================================================================
aggregateCombinedVector(Eigen::VectorXd & _Cg,const Eigen::Vector3d & _gravity)2113 void BodyNode::aggregateCombinedVector(
2114     Eigen::VectorXd& _Cg, const Eigen::Vector3d& _gravity)
2115 {
2116   // H(i) = I(i) * W(i) -
2117   //        dad{V}(I(i) * V(i)) + sum(k \in children) dAd_{T(i,j)^{-1}}(H(k))
2118   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
2119   if (mAspectProperties.mGravityMode == true)
2120     mFgravity = mI * math::AdInvRLinear(getWorldTransform(), _gravity);
2121   else
2122     mFgravity.setZero();
2123 
2124   const Eigen::Vector6d& V = getSpatialVelocity();
2125   mCg_F = mI * mCg_dV;
2126   mCg_F -= mFgravity;
2127   mCg_F -= math::dad(V, mI * V);
2128 
2129   for (std::vector<BodyNode*>::iterator it = mChildBodyNodes.begin();
2130        it != mChildBodyNodes.end();
2131        ++it)
2132   {
2133     mCg_F += math::dAdInvT((*it)->getParentJoint()->mT, (*it)->mCg_F);
2134   }
2135 
2136   std::size_t nGenCoords = mParentJoint->getNumDofs();
2137   if (nGenCoords > 0)
2138   {
2139     Eigen::VectorXd Cg
2140         = mParentJoint->getRelativeJacobian().transpose() * mCg_F;
2141     std::size_t iStart = mParentJoint->getIndexInTree(0);
2142     _Cg.segment(iStart, nGenCoords) = Cg;
2143   }
2144 }
2145 
2146 //==============================================================================
aggregateExternalForces(Eigen::VectorXd & _Fext)2147 void BodyNode::aggregateExternalForces(Eigen::VectorXd& _Fext)
2148 {
2149   mFext_F = mAspectState.mFext;
2150 
2151   for (std::vector<BodyNode*>::const_iterator it = mChildBodyNodes.begin();
2152        it != mChildBodyNodes.end();
2153        ++it)
2154   {
2155     mFext_F += math::dAdInvT(
2156         (*it)->mParentJoint->getRelativeTransform(), (*it)->mFext_F);
2157   }
2158 
2159   std::size_t nGenCoords = mParentJoint->getNumDofs();
2160   if (nGenCoords > 0)
2161   {
2162     Eigen::VectorXd Fext
2163         = mParentJoint->getRelativeJacobian().transpose() * mFext_F;
2164     std::size_t iStart = mParentJoint->getIndexInTree(0);
2165     _Fext.segment(iStart, nGenCoords) = Fext;
2166   }
2167 }
2168 
2169 //==============================================================================
aggregateSpatialToGeneralized(Eigen::VectorXd & _generalized,const Eigen::Vector6d & _spatial)2170 void BodyNode::aggregateSpatialToGeneralized(
2171     Eigen::VectorXd& _generalized, const Eigen::Vector6d& _spatial)
2172 {
2173   //
2174   mArbitrarySpatial = _spatial;
2175 
2176   //
2177   for (std::vector<BodyNode*>::const_iterator it = mChildBodyNodes.begin();
2178        it != mChildBodyNodes.end();
2179        ++it)
2180   {
2181     mArbitrarySpatial += math::dAdInvT(
2182         (*it)->mParentJoint->getRelativeTransform(), (*it)->mArbitrarySpatial);
2183   }
2184 
2185   // Project the spatial quantity to generalized coordinates
2186   const auto numDofs = mParentJoint->getNumDofs();
2187   if (numDofs > 0u)
2188   {
2189     const std::size_t iStart = mParentJoint->getIndexInTree(0);
2190     _generalized.segment(iStart, numDofs)
2191         = mParentJoint->getSpatialToGeneralized(mArbitrarySpatial);
2192   }
2193 }
2194 
2195 //==============================================================================
updateMassMatrix()2196 void BodyNode::updateMassMatrix()
2197 {
2198   mM_dV.setZero();
2199   std::size_t dof = mParentJoint->getNumDofs();
2200   if (dof > 0)
2201   {
2202     mM_dV.noalias() += mParentJoint->getRelativeJacobian()
2203                        * mParentJoint->getAccelerations();
2204     assert(!math::isNan(mM_dV));
2205   }
2206   if (mParentBodyNode)
2207     mM_dV += math::AdInvT(
2208         mParentJoint->getRelativeTransform(), mParentBodyNode->mM_dV);
2209   assert(!math::isNan(mM_dV));
2210 }
2211 
2212 //==============================================================================
aggregateMassMatrix(Eigen::MatrixXd & _MCol,std::size_t _col)2213 void BodyNode::aggregateMassMatrix(Eigen::MatrixXd& _MCol, std::size_t _col)
2214 {
2215   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
2216   //
2217   mM_F.noalias() = mI * mM_dV;
2218 
2219   // Verification
2220   assert(!math::isNan(mM_F));
2221 
2222   //
2223   for (std::vector<BodyNode*>::const_iterator it = mChildBodyNodes.begin();
2224        it != mChildBodyNodes.end();
2225        ++it)
2226   {
2227     mM_F += math::dAdInvT(
2228         (*it)->getParentJoint()->getRelativeTransform(), (*it)->mM_F);
2229   }
2230 
2231   // Verification
2232   assert(!math::isNan(mM_F));
2233 
2234   //
2235   std::size_t dof = mParentJoint->getNumDofs();
2236   if (dof > 0)
2237   {
2238     std::size_t iStart = mParentJoint->getIndexInTree(0);
2239     _MCol.block(iStart, _col, dof, 1).noalias()
2240         = mParentJoint->getRelativeJacobian().transpose() * mM_F;
2241   }
2242 }
2243 
2244 //==============================================================================
aggregateAugMassMatrix(Eigen::MatrixXd & _MCol,std::size_t _col,double _timeStep)2245 void BodyNode::aggregateAugMassMatrix(
2246     Eigen::MatrixXd& _MCol, std::size_t _col, double _timeStep)
2247 {
2248   // TODO(JS): Need to be reimplemented
2249   const Eigen::Matrix6d& mI = mAspectProperties.mInertia.getSpatialTensor();
2250 
2251   //
2252   mM_F.noalias() = mI * mM_dV;
2253 
2254   // Verification
2255   assert(!math::isNan(mM_F));
2256 
2257   //
2258   for (std::vector<BodyNode*>::const_iterator it = mChildBodyNodes.begin();
2259        it != mChildBodyNodes.end();
2260        ++it)
2261   {
2262     mM_F += math::dAdInvT(
2263         (*it)->getParentJoint()->getRelativeTransform(), (*it)->mM_F);
2264   }
2265 
2266   // Verification
2267   assert(!math::isNan(mM_F));
2268 
2269   //
2270   std::size_t dof = mParentJoint->getNumDofs();
2271   if (dof > 0)
2272   {
2273     Eigen::MatrixXd K = Eigen::MatrixXd::Zero(dof, dof);
2274     Eigen::MatrixXd D = Eigen::MatrixXd::Zero(dof, dof);
2275     for (std::size_t i = 0; i < dof; ++i)
2276     {
2277       K(i, i) = mParentJoint->getSpringStiffness(i);
2278       D(i, i) = mParentJoint->getDampingCoefficient(i);
2279     }
2280 
2281     std::size_t iStart = mParentJoint->getIndexInTree(0);
2282 
2283     _MCol.block(iStart, _col, dof, 1).noalias()
2284         = mParentJoint->getRelativeJacobian().transpose() * mM_F
2285           + D * (_timeStep * mParentJoint->getAccelerations())
2286           + K * (_timeStep * _timeStep * mParentJoint->getAccelerations());
2287   }
2288 }
2289 
2290 //==============================================================================
updateInvMassMatrix()2291 void BodyNode::updateInvMassMatrix()
2292 {
2293   //
2294   mInvM_c.setZero();
2295 
2296   //
2297   for (std::vector<BodyNode*>::const_iterator it = mChildBodyNodes.begin();
2298        it != mChildBodyNodes.end();
2299        ++it)
2300   {
2301     (*it)->getParentJoint()->addChildBiasForceForInvMassMatrix(
2302         mInvM_c, (*it)->getArticulatedInertia(), (*it)->mInvM_c);
2303   }
2304 
2305   // Verification
2306   assert(!math::isNan(mInvM_c));
2307 
2308   // Update parent joint's total force for inverse mass matrix
2309   mParentJoint->updateTotalForceForInvMassMatrix(mInvM_c);
2310 }
2311 
2312 //==============================================================================
updateInvAugMassMatrix()2313 void BodyNode::updateInvAugMassMatrix()
2314 {
2315   //
2316   mInvM_c.setZero();
2317 
2318   //
2319   for (std::vector<BodyNode*>::const_iterator it = mChildBodyNodes.begin();
2320        it != mChildBodyNodes.end();
2321        ++it)
2322   {
2323     (*it)->getParentJoint()->addChildBiasForceForInvAugMassMatrix(
2324         mInvM_c, (*it)->getArticulatedInertiaImplicit(), (*it)->mInvM_c);
2325   }
2326 
2327   // Verification
2328   assert(!math::isNan(mInvM_c));
2329 
2330   // Update parent joint's total force for inverse mass matrix
2331   mParentJoint->updateTotalForceForInvMassMatrix(mInvM_c);
2332 }
2333 
2334 //==============================================================================
aggregateInvMassMatrix(Eigen::MatrixXd & _InvMCol,std::size_t _col)2335 void BodyNode::aggregateInvMassMatrix(
2336     Eigen::MatrixXd& _InvMCol, std::size_t _col)
2337 {
2338   if (mParentBodyNode)
2339   {
2340     //
2341     mParentJoint->getInvMassMatrixSegment(
2342         _InvMCol, _col, getArticulatedInertia(), mParentBodyNode->mInvM_U);
2343 
2344     //
2345     mInvM_U = math::AdInvT(
2346         mParentJoint->getRelativeTransform(), mParentBodyNode->mInvM_U);
2347   }
2348   else
2349   {
2350     //
2351     mParentJoint->getInvMassMatrixSegment(
2352         _InvMCol, _col, getArticulatedInertia(), Eigen::Vector6d::Zero());
2353 
2354     //
2355     mInvM_U.setZero();
2356   }
2357 
2358   //
2359   mParentJoint->addInvMassMatrixSegmentTo(mInvM_U);
2360 }
2361 
2362 //==============================================================================
aggregateInvAugMassMatrix(Eigen::MatrixXd & _InvMCol,std::size_t _col,double)2363 void BodyNode::aggregateInvAugMassMatrix(
2364     Eigen::MatrixXd& _InvMCol, std::size_t _col, double /*_timeStep*/)
2365 {
2366   if (mParentBodyNode)
2367   {
2368     //
2369     mParentJoint->getInvAugMassMatrixSegment(
2370         _InvMCol,
2371         _col,
2372         getArticulatedInertiaImplicit(),
2373         mParentBodyNode->mInvM_U);
2374 
2375     //
2376     mInvM_U = math::AdInvT(
2377         mParentJoint->getRelativeTransform(), mParentBodyNode->mInvM_U);
2378   }
2379   else
2380   {
2381     //
2382     mParentJoint->getInvAugMassMatrixSegment(
2383         _InvMCol,
2384         _col,
2385         getArticulatedInertiaImplicit(),
2386         Eigen::Vector6d::Zero());
2387 
2388     //
2389     mInvM_U.setZero();
2390   }
2391 
2392   //
2393   mParentJoint->addInvMassMatrixSegmentTo(mInvM_U);
2394 }
2395 
2396 //==============================================================================
updateBodyJacobian() const2397 void BodyNode::updateBodyJacobian() const
2398 {
2399   //--------------------------------------------------------------------------
2400   // Jacobian update
2401   //
2402   // J = | J1 J2 ... Jn |
2403   //   = | Ad(T(i,i-1), J_parent) J_local |
2404   //
2405   //   J_parent: (6 x parentDOF)
2406   //    J_local: (6 x localDOF)
2407   //         Ji: (6 x 1) se3
2408   //          n: number of dependent coordinates
2409   //--------------------------------------------------------------------------
2410 
2411   if (nullptr == mParentJoint)
2412     return;
2413 
2414   const std::size_t localDof = mParentJoint->getNumDofs();
2415   assert(getNumDependentGenCoords() >= localDof);
2416   const std::size_t ascendantDof = getNumDependentGenCoords() - localDof;
2417 
2418   // Parent Jacobian
2419   if (mParentBodyNode)
2420   {
2421     assert(
2422         static_cast<std::size_t>(mParentBodyNode->getJacobian().cols())
2423             + mParentJoint->getNumDofs()
2424         == static_cast<std::size_t>(mBodyJacobian.cols()));
2425 
2426     assert(mParentJoint);
2427     mBodyJacobian.leftCols(ascendantDof) = math::AdInvTJac(
2428         mParentJoint->getRelativeTransform(), mParentBodyNode->getJacobian());
2429   }
2430 
2431   // Local Jacobian
2432   mBodyJacobian.rightCols(localDof) = mParentJoint->getRelativeJacobian();
2433 
2434   mIsBodyJacobianDirty = false;
2435 }
2436 
2437 //==============================================================================
updateWorldJacobian() const2438 void BodyNode::updateWorldJacobian() const
2439 {
2440   mWorldJacobian = math::AdRJac(getWorldTransform(), getJacobian());
2441 
2442   mIsWorldJacobianDirty = false;
2443 }
2444 
2445 //==============================================================================
updateBodyJacobianSpatialDeriv() const2446 void BodyNode::updateBodyJacobianSpatialDeriv() const
2447 {
2448   //--------------------------------------------------------------------------
2449   // Body Jacobian first spatial derivative update
2450   //
2451   // dJ = | Ad(T(i, parent(i)), dJ_parent(i))    ad(V(i), S(i)) + dS(i) |
2452   //
2453   // T(i, parent(i)): Transformation from this BodyNode to the parent BodyNode
2454   // dJ             : Spatial Jacobian derivative (6 x dependentDOF)
2455   // dJ_parent      : Parent Jacobian derivative (6 x (dependentDOF - localDOF))
2456   // V(i)           : Spatial velocity (6 x 1)
2457   // S(i)           : Local spatial Jacobian (6 x localDOF)
2458   // dS(i)          : Local spatial Jacobian deriavative (6 x localDOF)
2459   // Ad(T(1,2), V)  : Transformation a spatial motion from frame 2 to frame 1
2460   // ad(V, W)       : Spatial cross product for spatial motions
2461   //--------------------------------------------------------------------------
2462 
2463   if (nullptr == mParentJoint)
2464     return;
2465 
2466   const auto numLocalDOFs = mParentJoint->getNumDofs();
2467   assert(getNumDependentGenCoords() >= numLocalDOFs);
2468   const auto numParentDOFs = getNumDependentGenCoords() - numLocalDOFs;
2469 
2470   // Parent Jacobian: Ad(T(i, parent(i)), dJ_parent(i))
2471   if (mParentBodyNode)
2472   {
2473     const auto& dJ_parent = mParentBodyNode->getJacobianSpatialDeriv();
2474 
2475     assert(
2476         static_cast<std::size_t>(dJ_parent.cols()) + mParentJoint->getNumDofs()
2477         == static_cast<std::size_t>(mBodyJacobianSpatialDeriv.cols()));
2478 
2479     mBodyJacobianSpatialDeriv.leftCols(numParentDOFs)
2480         = math::AdInvTJac(mParentJoint->getRelativeTransform(), dJ_parent);
2481   }
2482 
2483   // Local Jacobian: ad(V(i), S(i)) + dS(i)
2484   mBodyJacobianSpatialDeriv.rightCols(numLocalDOFs)
2485       = math::adJac(getSpatialVelocity(), mParentJoint->getRelativeJacobian())
2486         + mParentJoint->getRelativeJacobianTimeDeriv();
2487 
2488   mIsBodyJacobianSpatialDerivDirty = false;
2489 }
2490 
2491 //==============================================================================
updateWorldJacobianClassicDeriv() const2492 void BodyNode::updateWorldJacobianClassicDeriv() const
2493 {
2494   //----------------------------------------------------------------------------
2495   // World Jacobian first classic deriv update
2496   //
2497   // dJr = |                   dJr_parent dJr_local - Jr_local x w |
2498   //
2499   // dJl = | dJl_parent + Jr_parent x (v_local + w_parent x p) + dJr_parent x p
2500   // dJl_local - Jl_local x w |
2501   //
2502   // dJr: Rotational portion of Jacobian derivative
2503   // dJl: Linear portion of Jacobian derivative
2504   // dJr_parent: Parent rotational Jacobian derivative
2505   // dJl_parent: Parent linear Jacobian derivative
2506   // dJr_local: Local rotational Jacobian derivative (in World coordinates)
2507   // dJl_local: Local linear Jacobian derivative (in World coordinates)
2508   // v_local: Linear velocity relative to parent Frame
2509   // w_parent: Total angular velocity of the parent Frame
2510   // w: Total angular velocity of this Frame
2511   // p: Offset from origin of parent Frame
2512 
2513   if (nullptr == mParentJoint)
2514     return;
2515 
2516   const std::size_t numLocalDOFs = mParentJoint->getNumDofs();
2517   assert(getNumDependentGenCoords() >= numLocalDOFs);
2518   const std::size_t numParentDOFs = getNumDependentGenCoords() - numLocalDOFs;
2519 
2520   if (mParentBodyNode)
2521   {
2522     const math::Jacobian& dJ_parent
2523         = mParentBodyNode->getJacobianClassicDeriv();
2524     const math::Jacobian& J_parent = mParentBodyNode->getWorldJacobian();
2525 
2526     const Eigen::Vector3d& v_local
2527         = getLinearVelocity(mParentBodyNode, Frame::World());
2528     const Eigen::Vector3d& w_parent = mParentFrame->getAngularVelocity();
2529     const Eigen::Vector3d& p
2530         = (getWorldTransform().translation()
2531            - mParentBodyNode->getWorldTransform().translation())
2532               .eval();
2533 
2534     assert(
2535         static_cast<std::size_t>(dJ_parent.cols()) + mParentJoint->getNumDofs()
2536         == static_cast<std::size_t>(mWorldJacobianClassicDeriv.cols()));
2537 
2538     // dJr
2539     mWorldJacobianClassicDeriv.block(0, 0, 3, numParentDOFs)
2540         = dJ_parent.topRows<3>();
2541     mWorldJacobianClassicDeriv.block(3, 0, 3, numParentDOFs)
2542         = dJ_parent.bottomRows<3>()
2543           + J_parent.topRows<3>().colwise().cross(v_local + w_parent.cross(p))
2544           + dJ_parent.topRows<3>().colwise().cross(p);
2545   }
2546 
2547   const math::Jacobian& dJ_local = mParentJoint->getRelativeJacobianTimeDeriv();
2548   const math::Jacobian& J_local = mParentJoint->getRelativeJacobian();
2549   const Eigen::Isometry3d& T = getWorldTransform();
2550   const Eigen::Vector3d& w = getAngularVelocity();
2551 
2552   mWorldJacobianClassicDeriv.block(0, numParentDOFs, 3, numLocalDOFs)
2553       = T.linear() * dJ_local.topRows<3>()
2554         - (T.linear() * J_local.topRows<3>()).colwise().cross(w);
2555 
2556   mWorldJacobianClassicDeriv.block(3, numParentDOFs, 3, numLocalDOFs)
2557       = T.linear() * dJ_local.bottomRows<3>()
2558         - (T.linear() * J_local.bottomRows<3>()).colwise().cross(w);
2559 
2560   mIsWorldJacobianClassicDerivDirty = false;
2561 }
2562 
2563 } // namespace dynamics
2564 } // namespace dart
2565