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/Skeleton.hpp"
34
35 #include <algorithm>
36 #include <queue>
37 #include <string>
38 #include <vector>
39
40 #include "dart/common/Console.hpp"
41 #include "dart/common/Deprecated.hpp"
42 #include "dart/common/StlHelpers.hpp"
43 #include "dart/dynamics/BodyNode.hpp"
44 #include "dart/dynamics/DegreeOfFreedom.hpp"
45 #include "dart/dynamics/EndEffector.hpp"
46 #include "dart/dynamics/InverseKinematics.hpp"
47 #include "dart/dynamics/Joint.hpp"
48 #include "dart/dynamics/Marker.hpp"
49 #include "dart/dynamics/PointMass.hpp"
50 #include "dart/dynamics/ShapeNode.hpp"
51 #include "dart/dynamics/SoftBodyNode.hpp"
52 #include "dart/math/Geometry.hpp"
53 #include "dart/math/Helpers.hpp"
54
55 #define SET_ALL_FLAGS(X) \
56 for (auto& cache : mTreeCache) \
57 cache.mDirty.X = true; \
58 mSkelCache.mDirty.X = true;
59
60 #define SET_FLAG(Y, X) \
61 mTreeCache[Y].mDirty.X = true; \
62 mSkelCache.mDirty.X = true;
63
64 #define ON_ALL_TREES(X) \
65 for (std::size_t i = 0; i < mTreeCache.size(); ++i) \
66 X(i);
67
68 #define CHECK_CONFIG_VECTOR_SIZE(V) \
69 if (V.size() > 0) \
70 { \
71 if (nonzero_size != INVALID_INDEX \
72 && V.size() != static_cast<int>(nonzero_size)) \
73 { \
74 dterr << "[Skeleton::Configuration] Mismatch in size of vector [" << #V \
75 << "] (expected " << nonzero_size << " | found " << V.size() \
76 << "\n"; \
77 assert(false); \
78 } \
79 else if (nonzero_size == INVALID_INDEX) \
80 nonzero_size = V.size(); \
81 }
82
83 namespace dart {
84 namespace dynamics {
85
86 namespace detail {
87
88 //==============================================================================
89 /// Templated function for passing each entry in a std::vector<Data> into each
90 /// member of an array of Objects belonging to some Owner class.
91 ///
92 /// The ObjectBase argument should be the base class of Object in which the
93 /// setData function is defined. In many cases, ObjectBase may be the same as
94 /// Object, but it is not always.
95 //
96 // TODO(MXG): Consider putting this in an accessible header if it might be
97 // useful in other places.
98 template <
99 class Owner,
100 class Object,
101 class ObjectBase,
102 class Data,
103 std::size_t (Owner::*getNumObjects)() const,
104 Object* (Owner::*getObject)(std::size_t),
105 void (ObjectBase::*setData)(const Data&)>
setAllMemberObjectData(Owner * owner,const std::vector<Data> & data)106 void setAllMemberObjectData(Owner* owner, const std::vector<Data>& data)
107 {
108 if (!owner)
109 {
110 dterr << "[setAllMemberObjectData] Attempting to set ["
111 << typeid(Data).name() << "] of every [" << typeid(Object).name()
112 << "] in a nullptr [" << typeid(Owner).name() << "]. Please report "
113 << "this as a bug!\n";
114 assert(false);
115 return;
116 }
117
118 std::size_t numObjects = (owner->*getNumObjects)();
119
120 if (data.size() != numObjects)
121 {
122 dtwarn << "[setAllMemberObjectData] Mismatch between the number of ["
123 << typeid(Object).name() << "] member objects (" << numObjects
124 << ") in the [" << typeid(Owner).name() << "] named ["
125 << owner->getName() << "] (" << owner << ") and the number of ["
126 << typeid(Object).name() << "] which is (" << data.size()
127 << ") while setting [" << typeid(Data).name() << "]\n"
128 << " -- We will set (" << std::min(numObjects, data.size())
129 << ") of them.\n";
130 numObjects = std::min(numObjects, data.size());
131 }
132
133 for (std::size_t i = 0; i < numObjects; ++i)
134 ((owner->*getObject)(i)->*setData)(data[i]);
135 }
136
137 //==============================================================================
138 /// Templated function for aggregating a std::vector<Data> out of each member of
139 /// an array of Objects belonging to some Owner class.
140 ///
141 /// The ObjectBase argument should be the base class of Object in which the
142 /// getData function is defined. In many cases, ObjectBase may be the same as
143 /// Object, but it is not always.
144 //
145 // TODO(MXG): Consider putting this in an accessible header if it might be
146 // useful in other places.
147 template <
148 class Owner,
149 class Object,
150 class ObjectBase,
151 class Data,
152 std::size_t (Owner::*getNumObjects)() const,
153 const Object* (Owner::*getObject)(std::size_t) const,
154 Data (ObjectBase::*getData)() const>
getAllMemberObjectData(const Owner * owner)155 std::vector<Data> getAllMemberObjectData(const Owner* owner)
156 {
157 if (!owner)
158 {
159 dterr << "[getAllMemberObjectData] Attempting to get the ["
160 << typeid(Data).name() << "] from every [" << typeid(Object).name()
161 << "] in a nullptr [" << typeid(Owner).name() << "]. Please report "
162 << "this as a bug!\n";
163 assert(false);
164 return std::vector<Data>();
165 }
166
167 const std::size_t numObjects = (owner->*getNumObjects)();
168 std::vector<Data> data;
169 data.reserve(numObjects);
170
171 for (std::size_t i = 0; i < numObjects; ++i)
172 data.push_back(((owner->*getObject)(i)->*getData)());
173
174 return data;
175 }
176
177 //==============================================================================
SkeletonAspectProperties(const std::string & _name,bool _isMobile,const Eigen::Vector3d & _gravity,double _timeStep,bool _enabledSelfCollisionCheck,bool _enableAdjacentBodyCheck)178 SkeletonAspectProperties::SkeletonAspectProperties(
179 const std::string& _name,
180 bool _isMobile,
181 const Eigen::Vector3d& _gravity,
182 double _timeStep,
183 bool _enabledSelfCollisionCheck,
184 bool _enableAdjacentBodyCheck)
185 : mName(_name),
186 mIsMobile(_isMobile),
187 mGravity(_gravity),
188 mTimeStep(_timeStep),
189 mEnabledSelfCollisionCheck(_enabledSelfCollisionCheck),
190 mEnabledAdjacentBodyCheck(_enableAdjacentBodyCheck)
191 {
192 // Do nothing
193 }
194
195 //==============================================================================
setAllBodyNodeStates(Skeleton * skel,const BodyNodeStateVector & states)196 void setAllBodyNodeStates(Skeleton* skel, const BodyNodeStateVector& states)
197 {
198 setAllMemberObjectData<
199 Skeleton,
200 BodyNode,
201 common::Composite,
202 common::Composite::State,
203 &Skeleton::getNumBodyNodes,
204 &Skeleton::getBodyNode,
205 &common::Composite::setCompositeState>(skel, states);
206 }
207
208 //==============================================================================
getAllBodyNodeStates(const Skeleton * skel)209 BodyNodeStateVector getAllBodyNodeStates(const Skeleton* skel)
210 {
211 return getAllMemberObjectData<
212 Skeleton,
213 BodyNode,
214 common::Composite,
215 common::Composite::State,
216 &Skeleton::getNumBodyNodes,
217 &Skeleton::getBodyNode,
218 &common::Composite::getCompositeState>(skel);
219 }
220
221 //==============================================================================
setAllBodyNodeProperties(Skeleton * skel,const BodyNodePropertiesVector & properties)222 void setAllBodyNodeProperties(
223 Skeleton* skel, const BodyNodePropertiesVector& properties)
224 {
225 setAllMemberObjectData<
226 Skeleton,
227 BodyNode,
228 common::Composite,
229 common::Composite::Properties,
230 &Skeleton::getNumBodyNodes,
231 &Skeleton::getBodyNode,
232 &common::Composite::setCompositeProperties>(skel, properties);
233 }
234
235 //==============================================================================
getAllBodyNodeProperties(const Skeleton * skel)236 BodyNodePropertiesVector getAllBodyNodeProperties(const Skeleton* skel)
237 {
238 return getAllMemberObjectData<
239 Skeleton,
240 BodyNode,
241 common::Composite,
242 common::Composite::Properties,
243 &Skeleton::getNumBodyNodes,
244 &Skeleton::getBodyNode,
245 &common::Composite::getCompositeProperties>(skel);
246 }
247
248 //==============================================================================
setAllJointStates(Skeleton * skel,const BodyNodeStateVector & states)249 void setAllJointStates(Skeleton* skel, const BodyNodeStateVector& states)
250 {
251 setAllMemberObjectData<
252 Skeleton,
253 Joint,
254 common::Composite,
255 common::Composite::State,
256 &Skeleton::getNumJoints,
257 &Skeleton::getJoint,
258 &common::Composite::setCompositeState>(skel, states);
259 }
260
261 //==============================================================================
getAllJointStates(const Skeleton * skel)262 BodyNodeStateVector getAllJointStates(const Skeleton* skel)
263 {
264 return getAllMemberObjectData<
265 Skeleton,
266 Joint,
267 common::Composite,
268 common::Composite::State,
269 &Skeleton::getNumJoints,
270 &Skeleton::getJoint,
271 &common::Composite::getCompositeState>(skel);
272 }
273
274 //==============================================================================
setAllJointProperties(Skeleton * skel,const BodyNodePropertiesVector & properties)275 void setAllJointProperties(
276 Skeleton* skel, const BodyNodePropertiesVector& properties)
277 {
278 setAllMemberObjectData<
279 Skeleton,
280 Joint,
281 common::Composite,
282 common::Composite::Properties,
283 &Skeleton::getNumJoints,
284 &Skeleton::getJoint,
285 &common::Composite::setCompositeProperties>(skel, properties);
286 }
287
288 //==============================================================================
getAllJointProperties(const Skeleton * skel)289 BodyNodePropertiesVector getAllJointProperties(const Skeleton* skel)
290 {
291 return getAllMemberObjectData<
292 Skeleton,
293 Joint,
294 common::Composite,
295 common::Composite::Properties,
296 &Skeleton::getNumJoints,
297 &Skeleton::getJoint,
298 &common::Composite::getCompositeProperties>(skel);
299 }
300
301 } // namespace detail
302
303 //==============================================================================
Configuration(const Eigen::VectorXd & positions,const Eigen::VectorXd & velocities,const Eigen::VectorXd & accelerations,const Eigen::VectorXd & forces,const Eigen::VectorXd & commands)304 Skeleton::Configuration::Configuration(
305 const Eigen::VectorXd& positions,
306 const Eigen::VectorXd& velocities,
307 const Eigen::VectorXd& accelerations,
308 const Eigen::VectorXd& forces,
309 const Eigen::VectorXd& commands)
310 : mPositions(positions),
311 mVelocities(velocities),
312 mAccelerations(accelerations),
313 mForces(forces),
314 mCommands(commands)
315 {
316 std::size_t nonzero_size = INVALID_INDEX;
317
318 CHECK_CONFIG_VECTOR_SIZE(positions);
319 CHECK_CONFIG_VECTOR_SIZE(velocities);
320 CHECK_CONFIG_VECTOR_SIZE(accelerations);
321 CHECK_CONFIG_VECTOR_SIZE(forces);
322 CHECK_CONFIG_VECTOR_SIZE(commands);
323
324 if (nonzero_size != INVALID_INDEX)
325 {
326 for (std::size_t i = 0; i < nonzero_size; ++i)
327 mIndices.push_back(i);
328 }
329 }
330
331 //==============================================================================
Configuration(const std::vector<std::size_t> & indices,const Eigen::VectorXd & positions,const Eigen::VectorXd & velocities,const Eigen::VectorXd & accelerations,const Eigen::VectorXd & forces,const Eigen::VectorXd & commands)332 Skeleton::Configuration::Configuration(
333 const std::vector<std::size_t>& indices,
334 const Eigen::VectorXd& positions,
335 const Eigen::VectorXd& velocities,
336 const Eigen::VectorXd& accelerations,
337 const Eigen::VectorXd& forces,
338 const Eigen::VectorXd& commands)
339 : mIndices(indices),
340 mPositions(positions),
341 mVelocities(velocities),
342 mAccelerations(accelerations),
343 mForces(forces),
344 mCommands(commands)
345 {
346 std::size_t nonzero_size = indices.size();
347
348 CHECK_CONFIG_VECTOR_SIZE(positions);
349 CHECK_CONFIG_VECTOR_SIZE(velocities);
350 CHECK_CONFIG_VECTOR_SIZE(accelerations);
351 CHECK_CONFIG_VECTOR_SIZE(forces);
352 CHECK_CONFIG_VECTOR_SIZE(commands);
353 }
354
355 //==============================================================================
356 #define RETURN_IF_CONFIG_VECTOR_IS_INEQ(V) \
357 if (V.size() != other.V.size()) \
358 return false; \
359 if (V != other.V) \
360 return false;
361
362 //==============================================================================
operator ==(const Configuration & other) const363 bool Skeleton::Configuration::operator==(const Configuration& other) const
364 {
365 if (mIndices != other.mIndices)
366 return false;
367
368 RETURN_IF_CONFIG_VECTOR_IS_INEQ(mPositions);
369 RETURN_IF_CONFIG_VECTOR_IS_INEQ(mVelocities);
370 RETURN_IF_CONFIG_VECTOR_IS_INEQ(mAccelerations);
371 RETURN_IF_CONFIG_VECTOR_IS_INEQ(mForces);
372 RETURN_IF_CONFIG_VECTOR_IS_INEQ(mCommands);
373
374 return true;
375 }
376
377 //==============================================================================
operator !=(const Configuration & other) const378 bool Skeleton::Configuration::operator!=(const Configuration& other) const
379 {
380 return !(*this == other);
381 }
382
383 //==============================================================================
create(const std::string & _name)384 SkeletonPtr Skeleton::create(const std::string& _name)
385 {
386 return create(AspectPropertiesData(_name));
387 }
388
389 //==============================================================================
create(const AspectPropertiesData & properties)390 SkeletonPtr Skeleton::create(const AspectPropertiesData& properties)
391 {
392 SkeletonPtr skel(new Skeleton(properties));
393 skel->setPtr(skel);
394 return skel;
395 }
396
397 //==============================================================================
getPtr()398 SkeletonPtr Skeleton::getPtr()
399 {
400 return mPtr.lock();
401 }
402
403 //==============================================================================
getPtr() const404 ConstSkeletonPtr Skeleton::getPtr() const
405 {
406 return mPtr.lock();
407 }
408
409 //==============================================================================
getSkeleton()410 SkeletonPtr Skeleton::getSkeleton()
411 {
412 return mPtr.lock();
413 }
414
415 //==============================================================================
getSkeleton() const416 ConstSkeletonPtr Skeleton::getSkeleton() const
417 {
418 return mPtr.lock();
419 }
420
421 //==============================================================================
getMutex() const422 std::mutex& Skeleton::getMutex() const
423 {
424 return mMutex;
425 }
426
427 //==============================================================================
getLockableReference() const428 std::unique_ptr<common::LockableReference> Skeleton::getLockableReference()
429 const
430 {
431 return std::make_unique<common::SingleLockableReference<std::mutex>>(
432 mPtr, mMutex);
433 }
434
435 //==============================================================================
~Skeleton()436 Skeleton::~Skeleton()
437 {
438 for (BodyNode* bn : mSkelCache.mBodyNodes)
439 delete bn;
440 }
441
442 //==============================================================================
clone() const443 SkeletonPtr Skeleton::clone() const
444 {
445 return cloneSkeleton(getName());
446 }
447
448 //==============================================================================
clone(const std::string & cloneName) const449 SkeletonPtr Skeleton::clone(const std::string& cloneName) const
450 {
451 return cloneSkeleton(cloneName);
452 }
453
454 //==============================================================================
cloneSkeleton() const455 SkeletonPtr Skeleton::cloneSkeleton() const
456 {
457 return cloneSkeleton(getName());
458 }
459
460 //==============================================================================
cloneSkeleton(const std::string & cloneName) const461 SkeletonPtr Skeleton::cloneSkeleton(const std::string& cloneName) const
462 {
463 SkeletonPtr skelClone = Skeleton::create(cloneName);
464
465 for (std::size_t i = 0; i < getNumBodyNodes(); ++i)
466 {
467 // Create a clone of the parent Joint
468 Joint* joint = getJoint(i)->clone();
469
470 // Identify the original parent BodyNode
471 const BodyNode* originalParent = getBodyNode(i)->getParentBodyNode();
472
473 // Grab the parent BodyNode clone (using its name, which is guaranteed to be
474 // unique), or use nullptr if this is a root BodyNode
475 BodyNode* parentClone
476 = (originalParent == nullptr)
477 ? nullptr
478 : skelClone->getBodyNode(originalParent->getName());
479
480 if ((nullptr != originalParent) && (nullptr == parentClone))
481 {
482 dterr << "[Skeleton::clone] Failed to find a clone of BodyNode named ["
483 << originalParent->getName() << "] which is needed as the parent "
484 << "of the BodyNode named [" << getBodyNode(i)->getName()
485 << "] and should already have been created. Please report this as "
486 << "a bug!\n";
487 }
488
489 BodyNode* newBody = getBodyNode(i)->clone(parentClone, joint, false);
490
491 // The IK module gets cloned by the Skeleton and not by the BodyNode,
492 // because IK modules rely on the Skeleton's structure and indexing. If the
493 // IK was cloned by the BodyNode into a Skeleton that has a different
494 // structure, then there is no guarantee that it will continue to work
495 // correctly.
496 if (getBodyNode(i)->getIK())
497 newBody->mIK = getBodyNode(i)->getIK()->clone(newBody);
498
499 skelClone->registerBodyNode(newBody);
500 }
501
502 // Clone over the nodes in such a way that their indexing will match up with
503 // the original
504 for (const auto& nodeType : mNodeMap)
505 {
506 for (const auto& node : nodeType.second)
507 {
508 const BodyNode* originalBn = node->getBodyNodePtr();
509 BodyNode* newBn = skelClone->getBodyNode(originalBn->getName());
510 node->cloneNode(newBn)->attach();
511 }
512 }
513
514 skelClone->setProperties(getAspectProperties());
515 skelClone->setName(cloneName);
516 skelClone->setState(getState());
517
518 // Fix mimic joint references
519 for (std::size_t i = 0; i < getNumJoints(); ++i)
520 {
521 Joint* joint = skelClone->getJoint(i);
522 if (joint->getActuatorType() == Joint::MIMIC)
523 {
524 const Joint* mimicJoint
525 = skelClone->getJoint(joint->getMimicJoint()->getName());
526 if (mimicJoint)
527 {
528 joint->setMimicJoint(
529 mimicJoint, joint->getMimicMultiplier(), joint->getMimicOffset());
530 }
531 else
532 {
533 dterr << "[Skeleton::clone] Failed to clone mimic joint successfully: "
534 << "Unable to find the mimic joint ["
535 << joint->getMimicJoint()->getName()
536 << "] in the cloned Skeleton. Please report this as a bug!\n";
537 }
538 }
539 }
540
541 return skelClone;
542 }
543
544 //==============================================================================
cloneMetaSkeleton(const std::string & cloneName) const545 MetaSkeletonPtr Skeleton::cloneMetaSkeleton(const std::string& cloneName) const
546 {
547 return cloneSkeleton(cloneName);
548 }
549
550 //==============================================================================
551 #define SET_CONFIG_VECTOR(V) \
552 if (configuration.m##V.size() > 0) \
553 { \
554 if (static_cast<int>(configuration.mIndices.size()) \
555 != configuration.m##V.size()) \
556 { \
557 dterr << "[Skeleton::setConfiguration] Mismatch in size of vector [" \
558 << #V << "] (expected " << configuration.mIndices.size() \
559 << " | found " << configuration.m##V.size() << "\n"; \
560 assert(false); \
561 } \
562 else \
563 set##V(configuration.mIndices, configuration.m##V); \
564 }
565
566 //==============================================================================
setConfiguration(const Configuration & configuration)567 void Skeleton::setConfiguration(const Configuration& configuration)
568 {
569 SET_CONFIG_VECTOR(Positions);
570 SET_CONFIG_VECTOR(Velocities);
571 SET_CONFIG_VECTOR(Accelerations);
572 SET_CONFIG_VECTOR(Forces);
573 SET_CONFIG_VECTOR(Commands);
574 }
575
576 //==============================================================================
getConfiguration(int flags) const577 Skeleton::Configuration Skeleton::getConfiguration(int flags) const
578 {
579 std::vector<std::size_t> indices;
580 for (std::size_t i = 0; i < getNumDofs(); ++i)
581 indices.push_back(i);
582
583 return getConfiguration(indices, flags);
584 }
585
586 //==============================================================================
getConfiguration(const std::vector<std::size_t> & indices,int flags) const587 Skeleton::Configuration Skeleton::getConfiguration(
588 const std::vector<std::size_t>& indices, int flags) const
589 {
590 Configuration config(indices);
591 if (flags == CONFIG_NOTHING)
592 return config;
593
594 if ((flags & CONFIG_POSITIONS) == CONFIG_POSITIONS)
595 config.mPositions = getPositions(indices);
596
597 if ((flags & CONFIG_VELOCITIES) == CONFIG_VELOCITIES)
598 config.mVelocities = getVelocities(indices);
599
600 if ((flags & CONFIG_ACCELERATIONS) == CONFIG_ACCELERATIONS)
601 config.mAccelerations = getAccelerations(indices);
602
603 if ((flags & CONFIG_FORCES) == CONFIG_FORCES)
604 config.mForces = getForces(indices);
605
606 if ((flags & CONFIG_COMMANDS) == CONFIG_COMMANDS)
607 config.mCommands = getCommands(indices);
608
609 return config;
610 }
611
612 //==============================================================================
setState(const State & state)613 void Skeleton::setState(const State& state)
614 {
615 setCompositeState(state);
616 }
617
618 //==============================================================================
getState() const619 Skeleton::State Skeleton::getState() const
620 {
621 return getCompositeState();
622 }
623
624 //==============================================================================
setProperties(const Properties & properties)625 void Skeleton::setProperties(const Properties& properties)
626 {
627 setCompositeProperties(properties);
628 }
629
630 //==============================================================================
getProperties() const631 Skeleton::Properties Skeleton::getProperties() const
632 {
633 return getCompositeProperties();
634 }
635
636 //==============================================================================
setProperties(const AspectProperties & properties)637 void Skeleton::setProperties(const AspectProperties& properties)
638 {
639 setAspectProperties(properties);
640 }
641
642 //==============================================================================
setAspectProperties(const AspectProperties & properties)643 void Skeleton::setAspectProperties(const AspectProperties& properties)
644 {
645 setName(properties.mName);
646 setMobile(properties.mIsMobile);
647 setGravity(properties.mGravity);
648 setTimeStep(properties.mTimeStep);
649 setSelfCollisionCheck(properties.mEnabledSelfCollisionCheck);
650 setAdjacentBodyCheck(properties.mEnabledAdjacentBodyCheck);
651 }
652
653 //==============================================================================
getSkeletonProperties() const654 const Skeleton::AspectProperties& Skeleton::getSkeletonProperties() const
655 {
656 return mAspectProperties;
657 }
658
659 //==============================================================================
setName(const std::string & _name)660 const std::string& Skeleton::setName(const std::string& _name)
661 {
662 if (_name == mAspectProperties.mName && !_name.empty())
663 return mAspectProperties.mName;
664
665 const std::string oldName = mAspectProperties.mName;
666 mAspectProperties.mName = _name;
667
668 updateNameManagerNames();
669
670 ConstMetaSkeletonPtr me = mPtr.lock();
671 mNameChangedSignal.raise(me, oldName, mAspectProperties.mName);
672
673 return mAspectProperties.mName;
674 }
675
676 //==============================================================================
getName() const677 const std::string& Skeleton::getName() const
678 {
679 return mAspectProperties.mName;
680 }
681
682 //==============================================================================
addEntryToBodyNodeNameMgr(BodyNode * _newNode)683 const std::string& Skeleton::addEntryToBodyNodeNameMgr(BodyNode* _newNode)
684 {
685 _newNode->BodyNode::mAspectProperties.mName
686 = mNameMgrForBodyNodes.issueNewNameAndAdd(_newNode->getName(), _newNode);
687
688 return _newNode->BodyNode::mAspectProperties.mName;
689 }
690
691 //==============================================================================
addEntryToJointNameMgr(Joint * _newJoint,bool _updateDofNames)692 const std::string& Skeleton::addEntryToJointNameMgr(
693 Joint* _newJoint, bool _updateDofNames)
694 {
695 _newJoint->mAspectProperties.mName
696 = mNameMgrForJoints.issueNewNameAndAdd(_newJoint->getName(), _newJoint);
697
698 if (_updateDofNames)
699 _newJoint->updateDegreeOfFreedomNames();
700
701 return _newJoint->mAspectProperties.mName;
702 }
703
704 //==============================================================================
addEntryToSoftBodyNodeNameMgr(SoftBodyNode * _newNode)705 void Skeleton::addEntryToSoftBodyNodeNameMgr(SoftBodyNode* _newNode)
706 {
707 // Note: This doesn't need the same checks as BodyNode and Joint, because
708 // its name has already been resolved against all the BodyNodes, which
709 // includes all SoftBodyNodes.
710 mNameMgrForSoftBodyNodes.addName(_newNode->getName(), _newNode);
711 }
712
713 //==============================================================================
updateNameManagerNames()714 void Skeleton::updateNameManagerNames()
715 {
716 mNameMgrForBodyNodes.setManagerName(
717 "Skeleton::BodyNode | " + mAspectProperties.mName);
718 mNameMgrForSoftBodyNodes.setManagerName(
719 "Skeleton::SoftBodyNode | " + mAspectProperties.mName);
720 mNameMgrForJoints.setManagerName(
721 "Skeleton::Joint | " + mAspectProperties.mName);
722 mNameMgrForDofs.setManagerName(
723 "Skeleton::DegreeOfFreedom | " + mAspectProperties.mName);
724
725 for (auto& mgr : mNodeNameMgrMap)
726 {
727 mgr.second.setManagerName(
728 std::string("Skeleton::") + mgr.first.name() + " | "
729 + mAspectProperties.mName);
730 }
731 }
732
733 //==============================================================================
enableSelfCollision(bool enableAdjacentBodyCheck)734 void Skeleton::enableSelfCollision(bool enableAdjacentBodyCheck)
735 {
736 enableSelfCollisionCheck();
737 setAdjacentBodyCheck(enableAdjacentBodyCheck);
738 }
739
740 //==============================================================================
disableSelfCollision()741 void Skeleton::disableSelfCollision()
742 {
743 disableSelfCollisionCheck();
744 setAdjacentBodyCheck(false);
745 }
746
747 //==============================================================================
setSelfCollisionCheck(bool enable)748 void Skeleton::setSelfCollisionCheck(bool enable)
749 {
750 mAspectProperties.mEnabledSelfCollisionCheck = enable;
751 }
752
753 //==============================================================================
getSelfCollisionCheck() const754 bool Skeleton::getSelfCollisionCheck() const
755 {
756 return mAspectProperties.mEnabledSelfCollisionCheck;
757 }
758
759 //==============================================================================
enableSelfCollisionCheck()760 void Skeleton::enableSelfCollisionCheck()
761 {
762 setSelfCollisionCheck(true);
763 }
764
765 //==============================================================================
disableSelfCollisionCheck()766 void Skeleton::disableSelfCollisionCheck()
767 {
768 setSelfCollisionCheck(false);
769 }
770
771 //==============================================================================
isEnabledSelfCollisionCheck() const772 bool Skeleton::isEnabledSelfCollisionCheck() const
773 {
774 return getSelfCollisionCheck();
775 }
776
777 //==============================================================================
setAdjacentBodyCheck(bool enable)778 void Skeleton::setAdjacentBodyCheck(bool enable)
779 {
780 mAspectProperties.mEnabledAdjacentBodyCheck = enable;
781 }
782
783 //==============================================================================
getAdjacentBodyCheck() const784 bool Skeleton::getAdjacentBodyCheck() const
785 {
786 return mAspectProperties.mEnabledAdjacentBodyCheck;
787 }
788
789 //==============================================================================
enableAdjacentBodyCheck()790 void Skeleton::enableAdjacentBodyCheck()
791 {
792 setAdjacentBodyCheck(true);
793 }
794
795 //==============================================================================
disableAdjacentBodyCheck()796 void Skeleton::disableAdjacentBodyCheck()
797 {
798 setAdjacentBodyCheck(false);
799 }
800
801 //==============================================================================
isEnabledAdjacentBodyCheck() const802 bool Skeleton::isEnabledAdjacentBodyCheck() const
803 {
804 return getAdjacentBodyCheck();
805 }
806
807 //==============================================================================
setMobile(bool _isMobile)808 void Skeleton::setMobile(bool _isMobile)
809 {
810 mAspectProperties.mIsMobile = _isMobile;
811 }
812
813 //==============================================================================
isMobile() const814 bool Skeleton::isMobile() const
815 {
816 return mAspectProperties.mIsMobile;
817 }
818
819 //==============================================================================
setTimeStep(double _timeStep)820 void Skeleton::setTimeStep(double _timeStep)
821 {
822 assert(_timeStep > 0.0);
823 mAspectProperties.mTimeStep = _timeStep;
824
825 for (std::size_t i = 0; i < mTreeCache.size(); ++i)
826 dirtyArticulatedInertia(i);
827 }
828
829 //==============================================================================
getTimeStep() const830 double Skeleton::getTimeStep() const
831 {
832 return mAspectProperties.mTimeStep;
833 }
834
835 //==============================================================================
setGravity(const Eigen::Vector3d & _gravity)836 void Skeleton::setGravity(const Eigen::Vector3d& _gravity)
837 {
838 mAspectProperties.mGravity = _gravity;
839 SET_ALL_FLAGS(mGravityForces);
840 SET_ALL_FLAGS(mCoriolisAndGravityForces);
841 ON_ALL_TREES(dirtySupportPolygon);
842 }
843
844 //==============================================================================
getGravity() const845 const Eigen::Vector3d& Skeleton::getGravity() const
846 {
847 return mAspectProperties.mGravity;
848 }
849
850 //==============================================================================
getNumBodyNodes() const851 std::size_t Skeleton::getNumBodyNodes() const
852 {
853 return mSkelCache.mBodyNodes.size();
854 }
855
856 //==============================================================================
getNumRigidBodyNodes() const857 std::size_t Skeleton::getNumRigidBodyNodes() const
858 {
859 return mSkelCache.mBodyNodes.size() - mSoftBodyNodes.size();
860 }
861
862 //==============================================================================
getNumSoftBodyNodes() const863 std::size_t Skeleton::getNumSoftBodyNodes() const
864 {
865 return mSoftBodyNodes.size();
866 }
867
868 //==============================================================================
getNumTrees() const869 std::size_t Skeleton::getNumTrees() const
870 {
871 return mTreeCache.size();
872 }
873
874 //==============================================================================
getRootBodyNode(std::size_t _treeIdx)875 BodyNode* Skeleton::getRootBodyNode(std::size_t _treeIdx)
876 {
877 if (mTreeCache.size() > _treeIdx)
878 return mTreeCache[_treeIdx].mBodyNodes[0];
879
880 if (mTreeCache.size() == 0)
881 {
882 dterr << "[Skeleton::getRootBodyNode] Requested a root BodyNode from a "
883 << "Skeleton with no BodyNodes!\n";
884 assert(false);
885 }
886 else
887 {
888 dterr << "[Skeleton::getRootBodyNode] Requested invalid root BodyNode "
889 << "index (" << _treeIdx << ")! Must be less than "
890 << mTreeCache.size() << ".\n";
891 assert(false);
892 }
893
894 return nullptr;
895 }
896
897 //==============================================================================
getRootBodyNode(std::size_t _treeIdx) const898 const BodyNode* Skeleton::getRootBodyNode(std::size_t _treeIdx) const
899 {
900 return const_cast<Skeleton*>(this)->getRootBodyNode(_treeIdx);
901 }
902
903 //==============================================================================
getRootJoint(std::size_t treeIdx)904 Joint* Skeleton::getRootJoint(std::size_t treeIdx)
905 {
906 auto rootBodyNode = getRootBodyNode(treeIdx);
907
908 if (rootBodyNode)
909 return rootBodyNode->getParentJoint();
910
911 return nullptr;
912 }
913
914 //==============================================================================
getRootJoint(std::size_t treeIdx) const915 const Joint* Skeleton::getRootJoint(std::size_t treeIdx) const
916 {
917 return const_cast<Skeleton*>(this)->getRootJoint(treeIdx);
918 }
919
920 //==============================================================================
getBodyNode(std::size_t _idx)921 BodyNode* Skeleton::getBodyNode(std::size_t _idx)
922 {
923 return common::getVectorObjectIfAvailable<BodyNode*>(
924 _idx, mSkelCache.mBodyNodes);
925 }
926
927 //==============================================================================
getBodyNode(std::size_t _idx) const928 const BodyNode* Skeleton::getBodyNode(std::size_t _idx) const
929 {
930 return common::getVectorObjectIfAvailable<BodyNode*>(
931 _idx, mSkelCache.mBodyNodes);
932 }
933
934 //==============================================================================
getSoftBodyNode(std::size_t _idx)935 SoftBodyNode* Skeleton::getSoftBodyNode(std::size_t _idx)
936 {
937 return common::getVectorObjectIfAvailable<SoftBodyNode*>(
938 _idx, mSoftBodyNodes);
939 }
940
941 //==============================================================================
getSoftBodyNode(std::size_t _idx) const942 const SoftBodyNode* Skeleton::getSoftBodyNode(std::size_t _idx) const
943 {
944 return common::getVectorObjectIfAvailable<SoftBodyNode*>(
945 _idx, mSoftBodyNodes);
946 }
947
948 //==============================================================================
getBodyNode(const std::string & _name)949 BodyNode* Skeleton::getBodyNode(const std::string& _name)
950 {
951 return mNameMgrForBodyNodes.getObject(_name);
952 }
953
954 //==============================================================================
getBodyNode(const std::string & _name) const955 const BodyNode* Skeleton::getBodyNode(const std::string& _name) const
956 {
957 return mNameMgrForBodyNodes.getObject(_name);
958 }
959
960 //==============================================================================
getSoftBodyNode(const std::string & _name)961 SoftBodyNode* Skeleton::getSoftBodyNode(const std::string& _name)
962 {
963 return mNameMgrForSoftBodyNodes.getObject(_name);
964 }
965
966 //==============================================================================
getSoftBodyNode(const std::string & _name) const967 const SoftBodyNode* Skeleton::getSoftBodyNode(const std::string& _name) const
968 {
969 return mNameMgrForSoftBodyNodes.getObject(_name);
970 }
971
972 //==============================================================================
973 template <class T>
convertToConstPtrVector(const std::vector<T * > & vec,std::vector<const T * > & const_vec)974 static std::vector<const T*>& convertToConstPtrVector(
975 const std::vector<T*>& vec, std::vector<const T*>& const_vec)
976 {
977 const_vec.resize(vec.size());
978 for (std::size_t i = 0; i < vec.size(); ++i)
979 const_vec[i] = vec[i];
980 return const_vec;
981 }
982
983 //==============================================================================
getBodyNodes()984 const std::vector<BodyNode*>& Skeleton::getBodyNodes()
985 {
986 return mSkelCache.mBodyNodes;
987 }
988
989 //==============================================================================
getBodyNodes() const990 const std::vector<const BodyNode*>& Skeleton::getBodyNodes() const
991 {
992 return convertToConstPtrVector<BodyNode>(
993 mSkelCache.mBodyNodes, mSkelCache.mConstBodyNodes);
994 }
995
996 //==============================================================================
getBodyNodes(const std::string & name)997 std::vector<BodyNode*> Skeleton::getBodyNodes(const std::string& name)
998 {
999 auto bodyNode = getBodyNode(name);
1000
1001 if (bodyNode)
1002 return {bodyNode};
1003 else
1004 return std::vector<BodyNode*>();
1005 }
1006
1007 //==============================================================================
getBodyNodes(const std::string & name) const1008 std::vector<const BodyNode*> Skeleton::getBodyNodes(
1009 const std::string& name) const
1010 {
1011 const auto bodyNode = getBodyNode(name);
1012
1013 if (bodyNode)
1014 return {bodyNode};
1015 else
1016 return std::vector<const BodyNode*>();
1017 }
1018
1019 //==============================================================================
hasBodyNode(const BodyNode * bodyNode) const1020 bool Skeleton::hasBodyNode(const BodyNode* bodyNode) const
1021 {
1022 return std::find(
1023 mSkelCache.mBodyNodes.begin(),
1024 mSkelCache.mBodyNodes.end(),
1025 bodyNode)
1026 != mSkelCache.mBodyNodes.end();
1027 }
1028
1029 //==============================================================================
1030 template <class ObjectT, std::size_t (ObjectT::*getIndexInSkeleton)() const>
templatedGetIndexOf(const Skeleton * _skel,const ObjectT * _obj,const std::string & _type,bool _warning)1031 static std::size_t templatedGetIndexOf(
1032 const Skeleton* _skel,
1033 const ObjectT* _obj,
1034 const std::string& _type,
1035 bool _warning)
1036 {
1037 if (nullptr == _obj)
1038 {
1039 if (_warning)
1040 {
1041 dterr << "[Skeleton::getIndexOf] Requesting the index of a nullptr "
1042 << _type << " within the Skeleton [" << _skel->getName() << "] ("
1043 << _skel << ")!\n";
1044 assert(false);
1045 }
1046 return INVALID_INDEX;
1047 }
1048
1049 if (_skel == _obj->getSkeleton().get())
1050 return (_obj->*getIndexInSkeleton)();
1051
1052 if (_warning)
1053 {
1054 dterr << "[Skeleton::getIndexOf] Requesting the index of a " << _type
1055 << " [" << _obj->getName() << "] (" << _obj
1056 << ") from a Skeleton that it does "
1057 << "not belong to!\n";
1058 assert(false);
1059 }
1060
1061 return INVALID_INDEX;
1062 }
1063
1064 //==============================================================================
getIndexOf(const BodyNode * _bn,bool _warning) const1065 std::size_t Skeleton::getIndexOf(const BodyNode* _bn, bool _warning) const
1066 {
1067 return templatedGetIndexOf<BodyNode, &BodyNode::getIndexInSkeleton>(
1068 this, _bn, "BodyNode", _warning);
1069 }
1070
1071 //==============================================================================
getTreeBodyNodes(std::size_t _treeIdx)1072 const std::vector<BodyNode*>& Skeleton::getTreeBodyNodes(std::size_t _treeIdx)
1073 {
1074 if (_treeIdx >= mTreeCache.size())
1075 {
1076 std::size_t count = mTreeCache.size();
1077 dterr << "[Skeleton::getTreeBodyNodes] Requesting an invalid tree ("
1078 << _treeIdx << ") "
1079 << (count > 0
1080 ? (std::string("when the max tree index is (")
1081 + std::to_string(count - 1) + ")\n")
1082 : std::string("when there are no trees in this Skeleton\n"));
1083 assert(false);
1084 }
1085
1086 return mTreeCache[_treeIdx].mBodyNodes;
1087 }
1088
1089 //==============================================================================
getTreeBodyNodes(std::size_t _treeIdx) const1090 std::vector<const BodyNode*> Skeleton::getTreeBodyNodes(
1091 std::size_t _treeIdx) const
1092 {
1093 return convertToConstPtrVector<BodyNode>(
1094 mTreeCache[_treeIdx].mBodyNodes, mTreeCache[_treeIdx].mConstBodyNodes);
1095 }
1096
1097 //==============================================================================
getNumJoints() const1098 std::size_t Skeleton::getNumJoints() const
1099 {
1100 // The number of joints and body nodes are identical
1101 return getNumBodyNodes();
1102 }
1103
1104 //==============================================================================
getJoint(std::size_t _idx)1105 Joint* Skeleton::getJoint(std::size_t _idx)
1106 {
1107 BodyNode* bn = common::getVectorObjectIfAvailable<BodyNode*>(
1108 _idx, mSkelCache.mBodyNodes);
1109 if (bn)
1110 return bn->getParentJoint();
1111
1112 return nullptr;
1113 }
1114
1115 //==============================================================================
getJoint(std::size_t _idx) const1116 const Joint* Skeleton::getJoint(std::size_t _idx) const
1117 {
1118 return const_cast<Skeleton*>(this)->getJoint(_idx);
1119 }
1120
1121 //==============================================================================
getJoint(const std::string & name)1122 Joint* Skeleton::getJoint(const std::string& name)
1123 {
1124 return mNameMgrForJoints.getObject(name);
1125 }
1126
1127 //==============================================================================
getJoint(const std::string & name) const1128 const Joint* Skeleton::getJoint(const std::string& name) const
1129 {
1130 return mNameMgrForJoints.getObject(name);
1131 }
1132
1133 //==============================================================================
getJoints()1134 std::vector<Joint*> Skeleton::getJoints()
1135 {
1136 const auto& bodyNodes = getBodyNodes();
1137
1138 std::vector<Joint*> joints;
1139 joints.reserve(bodyNodes.size());
1140 for (const auto& bodyNode : bodyNodes)
1141 joints.emplace_back(bodyNode->getParentJoint());
1142
1143 return joints;
1144 }
1145
1146 //==============================================================================
getJoints() const1147 std::vector<const Joint*> Skeleton::getJoints() const
1148 {
1149 const auto& bodyNodes = getBodyNodes();
1150
1151 std::vector<const Joint*> joints;
1152 joints.reserve(bodyNodes.size());
1153 for (const auto& bodyNode : bodyNodes)
1154 joints.emplace_back(bodyNode->getParentJoint());
1155
1156 return joints;
1157 }
1158
1159 //==============================================================================
getJoints(const std::string & name)1160 std::vector<Joint*> Skeleton::getJoints(const std::string& name)
1161 {
1162 auto joint = getJoint(name);
1163
1164 if (joint)
1165 return {joint};
1166 else
1167 return std::vector<Joint*>();
1168 }
1169
1170 //==============================================================================
getJoints(const std::string & name) const1171 std::vector<const Joint*> Skeleton::getJoints(const std::string& name) const
1172 {
1173 const auto joint = getJoint(name);
1174
1175 if (joint)
1176 return {joint};
1177 else
1178 return std::vector<const Joint*>();
1179 }
1180
1181 //==============================================================================
hasJoint(const Joint * joint) const1182 bool Skeleton::hasJoint(const Joint* joint) const
1183 {
1184 return std::find_if(
1185 mSkelCache.mBodyNodes.begin(),
1186 mSkelCache.mBodyNodes.end(),
1187 [&joint](const BodyNode* bodyNode) {
1188 return bodyNode->getParentJoint() == joint;
1189 })
1190 != mSkelCache.mBodyNodes.end();
1191 }
1192
1193 //==============================================================================
getIndexOf(const Joint * _joint,bool _warning) const1194 std::size_t Skeleton::getIndexOf(const Joint* _joint, bool _warning) const
1195 {
1196 return templatedGetIndexOf<Joint, &Joint::getJointIndexInSkeleton>(
1197 this, _joint, "Joint", _warning);
1198 }
1199
1200 //==============================================================================
getNumDofs() const1201 std::size_t Skeleton::getNumDofs() const
1202 {
1203 return mSkelCache.mDofs.size();
1204 }
1205
1206 //==============================================================================
getDof(std::size_t _idx)1207 DegreeOfFreedom* Skeleton::getDof(std::size_t _idx)
1208 {
1209 return common::getVectorObjectIfAvailable<DegreeOfFreedom*>(
1210 _idx, mSkelCache.mDofs);
1211 }
1212
1213 //==============================================================================
getDof(std::size_t _idx) const1214 const DegreeOfFreedom* Skeleton::getDof(std::size_t _idx) const
1215 {
1216 return common::getVectorObjectIfAvailable<DegreeOfFreedom*>(
1217 _idx, mSkelCache.mDofs);
1218 }
1219
1220 //==============================================================================
getDof(const std::string & _name)1221 DegreeOfFreedom* Skeleton::getDof(const std::string& _name)
1222 {
1223 return mNameMgrForDofs.getObject(_name);
1224 }
1225
1226 //==============================================================================
getDof(const std::string & _name) const1227 const DegreeOfFreedom* Skeleton::getDof(const std::string& _name) const
1228 {
1229 return mNameMgrForDofs.getObject(_name);
1230 }
1231
1232 //==============================================================================
getDofs()1233 const std::vector<DegreeOfFreedom*>& Skeleton::getDofs()
1234 {
1235 return mSkelCache.mDofs;
1236 }
1237
1238 //==============================================================================
getDofs() const1239 std::vector<const DegreeOfFreedom*> Skeleton::getDofs() const
1240 {
1241 return convertToConstPtrVector<DegreeOfFreedom>(
1242 mSkelCache.mDofs, mSkelCache.mConstDofs);
1243 }
1244
1245 //==============================================================================
getIndexOf(const DegreeOfFreedom * _dof,bool _warning) const1246 std::size_t Skeleton::getIndexOf(
1247 const DegreeOfFreedom* _dof, bool _warning) const
1248 {
1249 return templatedGetIndexOf<
1250 DegreeOfFreedom,
1251 &DegreeOfFreedom::getIndexInSkeleton>(
1252 this, _dof, "DegreeOfFreedom", _warning);
1253 }
1254
1255 //==============================================================================
getTreeDofs(std::size_t _treeIdx)1256 const std::vector<DegreeOfFreedom*>& Skeleton::getTreeDofs(std::size_t _treeIdx)
1257 {
1258 return mTreeCache[_treeIdx].mDofs;
1259 }
1260
1261 //==============================================================================
getTreeDofs(std::size_t _treeIdx) const1262 const std::vector<const DegreeOfFreedom*>& Skeleton::getTreeDofs(
1263 std::size_t _treeIdx) const
1264 {
1265 return convertToConstPtrVector<DegreeOfFreedom>(
1266 mTreeCache[_treeIdx].mDofs, mTreeCache[_treeIdx].mConstDofs);
1267 }
1268
1269 //==============================================================================
checkIndexingConsistency() const1270 bool Skeleton::checkIndexingConsistency() const
1271 {
1272 bool consistent = true;
1273
1274 // Check each BodyNode in the Skeleton cache
1275 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
1276 {
1277 const BodyNode* bn = mSkelCache.mBodyNodes[i];
1278 if (bn->mIndexInSkeleton != i)
1279 {
1280 dterr << "[Skeleton::checkIndexingConsistency] BodyNode named ["
1281 << bn->getName() << "] in Skeleton [" << getName() << "] is "
1282 << "mistaken about its index in the Skeleton (" << i << " | "
1283 << bn->mIndexInSkeleton << "). Please report this as a bug!"
1284 << std::endl;
1285 consistent = false;
1286 assert(false);
1287 }
1288
1289 const BodyNode* nameEntryForBodyNode = getBodyNode(bn->getName());
1290 if (nameEntryForBodyNode != bn)
1291 {
1292 dterr << "[Skeleton::checkIndexingConsistency] Skeleton named ["
1293 << getName() << "] (" << this << ") is mistaken about the name of "
1294 << "BodyNode [" << bn->getName() << "] (" << bn << "). The name "
1295 << "instead maps to [" << nameEntryForBodyNode->getName() << "] ("
1296 << nameEntryForBodyNode << "). Please report this as a bug!"
1297 << std::endl;
1298 consistent = false;
1299 assert(false);
1300 }
1301
1302 const Joint* joint = bn->getParentJoint();
1303 const Joint* nameEntryForJoint = getJoint(joint->getName());
1304 if (nameEntryForJoint != joint)
1305 {
1306 dterr << "[Skeleton::checkIndexingConsistency] Skeleton named ["
1307 << getName() << "] (" << this << ") is mistaken about the name of "
1308 << "Joint [" << joint->getName() << "] (" << joint << "). The name "
1309 << "instead maps to [" << nameEntryForJoint->getName() << "] ("
1310 << nameEntryForJoint << "). Please report this as a bug!"
1311 << std::endl;
1312 consistent = false;
1313 assert(false);
1314 }
1315
1316 const BodyNode::NodeMap& nodeMap = bn->mNodeMap;
1317 for (const auto& nodeType : nodeMap)
1318 {
1319 const std::vector<Node*>& nodes = nodeType.second;
1320 for (std::size_t k = 0; k < nodes.size(); ++k)
1321 {
1322 const Node* node = nodes[k];
1323 if (node->getBodyNodePtr() != bn)
1324 {
1325 dterr << "[Skeleton::checkIndexingConsistency] Node named ["
1326 << node->getName() << "] (" << node << ") in Skeleton ["
1327 << getName() << "] (" << this << ") is mistaken about its "
1328 << "BodyNode [" << node->getBodyNodePtr()->getName() << "] ("
1329 << node->getBodyNodePtr() << "). Please report this as a bug!"
1330 << std::endl;
1331 consistent = false;
1332 assert(false);
1333 }
1334
1335 if (node->mIndexInBodyNode != k)
1336 {
1337 dterr << "[Skeleton::checkIndexingConsistency] Node named ["
1338 << node->getName() << "] (" << node << ") in Skeleton ["
1339 << getName() << "] (" << this << ") is mistaken about its "
1340 << "index in its BodyNode (" << k << "|"
1341 << node->mIndexInBodyNode << "). Please report this as a bug!"
1342 << std::endl;
1343 consistent = false;
1344 assert(false);
1345 }
1346
1347 // TODO(MXG): Consider checking Node names here
1348 }
1349 }
1350 }
1351
1352 // Check DegreesOfFreedom indexing
1353 for (std::size_t i = 0; i < getNumDofs(); ++i)
1354 {
1355 const DegreeOfFreedom* dof = getDof(i);
1356 if (dof->getIndexInSkeleton() != i)
1357 {
1358 dterr << "[Skeleton::checkIndexingConsistency] DegreeOfFreedom named ["
1359 << dof->getName() << "] (" << dof << ") in Skeleton [" << getName()
1360 << "] (" << this << ") is mistaken about its index "
1361 << "in its Skeleton (" << i << "|" << dof->getIndexInSkeleton()
1362 << "). Please report this as a bug!" << std::endl;
1363 consistent = false;
1364 assert(false);
1365 }
1366
1367 const DegreeOfFreedom* nameEntryForDof = getDof(dof->getName());
1368 if (nameEntryForDof != dof)
1369 {
1370 dterr << "[Skeleton::checkIndexingConsistency] Skeleton named ["
1371 << getName() << "] (" << this << ") is mistaken about the name of "
1372 << "DegreeOfFreedom [" << dof->getName() << "] (" << dof << "). "
1373 << "The name instead maps to [" << nameEntryForDof->getName()
1374 << "] (" << nameEntryForDof << "). Please report this as a bug!"
1375 << std::endl;
1376 consistent = false;
1377 assert(false);
1378 }
1379 }
1380
1381 // Check each Node in the Skeleton-scope NodeMap
1382 {
1383 const Skeleton::NodeMap& nodeMap = mNodeMap;
1384 for (const auto& nodeType : nodeMap)
1385 {
1386 const std::vector<Node*>& nodes = nodeType.second;
1387 for (std::size_t k = 0; k < nodes.size(); ++k)
1388 {
1389 const Node* node = nodes[k];
1390 if (node->getSkeleton().get() != this)
1391 {
1392 dterr << "[Skeleton::checkIndexingConsistency] Node named ["
1393 << node->getName() << "] (" << node << ") in Skeleton ["
1394 << getName() << "] (" << this << ") is mistaken about its "
1395 << "Skeleton [" << node->getSkeleton()->getName() << "] ("
1396 << node->getSkeleton() << "). Please report this as a bug!"
1397 << std::endl;
1398 consistent = false;
1399 assert(false);
1400 }
1401
1402 if (node->mIndexInSkeleton != k)
1403 {
1404 dterr << "[Skeleton::checkIndexingConsistency] Node named ["
1405 << node->getName() << "] (" << node << ") in Skeleton ["
1406 << getName() << "] (" << this << ") is mistaken about its "
1407 << "index in its Skeleton (" << k << "|"
1408 << node->mIndexInSkeleton << "). Please report this as a bug!"
1409 << std::endl;
1410 consistent = false;
1411 assert(false);
1412 }
1413 }
1414 }
1415 }
1416
1417 // Check each BodyNode in each Tree cache
1418 for (std::size_t i = 0; i < mTreeCache.size(); ++i)
1419 {
1420 const DataCache& cache = mTreeCache[i];
1421 for (std::size_t j = 0; j < cache.mBodyNodes.size(); ++j)
1422 {
1423 const BodyNode* bn = cache.mBodyNodes[j];
1424 if (bn->mTreeIndex != i)
1425 {
1426 dterr << "[Skeleton::checkIndexingConsistency] BodyNode named ["
1427 << bn->getName() << "] in Skeleton [" << getName() << "] is "
1428 << "mistaken about its tree's index (" << i << "|"
1429 << bn->mTreeIndex << "). Please report this as a bug!"
1430 << std::endl;
1431 consistent = false;
1432 assert(false);
1433 }
1434
1435 if (bn->mIndexInTree != j)
1436 {
1437 dterr << "[Skeleton::checkIndexingConsistency] BodyNode named ["
1438 << bn->getName() << "] (" << bn << ") in Skeleton [" << getName()
1439 << "] (" << this << ") is mistaken about its index "
1440 << "in the tree (" << j << "|" << bn->mIndexInTree << "). Please "
1441 << "report this as a bug!" << std::endl;
1442 consistent = false;
1443 assert(false);
1444 }
1445 }
1446
1447 for (std::size_t j = 0; j < cache.mDofs.size(); ++j)
1448 {
1449 const DegreeOfFreedom* dof = cache.mDofs[j];
1450 if (dof->getTreeIndex() != i)
1451 {
1452 dterr << "[Skeleton::checkIndexingConsistency] DegreeOfFreedom named ["
1453 << dof->getName() << "] (" << dof << ") in Skeleton ["
1454 << getName() << "] (" << this << ") is mistaken about its tree's "
1455 << "index (" << i << "|" << dof->getTreeIndex() << "). Please "
1456 << "report this as a bug!" << std::endl;
1457 consistent = false;
1458 assert(false);
1459 }
1460 }
1461 }
1462
1463 // Check that the Tree cache and the number of Tree NodeMaps match up
1464 if (mTreeCache.size() != mTreeNodeMaps.size())
1465 {
1466 consistent = false;
1467 dterr << "[Skeleton::checkIndexingConsistency] Skeleton named ["
1468 << getName() << "] (" << this << ") has inconsistent tree cache "
1469 << " and tree Node map sizes (" << mTreeCache.size() << "|"
1470 << mTreeNodeMaps.size() << "). Please report this as a bug!"
1471 << std::endl;
1472 assert(false);
1473 }
1474
1475 // Check each Node in the NodeMap of each Tree
1476 for (std::size_t i = 0; i < mTreeNodeMaps.size(); ++i)
1477 {
1478 const NodeMap& nodeMap = mTreeNodeMaps[i];
1479
1480 for (const auto& nodeType : nodeMap)
1481 {
1482 const std::vector<Node*>& nodes = nodeType.second;
1483 for (std::size_t k = 0; k < nodes.size(); ++k)
1484 {
1485 const Node* node = nodes[k];
1486 if (node->getBodyNodePtr()->mTreeIndex != i)
1487 {
1488 dterr << "[Skeleton::checkIndexingConsistency] Node named ["
1489 << node->getName() << "] (" << node << ") in Skeleton ["
1490 << getName() << "] (" << this << ") is mistaken about its "
1491 << "Tree Index (" << i << "|"
1492 << node->getBodyNodePtr()->mTreeIndex << "). Please report "
1493 << "this as a bug!" << std::endl;
1494 consistent = false;
1495 assert(false);
1496 }
1497
1498 if (node->mIndexInTree != k)
1499 {
1500 dterr << "[Skeleton::checkIndexingConsistency] Node named ["
1501 << node->getName() << "] (" << node << ") in Skeleton ["
1502 << getName() << "] (" << this << ") is mistaken about its "
1503 << "index in its tree (" << k << "|" << node->mIndexInTree
1504 << "). Please report this as a bug!" << std::endl;
1505 consistent = false;
1506 assert(false);
1507 }
1508 }
1509 }
1510 }
1511
1512 return consistent;
1513 }
1514
1515 //==============================================================================
getIK(bool _createIfNull)1516 const std::shared_ptr<WholeBodyIK>& Skeleton::getIK(bool _createIfNull)
1517 {
1518 if (nullptr == mWholeBodyIK && _createIfNull)
1519 createIK();
1520
1521 return mWholeBodyIK;
1522 }
1523
1524 //==============================================================================
getOrCreateIK()1525 const std::shared_ptr<WholeBodyIK>& Skeleton::getOrCreateIK()
1526 {
1527 return getIK(true);
1528 }
1529
1530 //==============================================================================
getIK() const1531 std::shared_ptr<const WholeBodyIK> Skeleton::getIK() const
1532 {
1533 return mWholeBodyIK;
1534 }
1535
1536 //==============================================================================
createIK()1537 const std::shared_ptr<WholeBodyIK>& Skeleton::createIK()
1538 {
1539 mWholeBodyIK = WholeBodyIK::create(mPtr.lock());
1540 return mWholeBodyIK;
1541 }
1542
1543 //==============================================================================
clearIK()1544 void Skeleton::clearIK()
1545 {
1546 mWholeBodyIK = nullptr;
1547 }
1548
1549 //==============================================================================
DART_BAKE_SPECIALIZED_NODE_SKEL_DEFINITIONS(Skeleton,Marker)1550 DART_BAKE_SPECIALIZED_NODE_SKEL_DEFINITIONS(Skeleton, Marker)
1551
1552 //==============================================================================
1553 DART_BAKE_SPECIALIZED_NODE_SKEL_DEFINITIONS(Skeleton, ShapeNode)
1554
1555 //==============================================================================
1556 DART_BAKE_SPECIALIZED_NODE_SKEL_DEFINITIONS(Skeleton, EndEffector)
1557
1558 //==============================================================================
1559 void Skeleton::integratePositions(double _dt)
1560 {
1561 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
1562 mSkelCache.mBodyNodes[i]->getParentJoint()->integratePositions(_dt);
1563
1564 for (std::size_t i = 0; i < mSoftBodyNodes.size(); ++i)
1565 {
1566 for (std::size_t j = 0; j < mSoftBodyNodes[i]->getNumPointMasses(); ++j)
1567 mSoftBodyNodes[i]->getPointMass(j)->integratePositions(_dt);
1568 }
1569 }
1570
1571 //==============================================================================
integrateVelocities(double _dt)1572 void Skeleton::integrateVelocities(double _dt)
1573 {
1574 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
1575 mSkelCache.mBodyNodes[i]->getParentJoint()->integrateVelocities(_dt);
1576
1577 for (std::size_t i = 0; i < mSoftBodyNodes.size(); ++i)
1578 {
1579 for (std::size_t j = 0; j < mSoftBodyNodes[i]->getNumPointMasses(); ++j)
1580 mSoftBodyNodes[i]->getPointMass(j)->integrateVelocities(_dt);
1581 }
1582 }
1583
1584 //==============================================================================
getPositionDifferences(const Eigen::VectorXd & _q2,const Eigen::VectorXd & _q1) const1585 Eigen::VectorXd Skeleton::getPositionDifferences(
1586 const Eigen::VectorXd& _q2, const Eigen::VectorXd& _q1) const
1587 {
1588 if (static_cast<std::size_t>(_q2.size()) != getNumDofs()
1589 || static_cast<std::size_t>(_q1.size()) != getNumDofs())
1590 {
1591 dterr << "Skeleton::getPositionsDifference: q1's size[" << _q1.size()
1592 << "] or q2's size[" << _q2.size() << "is different with the dof ["
1593 << getNumDofs() << "]." << std::endl;
1594 return Eigen::VectorXd::Zero(getNumDofs());
1595 }
1596
1597 Eigen::VectorXd dq(getNumDofs());
1598
1599 for (const auto& bodyNode : mSkelCache.mBodyNodes)
1600 {
1601 const Joint* joint = bodyNode->getParentJoint();
1602 const std::size_t dof = joint->getNumDofs();
1603
1604 if (dof)
1605 {
1606 std::size_t index = joint->getDof(0)->getIndexInSkeleton();
1607 const Eigen::VectorXd& q2Seg = _q2.segment(index, dof);
1608 const Eigen::VectorXd& q1Seg = _q1.segment(index, dof);
1609 dq.segment(index, dof) = joint->getPositionDifferences(q2Seg, q1Seg);
1610 }
1611 }
1612
1613 return dq;
1614 }
1615
1616 //==============================================================================
getVelocityDifferences(const Eigen::VectorXd & _dq2,const Eigen::VectorXd & _dq1) const1617 Eigen::VectorXd Skeleton::getVelocityDifferences(
1618 const Eigen::VectorXd& _dq2, const Eigen::VectorXd& _dq1) const
1619 {
1620 if (static_cast<std::size_t>(_dq2.size()) != getNumDofs()
1621 || static_cast<std::size_t>(_dq1.size()) != getNumDofs())
1622 {
1623 dterr << "Skeleton::getPositionsDifference: dq1's size[" << _dq1.size()
1624 << "] or dq2's size[" << _dq2.size() << "is different with the dof ["
1625 << getNumDofs() << "]." << std::endl;
1626 return Eigen::VectorXd::Zero(getNumDofs());
1627 }
1628
1629 // All the tangent spaces of Joint's configuration spaces are vector spaces.
1630 return _dq2 - _dq1;
1631 }
1632
1633 //==============================================================================
isValidBodyNode(const Skeleton * _skeleton,const JacobianNode * _node,const std::string & _fname)1634 static bool isValidBodyNode(
1635 const Skeleton* _skeleton,
1636 const JacobianNode* _node,
1637 const std::string& _fname)
1638 {
1639 if (nullptr == _node)
1640 {
1641 dtwarn << "[Skeleton::" << _fname << "] Invalid BodyNode pointer: "
1642 << "nullptr. Returning zero Jacobian.\n";
1643 assert(false);
1644 return false;
1645 }
1646
1647 // The given BodyNode should be in the Skeleton
1648 if (_node->getSkeleton().get() != _skeleton)
1649 {
1650 dtwarn << "[Skeleton::" << _fname
1651 << "] Attempting to get a Jacobian for a "
1652 "BodyNode ["
1653 << _node->getName() << "] (" << _node
1654 << ") that is not in this Skeleton [" << _skeleton->getName()
1655 << "] (" << _skeleton << "). Returning zero Jacobian.\n";
1656 assert(false);
1657 return false;
1658 }
1659
1660 return true;
1661 }
1662
1663 //==============================================================================
1664 template <typename JacobianType>
assignJacobian(JacobianType & _J,const JacobianNode * _node,const JacobianType & _JBodyNode)1665 void assignJacobian(
1666 JacobianType& _J, const JacobianNode* _node, const JacobianType& _JBodyNode)
1667 {
1668 // Assign the BodyNode's Jacobian to the result Jacobian.
1669 std::size_t localIndex = 0;
1670 const auto& indices = _node->getDependentGenCoordIndices();
1671 for (const auto& index : indices)
1672 {
1673 // Each index should be less than the number of dofs of this Skeleton.
1674 assert(index < _node->getSkeleton()->getNumDofs());
1675
1676 _J.col(index) = _JBodyNode.col(localIndex++);
1677 }
1678 }
1679
1680 //==============================================================================
1681 template <typename... Args>
variadicGetJacobian(const Skeleton * _skel,const JacobianNode * _node,Args...args)1682 math::Jacobian variadicGetJacobian(
1683 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1684 {
1685 math::Jacobian J = math::Jacobian::Zero(6, _skel->getNumDofs());
1686
1687 if (!isValidBodyNode(_skel, _node, "getJacobian"))
1688 return J;
1689
1690 const math::Jacobian JBodyNode = _node->getJacobian(args...);
1691
1692 assignJacobian<math::Jacobian>(J, _node, JBodyNode);
1693
1694 return J;
1695 }
1696
1697 //==============================================================================
getJacobian(const JacobianNode * _node) const1698 math::Jacobian Skeleton::getJacobian(const JacobianNode* _node) const
1699 {
1700 return variadicGetJacobian(this, _node);
1701 }
1702
1703 //==============================================================================
getJacobian(const JacobianNode * _node,const Frame * _inCoordinatesOf) const1704 math::Jacobian Skeleton::getJacobian(
1705 const JacobianNode* _node, const Frame* _inCoordinatesOf) const
1706 {
1707 return variadicGetJacobian(this, _node, _inCoordinatesOf);
1708 }
1709
1710 //==============================================================================
getJacobian(const JacobianNode * _node,const Eigen::Vector3d & _localOffset) const1711 math::Jacobian Skeleton::getJacobian(
1712 const JacobianNode* _node, const Eigen::Vector3d& _localOffset) const
1713 {
1714 return variadicGetJacobian(this, _node, _localOffset);
1715 }
1716
1717 //==============================================================================
getJacobian(const JacobianNode * _node,const Eigen::Vector3d & _localOffset,const Frame * _inCoordinatesOf) const1718 math::Jacobian Skeleton::getJacobian(
1719 const JacobianNode* _node,
1720 const Eigen::Vector3d& _localOffset,
1721 const Frame* _inCoordinatesOf) const
1722 {
1723 return variadicGetJacobian(this, _node, _localOffset, _inCoordinatesOf);
1724 }
1725
1726 //==============================================================================
1727 template <typename... Args>
variadicGetWorldJacobian(const Skeleton * _skel,const JacobianNode * _node,Args...args)1728 math::Jacobian variadicGetWorldJacobian(
1729 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1730 {
1731 math::Jacobian J = math::Jacobian::Zero(6, _skel->getNumDofs());
1732
1733 if (!isValidBodyNode(_skel, _node, "getWorldJacobian"))
1734 return J;
1735
1736 const math::Jacobian JBodyNode = _node->getWorldJacobian(args...);
1737
1738 assignJacobian<math::Jacobian>(J, _node, JBodyNode);
1739
1740 return J;
1741 }
1742
1743 //==============================================================================
getWorldJacobian(const JacobianNode * _node) const1744 math::Jacobian Skeleton::getWorldJacobian(const JacobianNode* _node) const
1745 {
1746 return variadicGetWorldJacobian(this, _node);
1747 }
1748
1749 //==============================================================================
getWorldJacobian(const JacobianNode * _node,const Eigen::Vector3d & _localOffset) const1750 math::Jacobian Skeleton::getWorldJacobian(
1751 const JacobianNode* _node, const Eigen::Vector3d& _localOffset) const
1752 {
1753 return variadicGetWorldJacobian(this, _node, _localOffset);
1754 }
1755
1756 //==============================================================================
1757 template <typename... Args>
variadicGetLinearJacobian(const Skeleton * _skel,const JacobianNode * _node,Args...args)1758 math::LinearJacobian variadicGetLinearJacobian(
1759 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1760 {
1761 math::LinearJacobian J = math::LinearJacobian::Zero(3, _skel->getNumDofs());
1762
1763 if (!isValidBodyNode(_skel, _node, "getLinearJacobian"))
1764 return J;
1765
1766 const math::LinearJacobian JBodyNode = _node->getLinearJacobian(args...);
1767
1768 assignJacobian<math::LinearJacobian>(J, _node, JBodyNode);
1769
1770 return J;
1771 }
1772
1773 //==============================================================================
getLinearJacobian(const JacobianNode * _node,const Frame * _inCoordinatesOf) const1774 math::LinearJacobian Skeleton::getLinearJacobian(
1775 const JacobianNode* _node, const Frame* _inCoordinatesOf) const
1776 {
1777 return variadicGetLinearJacobian(this, _node, _inCoordinatesOf);
1778 }
1779
1780 //==============================================================================
getLinearJacobian(const JacobianNode * _node,const Eigen::Vector3d & _localOffset,const Frame * _inCoordinatesOf) const1781 math::LinearJacobian Skeleton::getLinearJacobian(
1782 const JacobianNode* _node,
1783 const Eigen::Vector3d& _localOffset,
1784 const Frame* _inCoordinatesOf) const
1785 {
1786 return variadicGetLinearJacobian(this, _node, _localOffset, _inCoordinatesOf);
1787 }
1788
1789 //==============================================================================
1790 template <typename... Args>
variadicGetAngularJacobian(const Skeleton * _skel,const JacobianNode * _node,Args...args)1791 math::AngularJacobian variadicGetAngularJacobian(
1792 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1793 {
1794 math::AngularJacobian J = math::AngularJacobian::Zero(3, _skel->getNumDofs());
1795
1796 if (!isValidBodyNode(_skel, _node, "getAngularJacobian"))
1797 return J;
1798
1799 const math::AngularJacobian JBodyNode = _node->getAngularJacobian(args...);
1800
1801 assignJacobian<math::AngularJacobian>(J, _node, JBodyNode);
1802
1803 return J;
1804 }
1805
1806 //==============================================================================
getAngularJacobian(const JacobianNode * _node,const Frame * _inCoordinatesOf) const1807 math::AngularJacobian Skeleton::getAngularJacobian(
1808 const JacobianNode* _node, const Frame* _inCoordinatesOf) const
1809 {
1810 return variadicGetAngularJacobian(this, _node, _inCoordinatesOf);
1811 }
1812
1813 //==============================================================================
1814 template <typename... Args>
variadicGetJacobianSpatialDeriv(const Skeleton * _skel,const JacobianNode * _node,Args...args)1815 math::Jacobian variadicGetJacobianSpatialDeriv(
1816 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1817 {
1818 math::Jacobian dJ = math::Jacobian::Zero(6, _skel->getNumDofs());
1819
1820 if (!isValidBodyNode(_skel, _node, "getJacobianSpatialDeriv"))
1821 return dJ;
1822
1823 const math::Jacobian dJBodyNode = _node->getJacobianSpatialDeriv(args...);
1824
1825 assignJacobian<math::Jacobian>(dJ, _node, dJBodyNode);
1826
1827 return dJ;
1828 }
1829
1830 //==============================================================================
getJacobianSpatialDeriv(const JacobianNode * _node) const1831 math::Jacobian Skeleton::getJacobianSpatialDeriv(
1832 const JacobianNode* _node) const
1833 {
1834 return variadicGetJacobianSpatialDeriv(this, _node);
1835 }
1836
1837 //==============================================================================
getJacobianSpatialDeriv(const JacobianNode * _node,const Frame * _inCoordinatesOf) const1838 math::Jacobian Skeleton::getJacobianSpatialDeriv(
1839 const JacobianNode* _node, const Frame* _inCoordinatesOf) const
1840 {
1841 return variadicGetJacobianSpatialDeriv(this, _node, _inCoordinatesOf);
1842 }
1843
1844 //==============================================================================
getJacobianSpatialDeriv(const JacobianNode * _node,const Eigen::Vector3d & _localOffset) const1845 math::Jacobian Skeleton::getJacobianSpatialDeriv(
1846 const JacobianNode* _node, const Eigen::Vector3d& _localOffset) const
1847 {
1848 return variadicGetJacobianSpatialDeriv(this, _node, _localOffset);
1849 }
1850
1851 //==============================================================================
getJacobianSpatialDeriv(const JacobianNode * _node,const Eigen::Vector3d & _localOffset,const Frame * _inCoordinatesOf) const1852 math::Jacobian Skeleton::getJacobianSpatialDeriv(
1853 const JacobianNode* _node,
1854 const Eigen::Vector3d& _localOffset,
1855 const Frame* _inCoordinatesOf) const
1856 {
1857 return variadicGetJacobianSpatialDeriv(
1858 this, _node, _localOffset, _inCoordinatesOf);
1859 }
1860
1861 //==============================================================================
1862 template <typename... Args>
variadicGetJacobianClassicDeriv(const Skeleton * _skel,const JacobianNode * _node,Args...args)1863 math::Jacobian variadicGetJacobianClassicDeriv(
1864 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1865 {
1866 math::Jacobian dJ = math::Jacobian::Zero(6, _skel->getNumDofs());
1867
1868 if (!isValidBodyNode(_skel, _node, "getJacobianClassicDeriv"))
1869 return dJ;
1870
1871 const math::Jacobian dJBodyNode = _node->getJacobianClassicDeriv(args...);
1872
1873 assignJacobian<math::Jacobian>(dJ, _node, dJBodyNode);
1874
1875 return dJ;
1876 }
1877
1878 //==============================================================================
getJacobianClassicDeriv(const JacobianNode * _node) const1879 math::Jacobian Skeleton::getJacobianClassicDeriv(
1880 const JacobianNode* _node) const
1881 {
1882 return variadicGetJacobianClassicDeriv(this, _node);
1883 }
1884
1885 //==============================================================================
getJacobianClassicDeriv(const JacobianNode * _node,const Frame * _inCoordinatesOf) const1886 math::Jacobian Skeleton::getJacobianClassicDeriv(
1887 const JacobianNode* _node, const Frame* _inCoordinatesOf) const
1888 {
1889 return variadicGetJacobianClassicDeriv(this, _node, _inCoordinatesOf);
1890 }
1891
1892 //==============================================================================
getJacobianClassicDeriv(const JacobianNode * _node,const Eigen::Vector3d & _localOffset,const Frame * _inCoordinatesOf) const1893 math::Jacobian Skeleton::getJacobianClassicDeriv(
1894 const JacobianNode* _node,
1895 const Eigen::Vector3d& _localOffset,
1896 const Frame* _inCoordinatesOf) const
1897 {
1898 return variadicGetJacobianClassicDeriv(
1899 this, _node, _localOffset, _inCoordinatesOf);
1900 }
1901
1902 //==============================================================================
1903 template <typename... Args>
variadicGetLinearJacobianDeriv(const Skeleton * _skel,const JacobianNode * _node,Args...args)1904 math::LinearJacobian variadicGetLinearJacobianDeriv(
1905 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1906 {
1907 math::LinearJacobian dJv = math::LinearJacobian::Zero(3, _skel->getNumDofs());
1908
1909 if (!isValidBodyNode(_skel, _node, "getLinearJacobianDeriv"))
1910 return dJv;
1911
1912 const math::LinearJacobian dJvBodyNode
1913 = _node->getLinearJacobianDeriv(args...);
1914
1915 assignJacobian<math::LinearJacobian>(dJv, _node, dJvBodyNode);
1916
1917 return dJv;
1918 }
1919
1920 //==============================================================================
getLinearJacobianDeriv(const JacobianNode * _node,const Frame * _inCoordinatesOf) const1921 math::LinearJacobian Skeleton::getLinearJacobianDeriv(
1922 const JacobianNode* _node, const Frame* _inCoordinatesOf) const
1923 {
1924 return variadicGetLinearJacobianDeriv(this, _node, _inCoordinatesOf);
1925 }
1926
1927 //==============================================================================
getLinearJacobianDeriv(const JacobianNode * _node,const Eigen::Vector3d & _localOffset,const Frame * _inCoordinatesOf) const1928 math::LinearJacobian Skeleton::getLinearJacobianDeriv(
1929 const JacobianNode* _node,
1930 const Eigen::Vector3d& _localOffset,
1931 const Frame* _inCoordinatesOf) const
1932 {
1933 return variadicGetLinearJacobianDeriv(
1934 this, _node, _localOffset, _inCoordinatesOf);
1935 }
1936
1937 //==============================================================================
1938 template <typename... Args>
variadicGetAngularJacobianDeriv(const Skeleton * _skel,const JacobianNode * _node,Args...args)1939 math::AngularJacobian variadicGetAngularJacobianDeriv(
1940 const Skeleton* _skel, const JacobianNode* _node, Args... args)
1941 {
1942 math::AngularJacobian dJw
1943 = math::AngularJacobian::Zero(3, _skel->getNumDofs());
1944
1945 if (!isValidBodyNode(_skel, _node, "getAngularJacobianDeriv"))
1946 return dJw;
1947
1948 const math::AngularJacobian dJwBodyNode
1949 = _node->getAngularJacobianDeriv(args...);
1950
1951 assignJacobian<math::AngularJacobian>(dJw, _node, dJwBodyNode);
1952
1953 return dJw;
1954 }
1955
1956 //==============================================================================
getAngularJacobianDeriv(const JacobianNode * _node,const Frame * _inCoordinatesOf) const1957 math::AngularJacobian Skeleton::getAngularJacobianDeriv(
1958 const JacobianNode* _node, const Frame* _inCoordinatesOf) const
1959 {
1960 return variadicGetAngularJacobianDeriv(this, _node, _inCoordinatesOf);
1961 }
1962
1963 //==============================================================================
getMass() const1964 double Skeleton::getMass() const
1965 {
1966 return mTotalMass;
1967 }
1968
1969 //==============================================================================
getMassMatrix(std::size_t _treeIdx) const1970 const Eigen::MatrixXd& Skeleton::getMassMatrix(std::size_t _treeIdx) const
1971 {
1972 if (mTreeCache[_treeIdx].mDirty.mMassMatrix)
1973 updateMassMatrix(_treeIdx);
1974 return mTreeCache[_treeIdx].mM;
1975 }
1976
1977 //==============================================================================
getMassMatrix() const1978 const Eigen::MatrixXd& Skeleton::getMassMatrix() const
1979 {
1980 if (mSkelCache.mDirty.mMassMatrix)
1981 updateMassMatrix();
1982 return mSkelCache.mM;
1983 }
1984
1985 //==============================================================================
getAugMassMatrix(std::size_t _treeIdx) const1986 const Eigen::MatrixXd& Skeleton::getAugMassMatrix(std::size_t _treeIdx) const
1987 {
1988 if (mTreeCache[_treeIdx].mDirty.mAugMassMatrix)
1989 updateAugMassMatrix(_treeIdx);
1990
1991 return mTreeCache[_treeIdx].mAugM;
1992 }
1993
1994 //==============================================================================
getAugMassMatrix() const1995 const Eigen::MatrixXd& Skeleton::getAugMassMatrix() const
1996 {
1997 if (mSkelCache.mDirty.mAugMassMatrix)
1998 updateAugMassMatrix();
1999
2000 return mSkelCache.mAugM;
2001 }
2002
2003 //==============================================================================
getInvMassMatrix(std::size_t _treeIdx) const2004 const Eigen::MatrixXd& Skeleton::getInvMassMatrix(std::size_t _treeIdx) const
2005 {
2006 if (mTreeCache[_treeIdx].mDirty.mInvMassMatrix)
2007 updateInvMassMatrix(_treeIdx);
2008
2009 return mTreeCache[_treeIdx].mInvM;
2010 }
2011
2012 //==============================================================================
getInvMassMatrix() const2013 const Eigen::MatrixXd& Skeleton::getInvMassMatrix() const
2014 {
2015 if (mSkelCache.mDirty.mInvMassMatrix)
2016 updateInvMassMatrix();
2017
2018 return mSkelCache.mInvM;
2019 }
2020
2021 //==============================================================================
getInvAugMassMatrix(std::size_t _treeIdx) const2022 const Eigen::MatrixXd& Skeleton::getInvAugMassMatrix(std::size_t _treeIdx) const
2023 {
2024 if (mTreeCache[_treeIdx].mDirty.mInvAugMassMatrix)
2025 updateInvAugMassMatrix(_treeIdx);
2026
2027 return mTreeCache[_treeIdx].mInvAugM;
2028 }
2029
2030 //==============================================================================
getInvAugMassMatrix() const2031 const Eigen::MatrixXd& Skeleton::getInvAugMassMatrix() const
2032 {
2033 if (mSkelCache.mDirty.mInvAugMassMatrix)
2034 updateInvAugMassMatrix();
2035
2036 return mSkelCache.mInvAugM;
2037 }
2038
2039 //==============================================================================
getCoriolisForces(std::size_t _treeIdx) const2040 const Eigen::VectorXd& Skeleton::getCoriolisForces(std::size_t _treeIdx) const
2041 {
2042 if (mTreeCache[_treeIdx].mDirty.mCoriolisForces)
2043 updateCoriolisForces(_treeIdx);
2044
2045 return mTreeCache[_treeIdx].mCvec;
2046 }
2047
2048 //==============================================================================
getCoriolisForces() const2049 const Eigen::VectorXd& Skeleton::getCoriolisForces() const
2050 {
2051 if (mSkelCache.mDirty.mCoriolisForces)
2052 updateCoriolisForces();
2053
2054 return mSkelCache.mCvec;
2055 }
2056
2057 //==============================================================================
getGravityForces(std::size_t _treeIdx) const2058 const Eigen::VectorXd& Skeleton::getGravityForces(std::size_t _treeIdx) const
2059 {
2060 if (mTreeCache[_treeIdx].mDirty.mGravityForces)
2061 updateGravityForces(_treeIdx);
2062
2063 return mTreeCache[_treeIdx].mG;
2064 }
2065
2066 //==============================================================================
getGravityForces() const2067 const Eigen::VectorXd& Skeleton::getGravityForces() const
2068 {
2069 if (mSkelCache.mDirty.mGravityForces)
2070 updateGravityForces();
2071
2072 return mSkelCache.mG;
2073 }
2074
2075 //==============================================================================
getCoriolisAndGravityForces(std::size_t _treeIdx) const2076 const Eigen::VectorXd& Skeleton::getCoriolisAndGravityForces(
2077 std::size_t _treeIdx) const
2078 {
2079 if (mTreeCache[_treeIdx].mDirty.mCoriolisAndGravityForces)
2080 updateCoriolisAndGravityForces(_treeIdx);
2081
2082 return mTreeCache[_treeIdx].mCg;
2083 }
2084
2085 //==============================================================================
getCoriolisAndGravityForces() const2086 const Eigen::VectorXd& Skeleton::getCoriolisAndGravityForces() const
2087 {
2088 if (mSkelCache.mDirty.mCoriolisAndGravityForces)
2089 updateCoriolisAndGravityForces();
2090
2091 return mSkelCache.mCg;
2092 }
2093
2094 //==============================================================================
getExternalForces(std::size_t _treeIdx) const2095 const Eigen::VectorXd& Skeleton::getExternalForces(std::size_t _treeIdx) const
2096 {
2097 if (mTreeCache[_treeIdx].mDirty.mExternalForces)
2098 updateExternalForces(_treeIdx);
2099
2100 return mTreeCache[_treeIdx].mFext;
2101 }
2102
2103 //==============================================================================
getExternalForces() const2104 const Eigen::VectorXd& Skeleton::getExternalForces() const
2105 {
2106 if (mSkelCache.mDirty.mExternalForces)
2107 updateExternalForces();
2108
2109 return mSkelCache.mFext;
2110 }
2111
2112 //==============================================================================
getConstraintForces(std::size_t _treeIdx) const2113 const Eigen::VectorXd& Skeleton::getConstraintForces(std::size_t _treeIdx) const
2114 {
2115 return computeConstraintForces(mTreeCache[_treeIdx]);
2116 }
2117
2118 //==============================================================================
getConstraintForces() const2119 const Eigen::VectorXd& Skeleton::getConstraintForces() const
2120 {
2121 return computeConstraintForces(mSkelCache);
2122 }
2123
2124 //==============================================================================
2125 // const Eigen::VectorXd& Skeleton::getDampingForceVector() {
2126 // if (mIsDampingForceVectorDirty)
2127 // updateDampingForceVector();
2128 // return mFd;
2129 //}
2130
2131 //==============================================================================
Skeleton(const AspectPropertiesData & properties)2132 Skeleton::Skeleton(const AspectPropertiesData& properties)
2133 : mTotalMass(0.0), mIsImpulseApplied(false), mUnionSize(1)
2134 {
2135 createAspect<Aspect>(properties);
2136 createAspect<detail::BodyNodeVectorProxyAspect>();
2137 createAspect<detail::JointVectorProxyAspect>();
2138
2139 updateNameManagerNames();
2140 }
2141
2142 //==============================================================================
setPtr(const SkeletonPtr & _ptr)2143 void Skeleton::setPtr(const SkeletonPtr& _ptr)
2144 {
2145 mPtr = _ptr;
2146 resetUnion();
2147 }
2148
2149 //==============================================================================
constructNewTree()2150 void Skeleton::constructNewTree()
2151 {
2152 mTreeCache.push_back(DataCache());
2153
2154 mTreeNodeMaps.push_back(NodeMap());
2155 NodeMap& nodeMap = mTreeNodeMaps.back();
2156
2157 // Create the machinery needed to directly call on specialized node types
2158 for (auto& nodeType : mSpecializedTreeNodes)
2159 {
2160 const std::type_index& index = nodeType.first;
2161 nodeMap[index] = std::vector<Node*>();
2162
2163 std::vector<NodeMap::iterator>* nodeVec = nodeType.second;
2164 nodeVec->push_back(nodeMap.find(index));
2165
2166 assert(nodeVec->size() == mTreeCache.size());
2167 }
2168 }
2169
2170 //==============================================================================
registerBodyNode(BodyNode * _newBodyNode)2171 void Skeleton::registerBodyNode(BodyNode* _newBodyNode)
2172 {
2173 #ifndef NDEBUG // Debug mode
2174 std::vector<BodyNode*>::iterator repeat = std::find(
2175 mSkelCache.mBodyNodes.begin(), mSkelCache.mBodyNodes.end(), _newBodyNode);
2176 if (repeat != mSkelCache.mBodyNodes.end())
2177 {
2178 dterr << "[Skeleton::registerBodyNode] Attempting to double-register the "
2179 << "BodyNode named [" << _newBodyNode->getName() << "] in the "
2180 << "Skeleton named [" << getName() << "]. Please report this as a "
2181 << "bug!\n";
2182 assert(false);
2183 return;
2184 }
2185 #endif // -------- Debug mode
2186
2187 mSkelCache.mBodyNodes.push_back(_newBodyNode);
2188 if (nullptr == _newBodyNode->getParentBodyNode())
2189 {
2190 // Create a new tree and add the new BodyNode to it
2191 _newBodyNode->mIndexInTree = 0;
2192 constructNewTree();
2193 mTreeCache.back().mBodyNodes.push_back(_newBodyNode);
2194 _newBodyNode->mTreeIndex = mTreeCache.size() - 1;
2195 }
2196 else
2197 {
2198 std::size_t tree = _newBodyNode->getParentBodyNode()->getTreeIndex();
2199 _newBodyNode->mTreeIndex = tree;
2200 DataCache& cache = mTreeCache[tree];
2201 cache.mBodyNodes.push_back(_newBodyNode);
2202 _newBodyNode->mIndexInTree = cache.mBodyNodes.size() - 1;
2203 }
2204
2205 _newBodyNode->mSkeleton = getPtr();
2206 _newBodyNode->mIndexInSkeleton = mSkelCache.mBodyNodes.size() - 1;
2207 addEntryToBodyNodeNameMgr(_newBodyNode);
2208 registerJoint(_newBodyNode->getParentJoint());
2209
2210 SoftBodyNode* softBodyNode = dynamic_cast<SoftBodyNode*>(_newBodyNode);
2211 if (softBodyNode)
2212 {
2213 mSoftBodyNodes.push_back(softBodyNode);
2214 addEntryToSoftBodyNodeNameMgr(softBodyNode);
2215 }
2216
2217 _newBodyNode->init(getPtr());
2218
2219 BodyNode::NodeMap& nodeMap = _newBodyNode->mNodeMap;
2220 for (auto& nodeType : nodeMap)
2221 for (auto& node : nodeType.second)
2222 registerNode(node);
2223
2224 updateTotalMass();
2225 updateCacheDimensions(_newBodyNode->mTreeIndex);
2226
2227 #ifndef NDEBUG // Debug mode
2228 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
2229 {
2230 if (mSkelCache.mBodyNodes[i]->mIndexInSkeleton != i)
2231 {
2232 dterr << "[Skeleton::registerBodyNode] BodyNode named ["
2233 << mSkelCache.mBodyNodes[i]->getName() << "] in Skeleton ["
2234 << getName() << "] is mistaken about its index in the Skeleton ( "
2235 << i << " : " << mSkelCache.mBodyNodes[i]->mIndexInSkeleton
2236 << "). Please report this as a bug!\n";
2237 assert(false);
2238 }
2239 }
2240
2241 for (std::size_t i = 0; i < mTreeCache.size(); ++i)
2242 {
2243 const DataCache& cache = mTreeCache[i];
2244 for (std::size_t j = 0; j < cache.mBodyNodes.size(); ++j)
2245 {
2246 BodyNode* bn = cache.mBodyNodes[j];
2247 if (bn->mTreeIndex != i)
2248 {
2249 dterr << "[Skeleton::registerBodyNode] BodyNode named ["
2250 << bn->getName() << "] in Skeleton [" << getName() << "] is "
2251 << "mistaken about its tree's index (" << i << " : "
2252 << bn->mTreeIndex << "). Please report this as a bug!\n";
2253 assert(false);
2254 }
2255
2256 if (bn->mIndexInTree != j)
2257 {
2258 dterr << "[Skeleton::registerBodyNode] BodyNode named ["
2259 << bn->getName() << "] in Skeleton [" << getName() << "] is "
2260 << "mistaken about its index in the tree (" << j << " : "
2261 << bn->mIndexInTree << "). Please report this as a bug!\n";
2262 assert(false);
2263 }
2264 }
2265 }
2266 #endif // ------- Debug mode
2267
2268 _newBodyNode->incrementVersion();
2269 _newBodyNode->mStructuralChangeSignal.raise(_newBodyNode);
2270 // We don't need to explicitly increment the version of this Skeleton here
2271 // because the BodyNode will increment the version of its dependent, which is
2272 // this Skeleton.
2273 }
2274
2275 //==============================================================================
registerJoint(Joint * _newJoint)2276 void Skeleton::registerJoint(Joint* _newJoint)
2277 {
2278 if (nullptr == _newJoint)
2279 {
2280 dterr << "[Skeleton::registerJoint] Error: Attempting to add a nullptr "
2281 "Joint to the Skeleton named ["
2282 << mAspectProperties.mName
2283 << "]. Report "
2284 "this as a bug!\n";
2285 assert(false);
2286 return;
2287 }
2288
2289 addEntryToJointNameMgr(_newJoint);
2290 _newJoint->registerDofs();
2291
2292 std::size_t tree = _newJoint->getChildBodyNode()->getTreeIndex();
2293 std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
2294 for (std::size_t i = 0; i < _newJoint->getNumDofs(); ++i)
2295 {
2296 mSkelCache.mDofs.push_back(_newJoint->getDof(i));
2297 _newJoint->getDof(i)->mIndexInSkeleton = mSkelCache.mDofs.size() - 1;
2298
2299 treeDofs.push_back(_newJoint->getDof(i));
2300 _newJoint->getDof(i)->mIndexInTree = treeDofs.size() - 1;
2301 }
2302 }
2303
2304 //==============================================================================
registerNode(NodeMap & nodeMap,Node * _newNode,std::size_t & _index)2305 void Skeleton::registerNode(
2306 NodeMap& nodeMap, Node* _newNode, std::size_t& _index)
2307 {
2308 NodeMap::iterator it = nodeMap.find(typeid(*_newNode));
2309
2310 if (nodeMap.end() == it)
2311 {
2312 nodeMap[typeid(*_newNode)] = std::vector<Node*>();
2313 it = nodeMap.find(typeid(*_newNode));
2314 }
2315
2316 std::vector<Node*>& nodes = it->second;
2317
2318 if (INVALID_INDEX == _index)
2319 {
2320 // If this Node believes its index is invalid, then it should not exist
2321 // anywhere in the vector
2322 assert(std::find(nodes.begin(), nodes.end(), _newNode) == nodes.end());
2323
2324 nodes.push_back(_newNode);
2325 _index = nodes.size() - 1;
2326 }
2327
2328 assert(std::find(nodes.begin(), nodes.end(), _newNode) != nodes.end());
2329 }
2330
2331 //==============================================================================
registerNode(Node * _newNode)2332 void Skeleton::registerNode(Node* _newNode)
2333 {
2334 registerNode(mNodeMap, _newNode, _newNode->mIndexInSkeleton);
2335
2336 registerNode(
2337 mTreeNodeMaps[_newNode->getBodyNodePtr()->getTreeIndex()],
2338 _newNode,
2339 _newNode->mIndexInTree);
2340
2341 const std::type_info& info = typeid(*_newNode);
2342 NodeNameMgrMap::iterator it = mNodeNameMgrMap.find(info);
2343 if (mNodeNameMgrMap.end() == it)
2344 {
2345 mNodeNameMgrMap[info] = common::NameManager<Node*>(
2346 std::string("Skeleton::") + info.name() + " | "
2347 + mAspectProperties.mName,
2348 info.name());
2349
2350 it = mNodeNameMgrMap.find(info);
2351 }
2352
2353 common::NameManager<Node*>& mgr = it->second;
2354 _newNode->setName(mgr.issueNewNameAndAdd(_newNode->getName(), _newNode));
2355 }
2356
2357 //==============================================================================
destructOldTree(std::size_t tree)2358 void Skeleton::destructOldTree(std::size_t tree)
2359 {
2360 mTreeCache.erase(mTreeCache.begin() + tree);
2361 mTreeNodeMaps.erase(mTreeNodeMaps.begin() + tree);
2362
2363 // Decrease the tree index of every BodyNode whose tree index is higher than
2364 // the one which is being removed. None of the BodyNodes that predate the
2365 // current one can have a higher tree index, so they can be ignored.
2366 for (std::size_t i = tree; i < mTreeCache.size(); ++i)
2367 {
2368 DataCache& loweredTree = mTreeCache[i];
2369 for (std::size_t j = 0; j < loweredTree.mBodyNodes.size(); ++j)
2370 loweredTree.mBodyNodes[j]->mTreeIndex = i;
2371 }
2372
2373 for (auto& nodeType : mSpecializedTreeNodes)
2374 {
2375 std::vector<NodeMap::iterator>* nodeRepo = nodeType.second;
2376 nodeRepo->erase(nodeRepo->begin() + tree);
2377 }
2378 }
2379
2380 //==============================================================================
unregisterBodyNode(BodyNode * _oldBodyNode)2381 void Skeleton::unregisterBodyNode(BodyNode* _oldBodyNode)
2382 {
2383 unregisterJoint(_oldBodyNode->getParentJoint());
2384
2385 BodyNode::NodeMap& nodeMap = _oldBodyNode->mNodeMap;
2386 for (auto& nodeType : nodeMap)
2387 for (auto& node : nodeType.second)
2388 unregisterNode(node);
2389
2390 mNameMgrForBodyNodes.removeName(_oldBodyNode->getName());
2391
2392 std::size_t index = _oldBodyNode->getIndexInSkeleton();
2393 assert(mSkelCache.mBodyNodes[index] == _oldBodyNode);
2394 mSkelCache.mBodyNodes.erase(mSkelCache.mBodyNodes.begin() + index);
2395 for (std::size_t i = index; i < mSkelCache.mBodyNodes.size(); ++i)
2396 {
2397 BodyNode* bn = mSkelCache.mBodyNodes[i];
2398 bn->mIndexInSkeleton = i;
2399 }
2400
2401 if (nullptr == _oldBodyNode->getParentBodyNode())
2402 {
2403 // If the parent of this BodyNode is a nullptr, then this is the root of its
2404 // tree. If the root of the tree is being removed, then the tree itself
2405 // should be destroyed.
2406
2407 // There is no way that any child BodyNodes of this root BodyNode are still
2408 // registered, because the BodyNodes always get unregistered from leaf to
2409 // root.
2410
2411 std::size_t tree = _oldBodyNode->getTreeIndex();
2412 assert(mTreeCache[tree].mBodyNodes.size() == 1);
2413 assert(mTreeCache[tree].mBodyNodes[0] == _oldBodyNode);
2414
2415 destructOldTree(tree);
2416 updateCacheDimensions(mSkelCache);
2417 }
2418 else
2419 {
2420 std::size_t tree = _oldBodyNode->getTreeIndex();
2421 std::size_t indexInTree = _oldBodyNode->getIndexInTree();
2422 assert(mTreeCache[tree].mBodyNodes[indexInTree] == _oldBodyNode);
2423 mTreeCache[tree].mBodyNodes.erase(
2424 mTreeCache[tree].mBodyNodes.begin() + indexInTree);
2425
2426 for (std::size_t i = indexInTree; i < mTreeCache[tree].mBodyNodes.size();
2427 ++i)
2428 mTreeCache[tree].mBodyNodes[i]->mIndexInTree = i;
2429
2430 updateCacheDimensions(tree);
2431 }
2432
2433 SoftBodyNode* soft = dynamic_cast<SoftBodyNode*>(_oldBodyNode);
2434 if (soft)
2435 {
2436 mNameMgrForSoftBodyNodes.removeName(soft->getName());
2437
2438 mSoftBodyNodes.erase(
2439 std::remove(mSoftBodyNodes.begin(), mSoftBodyNodes.end(), soft),
2440 mSoftBodyNodes.end());
2441 }
2442
2443 updateTotalMass();
2444
2445 _oldBodyNode->incrementVersion();
2446 _oldBodyNode->mStructuralChangeSignal.raise(_oldBodyNode);
2447 // We don't need to explicitly increment the version of this Skeleton here
2448 // because the BodyNode will increment the version of its dependent, which is
2449 // this Skeleton.
2450 }
2451
2452 //==============================================================================
unregisterJoint(Joint * _oldJoint)2453 void Skeleton::unregisterJoint(Joint* _oldJoint)
2454 {
2455 if (nullptr == _oldJoint)
2456 {
2457 dterr << "[Skeleton::unregisterJoint] Attempting to unregister nullptr "
2458 << "Joint from Skeleton named [" << getName() << "]. Report this as "
2459 << "a bug!\n";
2460 assert(false);
2461 return;
2462 }
2463
2464 mNameMgrForJoints.removeName(_oldJoint->getName());
2465
2466 std::size_t tree = _oldJoint->getChildBodyNode()->getTreeIndex();
2467 std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
2468 std::vector<DegreeOfFreedom*>& skelDofs = mSkelCache.mDofs;
2469
2470 std::size_t firstSkelIndex = INVALID_INDEX;
2471 std::size_t firstTreeIndex = INVALID_INDEX;
2472 for (std::size_t i = 0; i < _oldJoint->getNumDofs(); ++i)
2473 {
2474 DegreeOfFreedom* dof = _oldJoint->getDof(i);
2475 mNameMgrForDofs.removeObject(dof);
2476
2477 firstSkelIndex = std::min(firstSkelIndex, dof->getIndexInSkeleton());
2478 skelDofs.erase(
2479 std::remove(skelDofs.begin(), skelDofs.end(), dof), skelDofs.end());
2480
2481 firstTreeIndex = std::min(firstTreeIndex, dof->getIndexInTree());
2482 treeDofs.erase(
2483 std::remove(treeDofs.begin(), treeDofs.end(), dof), treeDofs.end());
2484 }
2485
2486 for (std::size_t i = firstSkelIndex; i < skelDofs.size(); ++i)
2487 {
2488 DegreeOfFreedom* dof = skelDofs[i];
2489 dof->mIndexInSkeleton = i;
2490 }
2491
2492 for (std::size_t i = firstTreeIndex; i < treeDofs.size(); ++i)
2493 {
2494 DegreeOfFreedom* dof = treeDofs[i];
2495 dof->mIndexInTree = i;
2496 }
2497 }
2498
2499 //==============================================================================
unregisterNode(NodeMap & nodeMap,Node * _oldNode,std::size_t & _index)2500 void Skeleton::unregisterNode(
2501 NodeMap& nodeMap, Node* _oldNode, std::size_t& _index)
2502 {
2503 NodeMap::iterator it = nodeMap.find(typeid(*_oldNode));
2504
2505 if (nodeMap.end() == it)
2506 {
2507 // If the Node was not in the map, then its index should be invalid
2508 assert(INVALID_INDEX == _index);
2509 return;
2510 }
2511
2512 std::vector<Node*>& nodes = it->second;
2513
2514 // This Node's index in the vector should be referring to this Node
2515 assert(nodes[_index] == _oldNode);
2516 nodes.erase(nodes.begin() + _index);
2517
2518 _index = INVALID_INDEX;
2519 }
2520
2521 //==============================================================================
unregisterNode(Node * _oldNode)2522 void Skeleton::unregisterNode(Node* _oldNode)
2523 {
2524 const std::size_t indexInSkel = _oldNode->mIndexInSkeleton;
2525 unregisterNode(mNodeMap, _oldNode, _oldNode->mIndexInSkeleton);
2526
2527 NodeMap::iterator node_it = mNodeMap.find(typeid(*_oldNode));
2528 assert(mNodeMap.end() != node_it);
2529
2530 const std::vector<Node*>& skelNodes = node_it->second;
2531 for (std::size_t i = indexInSkel; i < skelNodes.size(); ++i)
2532 skelNodes[i]->mIndexInSkeleton = i;
2533
2534 const std::size_t indexInTree = _oldNode->mIndexInTree;
2535 const std::size_t treeIndex = _oldNode->getBodyNodePtr()->getTreeIndex();
2536 NodeMap& treeNodeMap = mTreeNodeMaps[treeIndex];
2537 unregisterNode(treeNodeMap, _oldNode, _oldNode->mIndexInTree);
2538
2539 node_it = treeNodeMap.find(typeid(*_oldNode));
2540 assert(treeNodeMap.end() != node_it);
2541
2542 const std::vector<Node*>& treeNodes = node_it->second;
2543 for (std::size_t i = indexInTree; i < treeNodes.size(); ++i)
2544 treeNodes[i]->mIndexInTree = i;
2545
2546 // Remove it from the NameManager, if a NameManager is being used for this
2547 // type.
2548 NodeNameMgrMap::iterator name_it = mNodeNameMgrMap.find(typeid(*_oldNode));
2549 if (mNodeNameMgrMap.end() != name_it)
2550 {
2551 common::NameManager<Node*>& mgr = name_it->second;
2552 mgr.removeObject(_oldNode);
2553 }
2554 }
2555
2556 //==============================================================================
moveBodyNodeTree(Joint * _parentJoint,BodyNode * _bodyNode,SkeletonPtr _newSkeleton,BodyNode * _parentNode)2557 bool Skeleton::moveBodyNodeTree(
2558 Joint* _parentJoint,
2559 BodyNode* _bodyNode,
2560 SkeletonPtr _newSkeleton,
2561 BodyNode* _parentNode)
2562 {
2563 if (nullptr == _bodyNode)
2564 {
2565 dterr << "[Skeleton::moveBodyNodeTree] Skeleton named [" << getName()
2566 << "] (" << this << ") is attempting to move a nullptr BodyNode. "
2567 << "Please report this as a bug!\n";
2568 assert(false);
2569 return false;
2570 }
2571
2572 if (this != _bodyNode->getSkeleton().get())
2573 {
2574 dterr << "[Skeleton::moveBodyNodeTree] Skeleton named [" << getName()
2575 << "] (" << this << ") is attempting to move a BodyNode named ["
2576 << _bodyNode->getName() << "] even though it belongs to another "
2577 << "Skeleton [" << _bodyNode->getSkeleton()->getName() << "] ("
2578 << _bodyNode->getSkeleton() << "). Please report this as a bug!\n";
2579 assert(false);
2580 return false;
2581 }
2582
2583 if ((nullptr == _parentJoint)
2584 && (_bodyNode->getParentBodyNode() == _parentNode)
2585 && (this == _newSkeleton.get()))
2586 {
2587 // Short-circuit if the BodyNode is already in the requested place, and its
2588 // Joint does not need to be changed
2589 return false;
2590 }
2591
2592 if (_bodyNode == _parentNode)
2593 {
2594 dterr << "[Skeleton::moveBodyNodeTree] Attempting to move BodyNode named ["
2595 << _bodyNode->getName() << "] (" << _bodyNode << ") to be its own "
2596 << "parent. This is not permitted!\n";
2597 return false;
2598 }
2599
2600 if (_parentNode && _parentNode->descendsFrom(_bodyNode))
2601 {
2602 dterr << "[Skeleton::moveBodyNodeTree] Attempting to move BodyNode named ["
2603 << _bodyNode->getName() << "] of Skeleton [" << getName() << "] ("
2604 << this << ") to be a child of BodyNode [" << _parentNode->getName()
2605 << "] in Skeleton [" << _newSkeleton->getName() << "] ("
2606 << _newSkeleton << "), but that would create a closed kinematic "
2607 << "chain, which is not permitted! Nothing will be moved.\n";
2608 return false;
2609 }
2610
2611 if (nullptr == _newSkeleton)
2612 {
2613 if (nullptr == _parentNode)
2614 {
2615 dterr << "[Skeleton::moveBodyNodeTree] Attempting to move a BodyNode "
2616 << "tree starting from [" << _bodyNode->getName() << "] in "
2617 << "Skeleton [" << getName() << "] into a nullptr Skeleton. This "
2618 << "is not permitted!\n";
2619 return false;
2620 }
2621
2622 _newSkeleton = _parentNode->getSkeleton();
2623 }
2624
2625 if (_parentNode && _newSkeleton != _parentNode->getSkeleton())
2626 {
2627 dterr << "[Skeleton::moveBodyNodeTree] Mismatch between the specified "
2628 << "Skeleton [" << _newSkeleton->getName() << "] (" << _newSkeleton
2629 << ") and the specified new parent BodyNode ["
2630 << _parentNode->getName() << "] whose actual Skeleton is named ["
2631 << _parentNode->getSkeleton()->getName() << "] ("
2632 << _parentNode->getSkeleton() << ") while attempting to move a "
2633 << "BodyNode tree starting from [" << _bodyNode->getName() << "] in "
2634 << "Skeleton [" << getName() << "] (" << this << ")\n";
2635 return false;
2636 }
2637
2638 std::vector<BodyNode*> tree = extractBodyNodeTree(_bodyNode);
2639
2640 Joint* originalParent = _bodyNode->getParentJoint();
2641 if (originalParent != _parentJoint)
2642 {
2643 _bodyNode->mParentJoint = _parentJoint;
2644 _parentJoint->mChildBodyNode = _bodyNode;
2645 delete originalParent;
2646 }
2647
2648 if (_parentNode != _bodyNode->getParentBodyNode())
2649 {
2650 _bodyNode->mParentBodyNode = _parentNode;
2651 if (_parentNode)
2652 {
2653 _parentNode->mChildBodyNodes.push_back(_bodyNode);
2654 _bodyNode->changeParentFrame(_parentNode);
2655 }
2656 else
2657 {
2658 _bodyNode->changeParentFrame(Frame::World());
2659 }
2660 }
2661 _newSkeleton->receiveBodyNodeTree(tree);
2662
2663 return true;
2664 }
2665
2666 //==============================================================================
cloneBodyNodeTree(Joint * _parentJoint,const BodyNode * _bodyNode,const SkeletonPtr & _newSkeleton,BodyNode * _parentNode,bool _recursive) const2667 std::pair<Joint*, BodyNode*> Skeleton::cloneBodyNodeTree(
2668 Joint* _parentJoint,
2669 const BodyNode* _bodyNode,
2670 const SkeletonPtr& _newSkeleton,
2671 BodyNode* _parentNode,
2672 bool _recursive) const
2673 {
2674 std::pair<Joint*, BodyNode*> root(nullptr, nullptr);
2675 std::vector<const BodyNode*> tree;
2676 if (_recursive)
2677 tree = constructBodyNodeTree(_bodyNode);
2678 else
2679 tree.push_back(_bodyNode);
2680
2681 std::map<std::string, BodyNode*> nameMap;
2682 std::vector<BodyNode*> clones;
2683 clones.reserve(tree.size());
2684
2685 for (std::size_t i = 0; i < tree.size(); ++i)
2686 {
2687 const BodyNode* original = tree[i];
2688 // If this is the root of the tree, and the user has requested a change in
2689 // its parent Joint, use the specified parent Joint instead of created a
2690 // clone
2691 Joint* joint = (i == 0 && _parentJoint != nullptr)
2692 ? _parentJoint
2693 : original->getParentJoint()->clone();
2694
2695 BodyNode* newParent
2696 = i == 0 ? _parentNode
2697 : nameMap[original->getParentBodyNode()->getName()];
2698
2699 BodyNode* clone = original->clone(newParent, joint, true);
2700 clones.push_back(clone);
2701 nameMap[clone->getName()] = clone;
2702
2703 if (0 == i)
2704 {
2705 root.first = joint;
2706 root.second = clone;
2707 }
2708 }
2709
2710 _newSkeleton->receiveBodyNodeTree(clones);
2711 return root;
2712 }
2713
2714 //==============================================================================
2715 template <typename BodyNodeT>
recursiveConstructBodyNodeTree(std::vector<BodyNodeT * > & tree,BodyNodeT * _currentBodyNode)2716 static void recursiveConstructBodyNodeTree(
2717 std::vector<BodyNodeT*>& tree, BodyNodeT* _currentBodyNode)
2718 {
2719 tree.push_back(_currentBodyNode);
2720 for (std::size_t i = 0; i < _currentBodyNode->getNumChildBodyNodes(); ++i)
2721 recursiveConstructBodyNodeTree(tree, _currentBodyNode->getChildBodyNode(i));
2722 }
2723
2724 //==============================================================================
constructBodyNodeTree(const BodyNode * _bodyNode) const2725 std::vector<const BodyNode*> Skeleton::constructBodyNodeTree(
2726 const BodyNode* _bodyNode) const
2727 {
2728 std::vector<const BodyNode*> tree;
2729 recursiveConstructBodyNodeTree<const BodyNode>(tree, _bodyNode);
2730
2731 return tree;
2732 }
2733
2734 //==============================================================================
constructBodyNodeTree(BodyNode * _bodyNode)2735 std::vector<BodyNode*> Skeleton::constructBodyNodeTree(BodyNode* _bodyNode)
2736 {
2737 std::vector<BodyNode*> tree;
2738 recursiveConstructBodyNodeTree<BodyNode>(tree, _bodyNode);
2739
2740 return tree;
2741 }
2742
2743 //==============================================================================
extractBodyNodeTree(BodyNode * _bodyNode)2744 std::vector<BodyNode*> Skeleton::extractBodyNodeTree(BodyNode* _bodyNode)
2745 {
2746 std::vector<BodyNode*> tree = constructBodyNodeTree(_bodyNode);
2747
2748 // Go backwards to minimize the number of shifts needed
2749 std::vector<BodyNode*>::reverse_iterator rit;
2750 // Go backwards to minimize the amount of element shifting in the vectors
2751 for (rit = tree.rbegin(); rit != tree.rend(); ++rit)
2752 unregisterBodyNode(*rit);
2753
2754 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
2755 mSkelCache.mBodyNodes[i]->init(getPtr());
2756
2757 return tree;
2758 }
2759
2760 //==============================================================================
receiveBodyNodeTree(const std::vector<BodyNode * > & _tree)2761 void Skeleton::receiveBodyNodeTree(const std::vector<BodyNode*>& _tree)
2762 {
2763 for (BodyNode* bn : _tree)
2764 registerBodyNode(bn);
2765 }
2766
2767 //==============================================================================
updateTotalMass()2768 void Skeleton::updateTotalMass()
2769 {
2770 mTotalMass = 0.0;
2771 for (std::size_t i = 0; i < getNumBodyNodes(); ++i)
2772 mTotalMass += getBodyNode(i)->getMass();
2773 }
2774
2775 //==============================================================================
updateCacheDimensions(Skeleton::DataCache & _cache)2776 void Skeleton::updateCacheDimensions(Skeleton::DataCache& _cache)
2777 {
2778 std::size_t dof = _cache.mDofs.size();
2779 _cache.mM = Eigen::MatrixXd::Zero(dof, dof);
2780 _cache.mAugM = Eigen::MatrixXd::Zero(dof, dof);
2781 _cache.mInvM = Eigen::MatrixXd::Zero(dof, dof);
2782 _cache.mInvAugM = Eigen::MatrixXd::Zero(dof, dof);
2783 _cache.mCvec = Eigen::VectorXd::Zero(dof);
2784 _cache.mG = Eigen::VectorXd::Zero(dof);
2785 _cache.mCg = Eigen::VectorXd::Zero(dof);
2786 _cache.mFext = Eigen::VectorXd::Zero(dof);
2787 _cache.mFc = Eigen::VectorXd::Zero(dof);
2788 }
2789
2790 //==============================================================================
updateCacheDimensions(std::size_t _treeIdx)2791 void Skeleton::updateCacheDimensions(std::size_t _treeIdx)
2792 {
2793 updateCacheDimensions(mTreeCache[_treeIdx]);
2794 updateCacheDimensions(mSkelCache);
2795
2796 dirtyArticulatedInertia(_treeIdx);
2797 }
2798
2799 //==============================================================================
updateArticulatedInertia(std::size_t _tree) const2800 void Skeleton::updateArticulatedInertia(std::size_t _tree) const
2801 {
2802 DataCache& cache = mTreeCache[_tree];
2803 for (std::vector<BodyNode*>::const_reverse_iterator it
2804 = cache.mBodyNodes.rbegin();
2805 it != cache.mBodyNodes.rend();
2806 ++it)
2807 {
2808 (*it)->updateArtInertia(mAspectProperties.mTimeStep);
2809 }
2810
2811 cache.mDirty.mArticulatedInertia = false;
2812 }
2813
2814 //==============================================================================
updateArticulatedInertia() const2815 void Skeleton::updateArticulatedInertia() const
2816 {
2817 for (std::size_t i = 0; i < mTreeCache.size(); ++i)
2818 {
2819 DataCache& cache = mTreeCache[i];
2820 if (cache.mDirty.mArticulatedInertia)
2821 updateArticulatedInertia(i);
2822 }
2823
2824 mSkelCache.mDirty.mArticulatedInertia = false;
2825 }
2826
2827 //==============================================================================
updateMassMatrix(std::size_t _treeIdx) const2828 void Skeleton::updateMassMatrix(std::size_t _treeIdx) const
2829 {
2830 DataCache& cache = mTreeCache[_treeIdx];
2831 std::size_t dof = cache.mDofs.size();
2832 assert(
2833 static_cast<std::size_t>(cache.mM.cols()) == dof
2834 && static_cast<std::size_t>(cache.mM.rows()) == dof);
2835 if (dof == 0)
2836 {
2837 cache.mDirty.mMassMatrix = false;
2838 return;
2839 }
2840
2841 cache.mM.setZero();
2842
2843 // Backup the original internal force
2844 Eigen::VectorXd originalGenAcceleration = getAccelerations();
2845
2846 // Clear out the accelerations of the dofs in this tree so that we can set
2847 // them to 1.0 one at a time to build up the mass matrix
2848 for (std::size_t i = 0; i < dof; ++i)
2849 cache.mDofs[i]->setAcceleration(0.0);
2850
2851 for (std::size_t j = 0; j < dof; ++j)
2852 {
2853 // Set the acceleration of this DOF to 1.0 while all the rest are 0.0
2854 cache.mDofs[j]->setAcceleration(1.0);
2855
2856 // Prepare cache data
2857 for (std::vector<BodyNode*>::const_iterator it = cache.mBodyNodes.begin();
2858 it != cache.mBodyNodes.end();
2859 ++it)
2860 {
2861 (*it)->updateMassMatrix();
2862 }
2863
2864 // Mass matrix
2865 for (std::vector<BodyNode*>::const_reverse_iterator it
2866 = cache.mBodyNodes.rbegin();
2867 it != cache.mBodyNodes.rend();
2868 ++it)
2869 {
2870 (*it)->aggregateMassMatrix(cache.mM, j);
2871 std::size_t localDof = (*it)->mParentJoint->getNumDofs();
2872 if (localDof > 0)
2873 {
2874 std::size_t iStart = (*it)->mParentJoint->getIndexInTree(0);
2875
2876 if (iStart + localDof < j)
2877 break;
2878 }
2879 }
2880
2881 // Set the acceleration of this DOF back to 0.0
2882 cache.mDofs[j]->setAcceleration(0.0);
2883 }
2884 cache.mM.triangularView<Eigen::StrictlyUpper>() = cache.mM.transpose();
2885
2886 // Restore the original generalized accelerations
2887 const_cast<Skeleton*>(this)->setAccelerations(originalGenAcceleration);
2888
2889 cache.mDirty.mMassMatrix = false;
2890 }
2891
2892 //==============================================================================
updateMassMatrix() const2893 void Skeleton::updateMassMatrix() const
2894 {
2895 std::size_t dof = mSkelCache.mDofs.size();
2896 assert(
2897 static_cast<std::size_t>(mSkelCache.mM.cols()) == dof
2898 && static_cast<std::size_t>(mSkelCache.mM.rows()) == dof);
2899 if (dof == 0)
2900 {
2901 mSkelCache.mDirty.mMassMatrix = false;
2902 return;
2903 }
2904
2905 mSkelCache.mM.setZero();
2906
2907 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
2908 {
2909 const Eigen::MatrixXd& treeM = getMassMatrix(tree);
2910 const std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
2911 std::size_t nTreeDofs = treeDofs.size();
2912 for (std::size_t i = 0; i < nTreeDofs; ++i)
2913 {
2914 for (std::size_t j = 0; j < nTreeDofs; ++j)
2915 {
2916 std::size_t ki = treeDofs[i]->getIndexInSkeleton();
2917 std::size_t kj = treeDofs[j]->getIndexInSkeleton();
2918
2919 mSkelCache.mM(ki, kj) = treeM(i, j);
2920 }
2921 }
2922 }
2923
2924 mSkelCache.mDirty.mMassMatrix = false;
2925 }
2926
2927 //==============================================================================
updateAugMassMatrix(std::size_t _treeIdx) const2928 void Skeleton::updateAugMassMatrix(std::size_t _treeIdx) const
2929 {
2930 DataCache& cache = mTreeCache[_treeIdx];
2931 std::size_t dof = cache.mDofs.size();
2932 assert(
2933 static_cast<std::size_t>(cache.mAugM.cols()) == dof
2934 && static_cast<std::size_t>(cache.mAugM.rows()) == dof);
2935 if (dof == 0)
2936 {
2937 cache.mDirty.mAugMassMatrix = false;
2938 return;
2939 }
2940
2941 cache.mAugM.setZero();
2942
2943 // Backup the origianl internal force
2944 Eigen::VectorXd originalGenAcceleration = getAccelerations();
2945
2946 // Clear out the accelerations of the DOFs in this tree so that we can set
2947 // them to 1.0 one at a time to build up the augmented mass matrix
2948 for (std::size_t i = 0; i < dof; ++i)
2949 cache.mDofs[i]->setAcceleration(0.0);
2950
2951 for (std::size_t j = 0; j < dof; ++j)
2952 {
2953 // Set the acceleration of this DOF to 1.0 while all the rest are 0.0
2954 cache.mDofs[j]->setAcceleration(1.0);
2955
2956 // Prepare cache data
2957 for (std::vector<BodyNode*>::const_iterator it = cache.mBodyNodes.begin();
2958 it != cache.mBodyNodes.end();
2959 ++it)
2960 {
2961 (*it)->updateMassMatrix();
2962 }
2963
2964 // Augmented Mass matrix
2965 for (std::vector<BodyNode*>::const_reverse_iterator it
2966 = cache.mBodyNodes.rbegin();
2967 it != cache.mBodyNodes.rend();
2968 ++it)
2969 {
2970 (*it)->aggregateAugMassMatrix(
2971 cache.mAugM, j, mAspectProperties.mTimeStep);
2972 std::size_t localDof = (*it)->mParentJoint->getNumDofs();
2973 if (localDof > 0)
2974 {
2975 std::size_t iStart = (*it)->mParentJoint->getIndexInTree(0);
2976
2977 if (iStart + localDof < j)
2978 break;
2979 }
2980 }
2981
2982 // Set the acceleration of this DOF back to 0.0
2983 cache.mDofs[j]->setAcceleration(0.0);
2984 }
2985 cache.mAugM.triangularView<Eigen::StrictlyUpper>() = cache.mAugM.transpose();
2986
2987 // Restore the origianl internal force
2988 const_cast<Skeleton*>(this)->setAccelerations(originalGenAcceleration);
2989
2990 cache.mDirty.mAugMassMatrix = false;
2991 }
2992
2993 //==============================================================================
updateAugMassMatrix() const2994 void Skeleton::updateAugMassMatrix() const
2995 {
2996 std::size_t dof = mSkelCache.mDofs.size();
2997 assert(
2998 static_cast<std::size_t>(mSkelCache.mAugM.cols()) == dof
2999 && static_cast<std::size_t>(mSkelCache.mAugM.rows()) == dof);
3000 if (dof == 0)
3001 {
3002 mSkelCache.mDirty.mMassMatrix = false;
3003 return;
3004 }
3005
3006 mSkelCache.mAugM.setZero();
3007
3008 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
3009 {
3010 const Eigen::MatrixXd& treeAugM = getAugMassMatrix(tree);
3011 const std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
3012 std::size_t nTreeDofs = treeDofs.size();
3013 for (std::size_t i = 0; i < nTreeDofs; ++i)
3014 {
3015 for (std::size_t j = 0; j < nTreeDofs; ++j)
3016 {
3017 std::size_t ki = treeDofs[i]->getIndexInSkeleton();
3018 std::size_t kj = treeDofs[j]->getIndexInSkeleton();
3019
3020 mSkelCache.mAugM(ki, kj) = treeAugM(i, j);
3021 }
3022 }
3023 }
3024
3025 mSkelCache.mDirty.mAugMassMatrix = false;
3026 }
3027
3028 //==============================================================================
updateInvMassMatrix(std::size_t _treeIdx) const3029 void Skeleton::updateInvMassMatrix(std::size_t _treeIdx) const
3030 {
3031 DataCache& cache = mTreeCache[_treeIdx];
3032 std::size_t dof = cache.mDofs.size();
3033 assert(
3034 static_cast<std::size_t>(cache.mInvM.cols()) == dof
3035 && static_cast<std::size_t>(cache.mInvM.rows()) == dof);
3036 if (dof == 0)
3037 {
3038 cache.mDirty.mInvMassMatrix = false;
3039 return;
3040 }
3041
3042 // We don't need to set mInvM as zero matrix as long as the below is correct
3043 // cache.mInvM.setZero();
3044
3045 // Backup the origianl internal force
3046 Eigen::VectorXd originalInternalForce = getForces();
3047
3048 // Clear out the forces of the dofs in this tree so that we can set them to
3049 // 1.0 one at a time to build up the inverse mass matrix
3050 for (std::size_t i = 0; i < dof; ++i)
3051 cache.mDofs[i]->setForce(0.0);
3052
3053 for (std::size_t j = 0; j < dof; ++j)
3054 {
3055 // Set the force of this DOF to 1.0 while all the rest are 0.0
3056 cache.mDofs[j]->setForce(1.0);
3057
3058 // Prepare cache data
3059 for (std::vector<BodyNode*>::const_reverse_iterator it
3060 = cache.mBodyNodes.rbegin();
3061 it != cache.mBodyNodes.rend();
3062 ++it)
3063 {
3064 (*it)->updateInvMassMatrix();
3065 }
3066
3067 // Inverse of mass matrix
3068 for (std::vector<BodyNode*>::const_iterator it = cache.mBodyNodes.begin();
3069 it != cache.mBodyNodes.end();
3070 ++it)
3071 {
3072 (*it)->aggregateInvMassMatrix(cache.mInvM, j);
3073 std::size_t localDof = (*it)->mParentJoint->getNumDofs();
3074 if (localDof > 0)
3075 {
3076 std::size_t iStart = (*it)->mParentJoint->getIndexInTree(0);
3077
3078 if (iStart + localDof > j)
3079 break;
3080 }
3081 }
3082
3083 // Set the force of this DOF back to 0.0
3084 cache.mDofs[j]->setForce(0.0);
3085 }
3086 cache.mInvM.triangularView<Eigen::StrictlyLower>() = cache.mInvM.transpose();
3087
3088 // Restore the original internal force
3089 const_cast<Skeleton*>(this)->setForces(originalInternalForce);
3090
3091 cache.mDirty.mInvMassMatrix = false;
3092 }
3093
3094 //==============================================================================
updateInvMassMatrix() const3095 void Skeleton::updateInvMassMatrix() const
3096 {
3097 std::size_t dof = mSkelCache.mDofs.size();
3098 assert(
3099 static_cast<std::size_t>(mSkelCache.mInvM.cols()) == dof
3100 && static_cast<std::size_t>(mSkelCache.mInvM.rows()) == dof);
3101 if (dof == 0)
3102 {
3103 mSkelCache.mDirty.mInvMassMatrix = false;
3104 return;
3105 }
3106
3107 mSkelCache.mInvM.setZero();
3108
3109 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
3110 {
3111 const Eigen::MatrixXd& treeInvM = getInvMassMatrix(tree);
3112 const std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
3113 std::size_t nTreeDofs = treeDofs.size();
3114 for (std::size_t i = 0; i < nTreeDofs; ++i)
3115 {
3116 for (std::size_t j = 0; j < nTreeDofs; ++j)
3117 {
3118 std::size_t ki = treeDofs[i]->getIndexInSkeleton();
3119 std::size_t kj = treeDofs[j]->getIndexInSkeleton();
3120
3121 mSkelCache.mInvM(ki, kj) = treeInvM(i, j);
3122 }
3123 }
3124 }
3125
3126 mSkelCache.mDirty.mInvMassMatrix = false;
3127 }
3128
3129 //==============================================================================
updateInvAugMassMatrix(std::size_t _treeIdx) const3130 void Skeleton::updateInvAugMassMatrix(std::size_t _treeIdx) const
3131 {
3132 DataCache& cache = mTreeCache[_treeIdx];
3133 std::size_t dof = cache.mDofs.size();
3134 assert(
3135 static_cast<std::size_t>(cache.mInvAugM.cols()) == dof
3136 && static_cast<std::size_t>(cache.mInvAugM.rows()) == dof);
3137 if (dof == 0)
3138 {
3139 cache.mDirty.mInvAugMassMatrix = false;
3140 return;
3141 }
3142
3143 // We don't need to set mInvM as zero matrix as long as the below is correct
3144 // mInvM.setZero();
3145
3146 // Backup the origianl internal force
3147 Eigen::VectorXd originalInternalForce = getForces();
3148
3149 // Clear out the forces of the dofs in this tree so that we can set them to
3150 // 1.0 one at a time to build up the inverse augmented mass matrix
3151 for (std::size_t i = 0; i < dof; ++i)
3152 cache.mDofs[i]->setForce(0.0);
3153
3154 for (std::size_t j = 0; j < dof; ++j)
3155 {
3156 // Set the force of this DOF to 1.0 while all the rest are 0.0
3157 cache.mDofs[j]->setForce(1.0);
3158
3159 // Prepare cache data
3160 for (std::vector<BodyNode*>::const_reverse_iterator it
3161 = cache.mBodyNodes.rbegin();
3162 it != cache.mBodyNodes.rend();
3163 ++it)
3164 {
3165 (*it)->updateInvAugMassMatrix();
3166 }
3167
3168 // Inverse of augmented mass matrix
3169 for (std::vector<BodyNode*>::const_iterator it = cache.mBodyNodes.begin();
3170 it != cache.mBodyNodes.end();
3171 ++it)
3172 {
3173 (*it)->aggregateInvAugMassMatrix(
3174 cache.mInvAugM, j, mAspectProperties.mTimeStep);
3175 std::size_t localDof = (*it)->mParentJoint->getNumDofs();
3176 if (localDof > 0)
3177 {
3178 std::size_t iStart = (*it)->mParentJoint->getIndexInTree(0);
3179
3180 if (iStart + localDof > j)
3181 break;
3182 }
3183 }
3184
3185 // Set the force of this DOF back to 0.0
3186 cache.mDofs[j]->setForce(0.0);
3187 }
3188 cache.mInvAugM.triangularView<Eigen::StrictlyLower>()
3189 = cache.mInvAugM.transpose();
3190
3191 // Restore the original internal force
3192 const_cast<Skeleton*>(this)->setForces(originalInternalForce);
3193
3194 cache.mDirty.mInvAugMassMatrix = false;
3195 }
3196
3197 //==============================================================================
updateInvAugMassMatrix() const3198 void Skeleton::updateInvAugMassMatrix() const
3199 {
3200 std::size_t dof = mSkelCache.mDofs.size();
3201 assert(
3202 static_cast<std::size_t>(mSkelCache.mInvAugM.cols()) == dof
3203 && static_cast<std::size_t>(mSkelCache.mInvAugM.rows()) == dof);
3204 if (dof == 0)
3205 {
3206 mSkelCache.mDirty.mInvAugMassMatrix = false;
3207 return;
3208 }
3209
3210 mSkelCache.mInvAugM.setZero();
3211
3212 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
3213 {
3214 const Eigen::MatrixXd& treeInvAugM = getInvAugMassMatrix(tree);
3215 const std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
3216 std::size_t nTreeDofs = treeDofs.size();
3217 for (std::size_t i = 0; i < nTreeDofs; ++i)
3218 {
3219 for (std::size_t j = 0; j < nTreeDofs; ++j)
3220 {
3221 std::size_t ki = treeDofs[i]->getIndexInSkeleton();
3222 std::size_t kj = treeDofs[j]->getIndexInSkeleton();
3223
3224 mSkelCache.mInvAugM(ki, kj) = treeInvAugM(i, j);
3225 }
3226 }
3227 }
3228
3229 mSkelCache.mDirty.mInvAugMassMatrix = false;
3230 }
3231
3232 //==============================================================================
updateCoriolisForces(std::size_t _treeIdx) const3233 void Skeleton::updateCoriolisForces(std::size_t _treeIdx) const
3234 {
3235 DataCache& cache = mTreeCache[_treeIdx];
3236 std::size_t dof = cache.mDofs.size();
3237 assert(static_cast<std::size_t>(cache.mCvec.size()) == dof);
3238 if (dof == 0)
3239 {
3240 cache.mDirty.mCoriolisForces = false;
3241 return;
3242 }
3243
3244 cache.mCvec.setZero();
3245
3246 for (std::vector<BodyNode*>::const_iterator it = cache.mBodyNodes.begin();
3247 it != cache.mBodyNodes.end();
3248 ++it)
3249 {
3250 (*it)->updateCombinedVector();
3251 }
3252
3253 for (std::vector<BodyNode*>::const_reverse_iterator it
3254 = cache.mBodyNodes.rbegin();
3255 it != cache.mBodyNodes.rend();
3256 ++it)
3257 {
3258 (*it)->aggregateCoriolisForceVector(cache.mCvec);
3259 }
3260
3261 cache.mDirty.mCoriolisForces = false;
3262 }
3263
3264 //==============================================================================
updateCoriolisForces() const3265 void Skeleton::updateCoriolisForces() const
3266 {
3267 std::size_t dof = mSkelCache.mDofs.size();
3268 assert(static_cast<std::size_t>(mSkelCache.mCvec.size()) == dof);
3269 if (dof == 0)
3270 {
3271 mSkelCache.mDirty.mCoriolisForces = false;
3272 return;
3273 }
3274
3275 mSkelCache.mCvec.setZero();
3276
3277 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
3278 {
3279 const Eigen::VectorXd& treeCvec = getCoriolisForces(tree);
3280 const std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
3281 std::size_t nTreeDofs = treeDofs.size();
3282 for (std::size_t i = 0; i < nTreeDofs; ++i)
3283 {
3284 std::size_t k = treeDofs[i]->getIndexInSkeleton();
3285 mSkelCache.mCvec[k] = treeCvec[i];
3286 }
3287 }
3288
3289 mSkelCache.mDirty.mCoriolisForces = false;
3290 }
3291
3292 //==============================================================================
updateGravityForces(std::size_t _treeIdx) const3293 void Skeleton::updateGravityForces(std::size_t _treeIdx) const
3294 {
3295 DataCache& cache = mTreeCache[_treeIdx];
3296 std::size_t dof = cache.mDofs.size();
3297 assert(static_cast<std::size_t>(cache.mG.size()) == dof);
3298 if (dof == 0)
3299 {
3300 cache.mDirty.mGravityForces = false;
3301 return;
3302 }
3303
3304 cache.mG.setZero();
3305
3306 for (std::vector<BodyNode*>::const_reverse_iterator it
3307 = cache.mBodyNodes.rbegin();
3308 it != cache.mBodyNodes.rend();
3309 ++it)
3310 {
3311 (*it)->aggregateGravityForceVector(cache.mG, mAspectProperties.mGravity);
3312 }
3313
3314 cache.mDirty.mGravityForces = false;
3315 }
3316
3317 //==============================================================================
updateGravityForces() const3318 void Skeleton::updateGravityForces() const
3319 {
3320 std::size_t dof = mSkelCache.mDofs.size();
3321 assert(static_cast<std::size_t>(mSkelCache.mG.size()) == dof);
3322 if (dof == 0)
3323 {
3324 mSkelCache.mDirty.mGravityForces = false;
3325 return;
3326 }
3327
3328 mSkelCache.mG.setZero();
3329
3330 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
3331 {
3332 const Eigen::VectorXd& treeG = getGravityForces(tree);
3333 std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
3334 std::size_t nTreeDofs = treeDofs.size();
3335 for (std::size_t i = 0; i < nTreeDofs; ++i)
3336 {
3337 std::size_t k = treeDofs[i]->getIndexInSkeleton();
3338 mSkelCache.mG[k] = treeG[i];
3339 }
3340 }
3341
3342 mSkelCache.mDirty.mGravityForces = false;
3343 }
3344
3345 //==============================================================================
updateCoriolisAndGravityForces(std::size_t _treeIdx) const3346 void Skeleton::updateCoriolisAndGravityForces(std::size_t _treeIdx) const
3347 {
3348 DataCache& cache = mTreeCache[_treeIdx];
3349 std::size_t dof = cache.mDofs.size();
3350 assert(static_cast<std::size_t>(cache.mCg.size()) == dof);
3351 if (dof == 0)
3352 {
3353 cache.mDirty.mCoriolisAndGravityForces = false;
3354 return;
3355 }
3356
3357 cache.mCg.setZero();
3358
3359 for (std::vector<BodyNode*>::const_iterator it = cache.mBodyNodes.begin();
3360 it != cache.mBodyNodes.end();
3361 ++it)
3362 {
3363 (*it)->updateCombinedVector();
3364 }
3365
3366 for (std::vector<BodyNode*>::const_reverse_iterator it
3367 = cache.mBodyNodes.rbegin();
3368 it != cache.mBodyNodes.rend();
3369 ++it)
3370 {
3371 (*it)->aggregateCombinedVector(cache.mCg, mAspectProperties.mGravity);
3372 }
3373
3374 cache.mDirty.mCoriolisAndGravityForces = false;
3375 }
3376
3377 //==============================================================================
updateCoriolisAndGravityForces() const3378 void Skeleton::updateCoriolisAndGravityForces() const
3379 {
3380 std::size_t dof = mSkelCache.mDofs.size();
3381 assert(static_cast<std::size_t>(mSkelCache.mCg.size()) == dof);
3382 if (dof == 0)
3383 {
3384 mSkelCache.mDirty.mCoriolisAndGravityForces = false;
3385 return;
3386 }
3387
3388 mSkelCache.mCg.setZero();
3389
3390 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
3391 {
3392 const Eigen::VectorXd& treeCg = getCoriolisAndGravityForces(tree);
3393 const std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
3394 std::size_t nTreeDofs = treeDofs.size();
3395 for (std::size_t i = 0; i < nTreeDofs; ++i)
3396 {
3397 std::size_t k = treeDofs[i]->getIndexInSkeleton();
3398 mSkelCache.mCg[k] = treeCg[i];
3399 }
3400 }
3401
3402 mSkelCache.mDirty.mCoriolisAndGravityForces = false;
3403 }
3404
3405 //==============================================================================
updateExternalForces(std::size_t _treeIdx) const3406 void Skeleton::updateExternalForces(std::size_t _treeIdx) const
3407 {
3408 DataCache& cache = mTreeCache[_treeIdx];
3409 std::size_t dof = cache.mDofs.size();
3410 assert(static_cast<std::size_t>(cache.mFext.size()) == dof);
3411 if (dof == 0)
3412 {
3413 cache.mDirty.mExternalForces = false;
3414 return;
3415 }
3416
3417 // Clear external force.
3418 cache.mFext.setZero();
3419
3420 for (std::vector<BodyNode*>::const_reverse_iterator itr
3421 = cache.mBodyNodes.rbegin();
3422 itr != cache.mBodyNodes.rend();
3423 ++itr)
3424 {
3425 (*itr)->aggregateExternalForces(cache.mFext);
3426 }
3427
3428 // TODO(JS): Not implemented yet
3429 // for (std::vector<SoftBodyNode*>::iterator it = mSoftBodyNodes.begin();
3430 // it != mSoftBodyNodes.end(); ++it)
3431 // {
3432 // double kv = (*it)->getVertexSpringStiffness();
3433 // double ke = (*it)->getEdgeSpringStiffness();
3434
3435 // for (int i = 0; i < (*it)->getNumPointMasses(); ++i)
3436 // {
3437 // PointMass* pm = (*it)->getPointMass(i);
3438 // int nN = pm->getNumConnectedPointMasses();
3439
3440 // // Vertex restoring force
3441 // Eigen::Vector3d Fext = -(kv + nN * ke) * pm->getPositions()
3442 // - (mTimeStep * (kv + nN*ke)) *
3443 // pm->getVelocities();
3444
3445 // // Edge restoring force
3446 // for (int j = 0; j < nN; ++j)
3447 // {
3448 // Fext += ke * (pm->getConnectedPointMass(j)->getPositions()
3449 // + mTimeStep
3450 // * pm->getConnectedPointMass(j)->getVelocities());
3451 // }
3452
3453 // // Assign
3454 // int iStart = pm->getIndexInSkeleton(0);
3455 // mFext.segment<3>(iStart) = Fext;
3456 // }
3457 // }
3458
3459 cache.mDirty.mExternalForces = false;
3460 }
3461
3462 //==============================================================================
updateExternalForces() const3463 void Skeleton::updateExternalForces() const
3464 {
3465 std::size_t dof = mSkelCache.mDofs.size();
3466 assert(static_cast<std::size_t>(mSkelCache.mFext.size()) == dof);
3467 if (dof == 0)
3468 {
3469 mSkelCache.mDirty.mExternalForces = false;
3470 return;
3471 }
3472
3473 mSkelCache.mFext.setZero();
3474
3475 for (std::size_t tree = 0; tree < mTreeCache.size(); ++tree)
3476 {
3477 const Eigen::VectorXd& treeFext = getExternalForces(tree);
3478 const std::vector<DegreeOfFreedom*>& treeDofs = mTreeCache[tree].mDofs;
3479 std::size_t nTreeDofs = treeDofs.size();
3480 for (std::size_t i = 0; i < nTreeDofs; ++i)
3481 {
3482 std::size_t k = treeDofs[i]->getIndexInSkeleton();
3483 mSkelCache.mFext[k] = treeFext[i];
3484 }
3485 }
3486
3487 mSkelCache.mDirty.mExternalForces = false;
3488 }
3489
3490 //==============================================================================
computeConstraintForces(DataCache & cache) const3491 const Eigen::VectorXd& Skeleton::computeConstraintForces(DataCache& cache) const
3492 {
3493 const std::size_t dof = cache.mDofs.size();
3494 assert(static_cast<std::size_t>(cache.mFc.size()) == dof);
3495
3496 // Body constraint impulses
3497 for (std::vector<BodyNode*>::reverse_iterator it = cache.mBodyNodes.rbegin();
3498 it != cache.mBodyNodes.rend();
3499 ++it)
3500 {
3501 (*it)->aggregateSpatialToGeneralized(
3502 cache.mFc, (*it)->getConstraintImpulse());
3503 }
3504
3505 // Joint constraint impulses
3506 for (std::size_t i = 0; i < dof; ++i)
3507 cache.mFc[i] += cache.mDofs[i]->getConstraintImpulse();
3508
3509 // Get force by dividing the impulse by the time step
3510 cache.mFc = cache.mFc / mAspectProperties.mTimeStep;
3511
3512 return cache.mFc;
3513 }
3514
3515 //==============================================================================
computeSupportPolygon(const Skeleton * skel,math::SupportPolygon & polygon,math::SupportGeometry & geometry,std::vector<std::size_t> & ee_indices,Eigen::Vector3d & axis1,Eigen::Vector3d & axis2,Eigen::Vector2d & centroid,std::size_t treeIndex)3516 static void computeSupportPolygon(
3517 const Skeleton* skel,
3518 math::SupportPolygon& polygon,
3519 math::SupportGeometry& geometry,
3520 std::vector<std::size_t>& ee_indices,
3521 Eigen::Vector3d& axis1,
3522 Eigen::Vector3d& axis2,
3523 Eigen::Vector2d& centroid,
3524 std::size_t treeIndex)
3525 {
3526 polygon.clear();
3527 geometry.clear();
3528 ee_indices.clear();
3529
3530 const Eigen::Vector3d& up = -skel->getGravity();
3531 if (up.norm() == 0.0)
3532 {
3533 dtwarn << "[computeSupportPolygon] Requesting support polygon of a "
3534 << "Skeleton with no gravity. The result will only be an empty "
3535 << "set!\n";
3536 axis1.setZero();
3537 axis2.setZero();
3538 centroid = Eigen::Vector2d::Constant(std::nan(""));
3539 return;
3540 }
3541
3542 std::vector<std::size_t> originalEE_map;
3543 originalEE_map.reserve(skel->getNumEndEffectors());
3544 for (std::size_t i = 0; i < skel->getNumEndEffectors(); ++i)
3545 {
3546 const EndEffector* ee = skel->getEndEffector(i);
3547 if (ee->getSupport() && ee->getSupport()->isActive()
3548 && (INVALID_INDEX == treeIndex || ee->getTreeIndex() == treeIndex))
3549 {
3550 const math::SupportGeometry& eeGeom = ee->getSupport()->getGeometry();
3551 for (const Eigen::Vector3d& v : eeGeom)
3552 {
3553 geometry.push_back(ee->getWorldTransform() * v);
3554 originalEE_map.push_back(ee->getIndexInSkeleton());
3555 }
3556 }
3557 }
3558
3559 axis1 = (up - Eigen::Vector3d::UnitX()).norm() > 1e-6
3560 ? Eigen::Vector3d::UnitX()
3561 : Eigen::Vector3d::UnitY();
3562
3563 axis1 = axis1 - up.dot(axis1) * up / up.dot(up);
3564 axis1.normalize();
3565
3566 axis2 = up.normalized().cross(axis1);
3567
3568 std::vector<std::size_t> vertex_indices;
3569 polygon = math::computeSupportPolgyon(vertex_indices, geometry, axis1, axis2);
3570
3571 ee_indices.reserve(vertex_indices.size());
3572 for (std::size_t i = 0; i < vertex_indices.size(); ++i)
3573 ee_indices[i] = originalEE_map[vertex_indices[i]];
3574
3575 if (polygon.size() > 0)
3576 centroid = math::computeCentroidOfHull(polygon);
3577 else
3578 centroid = Eigen::Vector2d::Constant(std::nan(""));
3579 }
3580
3581 //==============================================================================
getSupportPolygon() const3582 const math::SupportPolygon& Skeleton::getSupportPolygon() const
3583 {
3584 math::SupportPolygon& polygon = mSkelCache.mSupportPolygon;
3585
3586 if (!mSkelCache.mDirty.mSupport)
3587 return polygon;
3588
3589 computeSupportPolygon(
3590 this,
3591 polygon,
3592 mSkelCache.mSupportGeometry,
3593 mSkelCache.mSupportIndices,
3594 mSkelCache.mSupportAxes.first,
3595 mSkelCache.mSupportAxes.second,
3596 mSkelCache.mSupportCentroid,
3597 INVALID_INDEX);
3598
3599 mSkelCache.mDirty.mSupport = false;
3600 ++mSkelCache.mDirty.mSupportVersion;
3601 return polygon;
3602 }
3603
3604 //==============================================================================
getSupportPolygon(std::size_t _treeIdx) const3605 const math::SupportPolygon& Skeleton::getSupportPolygon(
3606 std::size_t _treeIdx) const
3607 {
3608 math::SupportPolygon& polygon = mTreeCache[_treeIdx].mSupportPolygon;
3609
3610 if (!mTreeCache[_treeIdx].mDirty.mSupport)
3611 return polygon;
3612
3613 computeSupportPolygon(
3614 this,
3615 polygon,
3616 mTreeCache[_treeIdx].mSupportGeometry,
3617 mTreeCache[_treeIdx].mSupportIndices,
3618 mTreeCache[_treeIdx].mSupportAxes.first,
3619 mTreeCache[_treeIdx].mSupportAxes.second,
3620 mTreeCache[_treeIdx].mSupportCentroid,
3621 _treeIdx);
3622
3623 mTreeCache[_treeIdx].mDirty.mSupport = false;
3624 ++mTreeCache[_treeIdx].mDirty.mSupportVersion;
3625 return polygon;
3626 }
3627
3628 //==============================================================================
getSupportIndices() const3629 const std::vector<std::size_t>& Skeleton::getSupportIndices() const
3630 {
3631 getSupportPolygon();
3632 return mSkelCache.mSupportIndices;
3633 }
3634
3635 //==============================================================================
getSupportIndices(std::size_t _treeIdx) const3636 const std::vector<std::size_t>& Skeleton::getSupportIndices(
3637 std::size_t _treeIdx) const
3638 {
3639 getSupportPolygon(_treeIdx);
3640 return mTreeCache[_treeIdx].mSupportIndices;
3641 }
3642
3643 //==============================================================================
getSupportAxes() const3644 const std::pair<Eigen::Vector3d, Eigen::Vector3d>& Skeleton::getSupportAxes()
3645 const
3646 {
3647 getSupportPolygon();
3648 return mSkelCache.mSupportAxes;
3649 }
3650
3651 //==============================================================================
getSupportAxes(std::size_t _treeIdx) const3652 const std::pair<Eigen::Vector3d, Eigen::Vector3d>& Skeleton::getSupportAxes(
3653 std::size_t _treeIdx) const
3654 {
3655 getSupportPolygon(_treeIdx);
3656 return mTreeCache[_treeIdx].mSupportAxes;
3657 }
3658
3659 //==============================================================================
getSupportCentroid() const3660 const Eigen::Vector2d& Skeleton::getSupportCentroid() const
3661 {
3662 getSupportPolygon();
3663 return mSkelCache.mSupportCentroid;
3664 }
3665
3666 //==============================================================================
getSupportCentroid(std::size_t _treeIdx) const3667 const Eigen::Vector2d& Skeleton::getSupportCentroid(std::size_t _treeIdx) const
3668 {
3669 getSupportPolygon(_treeIdx);
3670 return mTreeCache[_treeIdx].mSupportCentroid;
3671 }
3672
3673 //==============================================================================
getSupportVersion() const3674 std::size_t Skeleton::getSupportVersion() const
3675 {
3676 if (mSkelCache.mDirty.mSupport)
3677 return mSkelCache.mDirty.mSupportVersion + 1;
3678
3679 return mSkelCache.mDirty.mSupportVersion;
3680 }
3681
3682 //==============================================================================
getSupportVersion(std::size_t _treeIdx) const3683 std::size_t Skeleton::getSupportVersion(std::size_t _treeIdx) const
3684 {
3685 if (mTreeCache[_treeIdx].mDirty.mSupport)
3686 return mTreeCache[_treeIdx].mDirty.mSupportVersion + 1;
3687
3688 return mTreeCache[_treeIdx].mDirty.mSupportVersion;
3689 }
3690
3691 //==============================================================================
computeForwardKinematics(bool _updateTransforms,bool _updateVels,bool _updateAccs)3692 void Skeleton::computeForwardKinematics(
3693 bool _updateTransforms, bool _updateVels, bool _updateAccs)
3694 {
3695 if (_updateTransforms)
3696 {
3697 for (std::vector<BodyNode*>::iterator it = mSkelCache.mBodyNodes.begin();
3698 it != mSkelCache.mBodyNodes.end();
3699 ++it)
3700 {
3701 (*it)->updateTransform();
3702 }
3703 }
3704
3705 if (_updateVels)
3706 {
3707 for (std::vector<BodyNode*>::iterator it = mSkelCache.mBodyNodes.begin();
3708 it != mSkelCache.mBodyNodes.end();
3709 ++it)
3710 {
3711 (*it)->updateVelocity();
3712 (*it)->updatePartialAcceleration();
3713 }
3714 }
3715
3716 if (_updateAccs)
3717 {
3718 for (std::vector<BodyNode*>::iterator it = mSkelCache.mBodyNodes.begin();
3719 it != mSkelCache.mBodyNodes.end();
3720 ++it)
3721 {
3722 (*it)->updateAccelerationID();
3723 }
3724 }
3725 }
3726
3727 //==============================================================================
computeForwardDynamics()3728 void Skeleton::computeForwardDynamics()
3729 {
3730 // Note: Articulated Inertias will be updated automatically when
3731 // getArtInertiaImplicit() is called in BodyNode::updateBiasForce()
3732
3733 for (auto it = mSkelCache.mBodyNodes.rbegin();
3734 it != mSkelCache.mBodyNodes.rend();
3735 ++it)
3736 (*it)->updateBiasForce(
3737 mAspectProperties.mGravity, mAspectProperties.mTimeStep);
3738
3739 // Forward recursion
3740 for (auto& bodyNode : mSkelCache.mBodyNodes)
3741 {
3742 bodyNode->updateAccelerationFD();
3743 bodyNode->updateTransmittedForceFD();
3744 bodyNode->updateJointForceFD(mAspectProperties.mTimeStep, true, true);
3745 }
3746 }
3747
3748 //==============================================================================
computeInverseDynamics(bool _withExternalForces,bool _withDampingForces,bool _withSpringForces)3749 void Skeleton::computeInverseDynamics(
3750 bool _withExternalForces, bool _withDampingForces, bool _withSpringForces)
3751 {
3752 // Skip immobile or 0-dof skeleton
3753 if (getNumDofs() == 0)
3754 return;
3755
3756 // Backward recursion
3757 for (auto it = mSkelCache.mBodyNodes.rbegin();
3758 it != mSkelCache.mBodyNodes.rend();
3759 ++it)
3760 {
3761 (*it)->updateTransmittedForceID(
3762 mAspectProperties.mGravity, _withExternalForces);
3763 (*it)->updateJointForceID(
3764 mAspectProperties.mTimeStep, _withDampingForces, _withSpringForces);
3765 }
3766 }
3767
3768 //==============================================================================
clearExternalForces()3769 void Skeleton::clearExternalForces()
3770 {
3771 for (auto& bodyNode : mSkelCache.mBodyNodes)
3772 bodyNode->clearExternalForces();
3773 }
3774
3775 //==============================================================================
clearInternalForces()3776 void Skeleton::clearInternalForces()
3777 {
3778 for (auto& bodyNode : mSkelCache.mBodyNodes)
3779 bodyNode->clearInternalForces();
3780 }
3781
3782 //==============================================================================
notifyArticulatedInertiaUpdate(std::size_t _treeIdx)3783 void Skeleton::notifyArticulatedInertiaUpdate(std::size_t _treeIdx)
3784 {
3785 dirtyArticulatedInertia(_treeIdx);
3786 }
3787
3788 //==============================================================================
dirtyArticulatedInertia(std::size_t _treeIdx)3789 void Skeleton::dirtyArticulatedInertia(std::size_t _treeIdx)
3790 {
3791 SET_FLAG(_treeIdx, mArticulatedInertia);
3792 SET_FLAG(_treeIdx, mMassMatrix);
3793 SET_FLAG(_treeIdx, mAugMassMatrix);
3794 SET_FLAG(_treeIdx, mInvMassMatrix);
3795 SET_FLAG(_treeIdx, mInvAugMassMatrix);
3796 SET_FLAG(_treeIdx, mCoriolisForces);
3797 SET_FLAG(_treeIdx, mGravityForces);
3798 SET_FLAG(_treeIdx, mCoriolisAndGravityForces);
3799 }
3800
3801 //==============================================================================
notifySupportUpdate(std::size_t _treeIdx)3802 void Skeleton::notifySupportUpdate(std::size_t _treeIdx)
3803 {
3804 dirtySupportPolygon(_treeIdx);
3805 }
3806
3807 //==============================================================================
dirtySupportPolygon(std::size_t _treeIdx)3808 void Skeleton::dirtySupportPolygon(std::size_t _treeIdx)
3809 {
3810 SET_FLAG(_treeIdx, mSupport);
3811 }
3812
3813 //==============================================================================
clearConstraintImpulses()3814 void Skeleton::clearConstraintImpulses()
3815 {
3816 for (auto& bodyNode : mSkelCache.mBodyNodes)
3817 bodyNode->clearConstraintImpulse();
3818 }
3819
3820 //==============================================================================
updateBiasImpulse(BodyNode * _bodyNode)3821 void Skeleton::updateBiasImpulse(BodyNode* _bodyNode)
3822 {
3823 if (nullptr == _bodyNode)
3824 {
3825 dterr << "[Skeleton::updateBiasImpulse] Passed in a nullptr!\n";
3826 assert(false);
3827 return;
3828 }
3829
3830 assert(getNumDofs() > 0);
3831
3832 // This skeleton should contain _bodyNode
3833 assert(_bodyNode->getSkeleton().get() == this);
3834
3835 #ifndef NDEBUG
3836 // All the constraint impulse should be zero
3837 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
3838 assert(
3839 mSkelCache.mBodyNodes[i]->mConstraintImpulse
3840 == Eigen::Vector6d::Zero());
3841 #endif
3842
3843 // Prepare cache data
3844 BodyNode* it = _bodyNode;
3845 while (it != nullptr)
3846 {
3847 it->updateBiasImpulse();
3848 it = it->getParentBodyNode();
3849 }
3850 }
3851
3852 //==============================================================================
updateBiasImpulse(BodyNode * _bodyNode,const Eigen::Vector6d & _imp)3853 void Skeleton::updateBiasImpulse(
3854 BodyNode* _bodyNode, const Eigen::Vector6d& _imp)
3855 {
3856 if (nullptr == _bodyNode)
3857 {
3858 dterr << "[Skeleton::updateBiasImpulse] Passed in a nullptr!\n";
3859 assert(false);
3860 return;
3861 }
3862
3863 assert(getNumDofs() > 0);
3864
3865 // This skeleton should contain _bodyNode
3866 assert(_bodyNode->getSkeleton().get() == this);
3867
3868 #ifndef NDEBUG
3869 // All the constraint impulse should be zero
3870 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
3871 assert(
3872 mSkelCache.mBodyNodes[i]->mConstraintImpulse
3873 == Eigen::Vector6d::Zero());
3874 #endif
3875
3876 // Set impulse of _bodyNode
3877 _bodyNode->mConstraintImpulse = _imp;
3878
3879 // Prepare cache data
3880 BodyNode* it = _bodyNode;
3881 while (it != nullptr)
3882 {
3883 it->updateBiasImpulse();
3884 it = it->getParentBodyNode();
3885 }
3886
3887 _bodyNode->mConstraintImpulse.setZero();
3888 }
3889
3890 //==============================================================================
updateBiasImpulse(BodyNode * _bodyNode1,const Eigen::Vector6d & _imp1,BodyNode * _bodyNode2,const Eigen::Vector6d & _imp2)3891 void Skeleton::updateBiasImpulse(
3892 BodyNode* _bodyNode1,
3893 const Eigen::Vector6d& _imp1,
3894 BodyNode* _bodyNode2,
3895 const Eigen::Vector6d& _imp2)
3896 {
3897 // Assertions
3898 if (nullptr == _bodyNode1)
3899 {
3900 dterr << "[Skeleton::updateBiasImpulse] Passed in nullptr for BodyNode1!\n";
3901 assert(false);
3902 return;
3903 }
3904
3905 if (nullptr == _bodyNode2)
3906 {
3907 dterr << "[Skeleton::updateBiasImpulse] Passed in nullptr for BodyNode2!\n";
3908 assert(false);
3909 return;
3910 }
3911
3912 assert(getNumDofs() > 0);
3913
3914 // This skeleton should contain _bodyNode
3915 assert(_bodyNode1->getSkeleton().get() == this);
3916 assert(_bodyNode2->getSkeleton().get() == this);
3917
3918 #ifndef NDEBUG
3919 // All the constraint impulse should be zero
3920 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
3921 assert(
3922 mSkelCache.mBodyNodes[i]->mConstraintImpulse
3923 == Eigen::Vector6d::Zero());
3924 #endif
3925
3926 // Set impulse to _bodyNode
3927 _bodyNode1->mConstraintImpulse = _imp1;
3928 _bodyNode2->mConstraintImpulse = _imp2;
3929
3930 // Find which body is placed later in the list of body nodes in this skeleton
3931 std::size_t index1 = _bodyNode1->getIndexInSkeleton();
3932 std::size_t index2 = _bodyNode2->getIndexInSkeleton();
3933
3934 std::size_t index = std::max(index1, index2);
3935
3936 // Prepare cache data
3937 for (int i = index; 0 <= i; --i)
3938 mSkelCache.mBodyNodes[i]->updateBiasImpulse();
3939
3940 _bodyNode1->mConstraintImpulse.setZero();
3941 _bodyNode2->mConstraintImpulse.setZero();
3942 }
3943
3944 //==============================================================================
updateBiasImpulse(SoftBodyNode * _softBodyNode,PointMass * _pointMass,const Eigen::Vector3d & _imp)3945 void Skeleton::updateBiasImpulse(
3946 SoftBodyNode* _softBodyNode,
3947 PointMass* _pointMass,
3948 const Eigen::Vector3d& _imp)
3949 {
3950 // Assertions
3951 assert(_softBodyNode != nullptr);
3952 assert(getNumDofs() > 0);
3953
3954 // This skeleton should contain _bodyNode
3955 assert(
3956 std::find(mSoftBodyNodes.begin(), mSoftBodyNodes.end(), _softBodyNode)
3957 != mSoftBodyNodes.end());
3958
3959 #ifndef NDEBUG
3960 // All the constraint impulse should be zero
3961 for (std::size_t i = 0; i < mSkelCache.mBodyNodes.size(); ++i)
3962 assert(
3963 mSkelCache.mBodyNodes[i]->mConstraintImpulse
3964 == Eigen::Vector6d::Zero());
3965 #endif
3966
3967 // Set impulse to _bodyNode
3968 Eigen::Vector3d oldConstraintImpulse = _pointMass->getConstraintImpulses();
3969 _pointMass->setConstraintImpulse(_imp, true);
3970
3971 // Prepare cache data
3972 BodyNode* it = _softBodyNode;
3973 while (it != nullptr)
3974 {
3975 it->updateBiasImpulse();
3976 it = it->getParentBodyNode();
3977 }
3978
3979 // TODO(JS): Do we need to backup and restore the original value?
3980 _pointMass->setConstraintImpulse(oldConstraintImpulse);
3981 }
3982
3983 //==============================================================================
updateVelocityChange()3984 void Skeleton::updateVelocityChange()
3985 {
3986 for (auto& bodyNode : mSkelCache.mBodyNodes)
3987 bodyNode->updateVelocityChangeFD();
3988 }
3989
3990 //==============================================================================
setImpulseApplied(bool _val)3991 void Skeleton::setImpulseApplied(bool _val)
3992 {
3993 mIsImpulseApplied = _val;
3994 }
3995
3996 //==============================================================================
isImpulseApplied() const3997 bool Skeleton::isImpulseApplied() const
3998 {
3999 return mIsImpulseApplied;
4000 }
4001
4002 //==============================================================================
computeImpulseForwardDynamics()4003 void Skeleton::computeImpulseForwardDynamics()
4004 {
4005 // Skip immobile or 0-dof skeleton
4006 if (!isMobile() || getNumDofs() == 0)
4007 return;
4008
4009 // Note: we do not need to update articulated inertias here, because they will
4010 // be updated when BodyNode::updateBiasImpulse() calls
4011 // BodyNode::getArticulatedInertia()
4012
4013 // Backward recursion
4014 for (auto it = mSkelCache.mBodyNodes.rbegin();
4015 it != mSkelCache.mBodyNodes.rend();
4016 ++it)
4017 (*it)->updateBiasImpulse();
4018
4019 // Forward recursion
4020 for (auto& bodyNode : mSkelCache.mBodyNodes)
4021 {
4022 bodyNode->updateVelocityChangeFD();
4023 bodyNode->updateTransmittedImpulse();
4024 bodyNode->updateJointImpulseFD();
4025 bodyNode->updateConstrainedTerms(mAspectProperties.mTimeStep);
4026 }
4027 }
4028
4029 //==============================================================================
computeKineticEnergy() const4030 double Skeleton::computeKineticEnergy() const
4031 {
4032 double KE = 0.0;
4033
4034 for (auto* bodyNode : mSkelCache.mBodyNodes)
4035 KE += bodyNode->computeKineticEnergy();
4036
4037 assert(KE >= 0.0 && "Kinetic energy should be positive value.");
4038 return KE;
4039 }
4040
4041 //==============================================================================
computePotentialEnergy() const4042 double Skeleton::computePotentialEnergy() const
4043 {
4044 double PE = 0.0;
4045
4046 for (auto* bodyNode : mSkelCache.mBodyNodes)
4047 {
4048 PE += bodyNode->computePotentialEnergy(mAspectProperties.mGravity);
4049 PE += bodyNode->getParentJoint()->computePotentialEnergy();
4050 }
4051
4052 return PE;
4053 }
4054
4055 //==============================================================================
clearCollidingBodies()4056 void Skeleton::clearCollidingBodies()
4057 {
4058 for (auto i = 0u; i < getNumBodyNodes(); ++i)
4059 {
4060 auto bodyNode = getBodyNode(i);
4061 DART_SUPPRESS_DEPRECATED_BEGIN
4062 bodyNode->setColliding(false);
4063 DART_SUPPRESS_DEPRECATED_END
4064
4065 auto softBodyNode = bodyNode->asSoftBodyNode();
4066 if (softBodyNode)
4067 {
4068 auto& pointMasses = softBodyNode->getPointMasses();
4069
4070 for (auto pointMass : pointMasses)
4071 pointMass->setColliding(false);
4072 }
4073 }
4074 }
4075
4076 //==============================================================================
getCOM(const Frame * _withRespectTo) const4077 Eigen::Vector3d Skeleton::getCOM(const Frame* _withRespectTo) const
4078 {
4079 Eigen::Vector3d com = Eigen::Vector3d::Zero();
4080
4081 const std::size_t numBodies = getNumBodyNodes();
4082 for (std::size_t i = 0; i < numBodies; ++i)
4083 {
4084 const BodyNode* bodyNode = getBodyNode(i);
4085 com += bodyNode->getMass() * bodyNode->getCOM(_withRespectTo);
4086 }
4087
4088 assert(mTotalMass != 0.0);
4089 return com / mTotalMass;
4090 }
4091
4092 //==============================================================================
4093 // Templated function for computing different kinds of COM properties, like
4094 // velocities and accelerations
4095 template <
4096 typename PropertyType,
4097 PropertyType (BodyNode::*getPropertyFn)(const Frame*, const Frame*) const>
4098 PropertyType getCOMPropertyTemplate(
4099 const Skeleton* _skel,
4100 const Frame* _relativeTo,
4101 const Frame* _inCoordinatesOf)
4102 {
4103 PropertyType result(PropertyType::Zero());
4104
4105 const std::size_t numBodies = _skel->getNumBodyNodes();
4106 for (std::size_t i = 0; i < numBodies; ++i)
4107 {
4108 const BodyNode* bodyNode = _skel->getBodyNode(i);
4109 result += bodyNode->getMass()
4110 * (bodyNode->*getPropertyFn)(_relativeTo, _inCoordinatesOf);
4111 }
4112
4113 assert(_skel->getMass() != 0.0);
4114 return result / _skel->getMass();
4115 }
4116
4117 //==============================================================================
getCOMSpatialVelocity(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const4118 Eigen::Vector6d Skeleton::getCOMSpatialVelocity(
4119 const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
4120 {
4121 return getCOMPropertyTemplate<
4122 Eigen::Vector6d,
4123 &BodyNode::getCOMSpatialVelocity>(this, _relativeTo, _inCoordinatesOf);
4124 }
4125
4126 //==============================================================================
getCOMLinearVelocity(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const4127 Eigen::Vector3d Skeleton::getCOMLinearVelocity(
4128 const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
4129 {
4130 return getCOMPropertyTemplate<
4131 Eigen::Vector3d,
4132 &BodyNode::getCOMLinearVelocity>(this, _relativeTo, _inCoordinatesOf);
4133 }
4134
4135 //==============================================================================
getCOMSpatialAcceleration(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const4136 Eigen::Vector6d Skeleton::getCOMSpatialAcceleration(
4137 const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
4138 {
4139 return getCOMPropertyTemplate<
4140 Eigen::Vector6d,
4141 &BodyNode::getCOMSpatialAcceleration>(
4142 this, _relativeTo, _inCoordinatesOf);
4143 }
4144
4145 //==============================================================================
getCOMLinearAcceleration(const Frame * _relativeTo,const Frame * _inCoordinatesOf) const4146 Eigen::Vector3d Skeleton::getCOMLinearAcceleration(
4147 const Frame* _relativeTo, const Frame* _inCoordinatesOf) const
4148 {
4149 return getCOMPropertyTemplate<
4150 Eigen::Vector3d,
4151 &BodyNode::getCOMLinearAcceleration>(this, _relativeTo, _inCoordinatesOf);
4152 }
4153
4154 //==============================================================================
4155 // Templated function for computing different kinds of COM Jacobians and their
4156 // derivatives
4157 template <
4158 typename JacType, // JacType is the type of Jacobian we're computing
4159 JacType (TemplatedJacobianNode<BodyNode>::*getJacFn)(
4160 const Eigen::Vector3d&, const Frame*) const>
4161 JacType getCOMJacobianTemplate(
4162 const Skeleton* _skel, const Frame* _inCoordinatesOf)
4163 {
4164 // Initialize the Jacobian to zero
4165 JacType J = JacType::Zero(JacType::RowsAtCompileTime, _skel->getNumDofs());
4166
4167 // Iterate through each of the Skeleton's BodyNodes
4168 const std::size_t numBodies = _skel->getNumBodyNodes();
4169 for (std::size_t i = 0; i < numBodies; ++i)
4170 {
4171 const BodyNode* bn = _skel->getBodyNode(i);
4172
4173 // (bn->*getJacFn) is a function pointer to the function that gives us the
4174 // kind of Jacobian we want from the BodyNodes. Calling it will give us the
4175 // relevant Jacobian for this BodyNode
4176 JacType bnJ
4177 = bn->getMass() * (bn->*getJacFn)(bn->getLocalCOM(), _inCoordinatesOf);
4178
4179 // For each column in the Jacobian of this BodyNode, we add it to the
4180 // appropriate column of the overall BodyNode
4181 for (std::size_t j = 0, end = bn->getNumDependentGenCoords(); j < end; ++j)
4182 {
4183 std::size_t idx = bn->getDependentGenCoordIndex(j);
4184 J.col(idx) += bnJ.col(j);
4185 }
4186 }
4187
4188 assert(_skel->getMass() != 0.0);
4189 return J / _skel->getMass();
4190 }
4191
4192 //==============================================================================
getCOMJacobian(const Frame * _inCoordinatesOf) const4193 math::Jacobian Skeleton::getCOMJacobian(const Frame* _inCoordinatesOf) const
4194 {
4195 return getCOMJacobianTemplate<
4196 math::Jacobian,
4197 &TemplatedJacobianNode<BodyNode>::getJacobian>(this, _inCoordinatesOf);
4198 }
4199
4200 //==============================================================================
getCOMLinearJacobian(const Frame * _inCoordinatesOf) const4201 math::LinearJacobian Skeleton::getCOMLinearJacobian(
4202 const Frame* _inCoordinatesOf) const
4203 {
4204 return getCOMJacobianTemplate<
4205 math::LinearJacobian,
4206 &TemplatedJacobianNode<BodyNode>::getLinearJacobian>(
4207 this, _inCoordinatesOf);
4208 }
4209
4210 //==============================================================================
getCOMJacobianSpatialDeriv(const Frame * _inCoordinatesOf) const4211 math::Jacobian Skeleton::getCOMJacobianSpatialDeriv(
4212 const Frame* _inCoordinatesOf) const
4213 {
4214 return getCOMJacobianTemplate<
4215 math::Jacobian,
4216 &TemplatedJacobianNode<BodyNode>::getJacobianSpatialDeriv>(
4217 this, _inCoordinatesOf);
4218 }
4219
4220 //==============================================================================
getCOMLinearJacobianDeriv(const Frame * _inCoordinatesOf) const4221 math::LinearJacobian Skeleton::getCOMLinearJacobianDeriv(
4222 const Frame* _inCoordinatesOf) const
4223 {
4224 return getCOMJacobianTemplate<
4225 math::LinearJacobian,
4226 &TemplatedJacobianNode<BodyNode>::getLinearJacobianDeriv>(
4227 this, _inCoordinatesOf);
4228 }
4229
4230 //==============================================================================
DirtyFlags()4231 Skeleton::DirtyFlags::DirtyFlags()
4232 : mArticulatedInertia(true),
4233 mMassMatrix(true),
4234 mAugMassMatrix(true),
4235 mInvMassMatrix(true),
4236 mInvAugMassMatrix(true),
4237 mGravityForces(true),
4238 mCoriolisForces(true),
4239 mCoriolisAndGravityForces(true),
4240 mExternalForces(true),
4241 mDampingForces(true),
4242 mSupport(true),
4243 mSupportVersion(0)
4244 {
4245 // Do nothing
4246 }
4247
4248 } // namespace dynamics
4249 } // namespace dart
4250