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