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/PointMass.hpp"
34 
35 #include "dart/common/Console.hpp"
36 #include "dart/dynamics/EllipsoidShape.hpp"
37 #include "dart/dynamics/SoftBodyNode.hpp"
38 #include "dart/math/Geometry.hpp"
39 #include "dart/math/Helpers.hpp"
40 
41 using namespace Eigen;
42 
43 namespace dart {
44 namespace dynamics {
45 
46 #define RETURN_FALSE_IF_OTHER_IS_EQUAL(X)                                      \
47   if (other.X != X)                                                            \
48     return false;
49 
50 //==============================================================================
State(const Vector3d & positions,const Vector3d & velocities,const Vector3d & accelerations,const Vector3d & forces)51 PointMass::State::State(
52     const Vector3d& positions,
53     const Vector3d& velocities,
54     const Vector3d& accelerations,
55     const Vector3d& forces)
56   : mPositions(positions),
57     mVelocities(velocities),
58     mAccelerations(accelerations),
59     mForces(forces)
60 {
61   // Do nothing
62 }
63 
64 //==============================================================================
operator ==(const PointMass::State & other) const65 bool PointMass::State::operator==(const PointMass::State& other) const
66 {
67   RETURN_FALSE_IF_OTHER_IS_EQUAL(mPositions);
68   RETURN_FALSE_IF_OTHER_IS_EQUAL(mVelocities);
69   RETURN_FALSE_IF_OTHER_IS_EQUAL(mAccelerations);
70   RETURN_FALSE_IF_OTHER_IS_EQUAL(mForces);
71 
72   return true;
73 }
74 
75 //==============================================================================
Properties(const Vector3d & _X0,double _mass,const std::vector<std::size_t> & _connections,const Vector3d & _positionLowerLimits,const Vector3d & _positionUpperLimits,const Vector3d & _velocityLowerLimits,const Vector3d & _velocityUpperLimits,const Vector3d & _accelerationLowerLimits,const Vector3d & _accelerationUpperLimits,const Vector3d & _forceLowerLimits,const Vector3d & _forceUpperLimits)76 PointMass::Properties::Properties(
77     const Vector3d& _X0,
78     double _mass,
79     const std::vector<std::size_t>& _connections,
80     const Vector3d& _positionLowerLimits,
81     const Vector3d& _positionUpperLimits,
82     const Vector3d& _velocityLowerLimits,
83     const Vector3d& _velocityUpperLimits,
84     const Vector3d& _accelerationLowerLimits,
85     const Vector3d& _accelerationUpperLimits,
86     const Vector3d& _forceLowerLimits,
87     const Vector3d& _forceUpperLimits)
88   : mX0(_X0),
89     mMass(_mass),
90     mConnectedPointMassIndices(_connections),
91     mPositionLowerLimits(_positionLowerLimits),
92     mPositionUpperLimits(_positionUpperLimits),
93     mVelocityLowerLimits(_velocityLowerLimits),
94     mVelocityUpperLimits(_velocityUpperLimits),
95     mAccelerationLowerLimits(_accelerationLowerLimits),
96     mAccelerationUpperLimits(_accelerationUpperLimits),
97     mForceLowerLimits(_forceLowerLimits),
98     mForceUpperLimits(_forceUpperLimits)
99 {
100   // Do nothing
101 }
102 
103 //==============================================================================
setRestingPosition(const Vector3d & _x)104 void PointMass::Properties::setRestingPosition(const Vector3d& _x)
105 {
106   mX0 = _x;
107 }
108 
109 //==============================================================================
setMass(double _mass)110 void PointMass::Properties::setMass(double _mass)
111 {
112   mMass = _mass;
113 }
114 
115 //==============================================================================
operator ==(const PointMass::Properties & other) const116 bool PointMass::Properties::operator==(const PointMass::Properties& other) const
117 {
118   RETURN_FALSE_IF_OTHER_IS_EQUAL(mX0);
119   RETURN_FALSE_IF_OTHER_IS_EQUAL(mMass);
120   RETURN_FALSE_IF_OTHER_IS_EQUAL(mConnectedPointMassIndices);
121   RETURN_FALSE_IF_OTHER_IS_EQUAL(mPositionLowerLimits);
122   RETURN_FALSE_IF_OTHER_IS_EQUAL(mPositionUpperLimits);
123   RETURN_FALSE_IF_OTHER_IS_EQUAL(mVelocityLowerLimits);
124   RETURN_FALSE_IF_OTHER_IS_EQUAL(mVelocityUpperLimits);
125   RETURN_FALSE_IF_OTHER_IS_EQUAL(mAccelerationLowerLimits);
126   RETURN_FALSE_IF_OTHER_IS_EQUAL(mAccelerationUpperLimits);
127   RETURN_FALSE_IF_OTHER_IS_EQUAL(mForceLowerLimits);
128   RETURN_FALSE_IF_OTHER_IS_EQUAL(mForceUpperLimits);
129 
130   // Nothing was inequal, so we return true
131   return true;
132 }
133 
134 //==============================================================================
operator !=(const PointMass::Properties & other) const135 bool PointMass::Properties::operator!=(const PointMass::Properties& other) const
136 {
137   return !(other == *this);
138 }
139 
140 //==============================================================================
PointMass(SoftBodyNode * _softBodyNode)141 PointMass::PointMass(SoftBodyNode* _softBodyNode)
142   : // mIndexInSkeleton(Eigen::Matrix<std::size_t, 3, 1>::Zero()),
143     mParentSoftBodyNode(_softBodyNode),
144     mPositionDeriv(Eigen::Vector3d::Zero()),
145     mVelocitiesDeriv(Eigen::Vector3d::Zero()),
146     mAccelerationsDeriv(Eigen::Vector3d::Zero()),
147     mForcesDeriv(Eigen::Vector3d::Zero()),
148     mVelocityChanges(Eigen::Vector3d::Zero()),
149     // mImpulse(Eigen::Vector3d::Zero()),
150     mConstraintImpulses(Eigen::Vector3d::Zero()),
151     mW(Eigen::Vector3d::Zero()),
152     mX(Eigen::Vector3d::Zero()),
153     mV(Eigen::Vector3d::Zero()),
154     mEta(Eigen::Vector3d::Zero()),
155     mAlpha(Eigen::Vector3d::Zero()),
156     mBeta(Eigen::Vector3d::Zero()),
157     mA(Eigen::Vector3d::Zero()),
158     mF(Eigen::Vector3d::Zero()),
159     mPsi(0.0),
160     mImplicitPsi(0.0),
161     mPi(0.0),
162     mImplicitPi(0.0),
163     mB(Eigen::Vector3d::Zero()),
164     mFext(Eigen::Vector3d::Zero()),
165     mIsColliding(false),
166     mDelV(Eigen::Vector3d::Zero()),
167     mImpB(Eigen::Vector3d::Zero()),
168     mImpAlpha(Eigen::Vector3d::Zero()),
169     mImpBeta(Eigen::Vector3d::Zero()),
170     mImpF(Eigen::Vector3d::Zero()),
171     mNotifier(_softBodyNode->mNotifier)
172 {
173   assert(mParentSoftBodyNode != nullptr);
174   mNotifier->dirtyTransform();
175 }
176 
177 //==============================================================================
~PointMass()178 PointMass::~PointMass()
179 {
180   // Do nothing
181 }
182 
183 //==============================================================================
getState()184 PointMass::State& PointMass::getState()
185 {
186   return mParentSoftBodyNode->mAspectState.mPointStates[mIndex];
187 }
188 
189 //==============================================================================
getState() const190 const PointMass::State& PointMass::getState() const
191 {
192   return mParentSoftBodyNode->mAspectState.mPointStates[mIndex];
193 }
194 
195 //==============================================================================
getIndexInSoftBodyNode() const196 std::size_t PointMass::getIndexInSoftBodyNode() const
197 {
198   return mIndex;
199 }
200 
201 //==============================================================================
setMass(double _mass)202 void PointMass::setMass(double _mass)
203 {
204   assert(0.0 < _mass);
205   double& mMass
206       = mParentSoftBodyNode->mAspectProperties.mPointProps[mIndex].mMass;
207   if (_mass == mMass)
208     return;
209 
210   mMass = _mass;
211   mParentSoftBodyNode->incrementVersion();
212 }
213 
214 //==============================================================================
getMass() const215 double PointMass::getMass() const
216 {
217   return mParentSoftBodyNode->mAspectProperties.mPointProps[mIndex].mMass;
218 }
219 
220 //==============================================================================
getPsi() const221 double PointMass::getPsi() const
222 {
223   mParentSoftBodyNode->checkArticulatedInertiaUpdate();
224   return mPsi;
225 }
226 
227 //==============================================================================
getImplicitPsi() const228 double PointMass::getImplicitPsi() const
229 {
230   mParentSoftBodyNode->checkArticulatedInertiaUpdate();
231   return mImplicitPsi;
232 }
233 
234 //==============================================================================
getPi() const235 double PointMass::getPi() const
236 {
237   mParentSoftBodyNode->checkArticulatedInertiaUpdate();
238   return mPi;
239 }
240 
241 //==============================================================================
getImplicitPi() const242 double PointMass::getImplicitPi() const
243 {
244   mParentSoftBodyNode->checkArticulatedInertiaUpdate();
245   return mImplicitPi;
246 }
247 
248 //==============================================================================
addConnectedPointMass(PointMass * _pointMass)249 void PointMass::addConnectedPointMass(PointMass* _pointMass)
250 {
251   assert(_pointMass != nullptr);
252 
253   mParentSoftBodyNode->mAspectProperties.mPointProps[mIndex]
254       .mConnectedPointMassIndices.push_back(_pointMass->mIndex);
255   mParentSoftBodyNode->incrementVersion();
256 }
257 
258 //==============================================================================
getNumConnectedPointMasses() const259 std::size_t PointMass::getNumConnectedPointMasses() const
260 {
261   return mParentSoftBodyNode->mAspectProperties.mPointProps[mIndex]
262       .mConnectedPointMassIndices.size();
263 }
264 
265 //==============================================================================
getConnectedPointMass(std::size_t _idx)266 PointMass* PointMass::getConnectedPointMass(std::size_t _idx)
267 {
268   assert(_idx < getNumConnectedPointMasses());
269 
270   return mParentSoftBodyNode
271       ->mPointMasses[mParentSoftBodyNode->mAspectProperties.mPointProps[mIndex]
272                          .mConnectedPointMassIndices[_idx]];
273 }
274 
275 //==============================================================================
getConnectedPointMass(std::size_t _idx) const276 const PointMass* PointMass::getConnectedPointMass(std::size_t _idx) const
277 {
278   return const_cast<PointMass*>(this)->getConnectedPointMass(_idx);
279 }
280 
281 //==============================================================================
setColliding(bool _isColliding)282 void PointMass::setColliding(bool _isColliding)
283 {
284   mIsColliding = _isColliding;
285 }
286 
287 //==============================================================================
isColliding()288 bool PointMass::isColliding()
289 {
290   return mIsColliding;
291 }
292 
293 //==============================================================================
getNumDofs() const294 std::size_t PointMass::getNumDofs() const
295 {
296   return 3;
297 }
298 
299 ////==============================================================================
300 // void PointMass::setIndexInSkeleton(std::size_t _index, std::size_t
301 // _indexInSkeleton)
302 //{
303 //  assert(_index < 3);
304 
305 //  mIndexInSkeleton[_index] = _indexInSkeleton;
306 //}
307 
308 ////==============================================================================
309 // std::size_t PointMass::getIndexInSkeleton(std::size_t _index) const
310 //{
311 //  assert(_index < 3);
312 
313 //  return mIndexInSkeleton[_index];
314 //}
315 
316 //==============================================================================
setPosition(std::size_t _index,double _position)317 void PointMass::setPosition(std::size_t _index, double _position)
318 {
319   assert(_index < 3);
320 
321   getState().mPositions[_index] = _position;
322   mNotifier->dirtyTransform();
323 }
324 
325 //==============================================================================
getPosition(std::size_t _index) const326 double PointMass::getPosition(std::size_t _index) const
327 {
328   assert(_index < 3);
329 
330   return getState().mPositions[_index];
331 }
332 
333 //==============================================================================
setPositions(const Vector3d & _positions)334 void PointMass::setPositions(const Vector3d& _positions)
335 {
336   getState().mPositions = _positions;
337   mNotifier->dirtyTransform();
338 }
339 
340 //==============================================================================
getPositions() const341 const Vector3d& PointMass::getPositions() const
342 {
343   return getState().mPositions;
344 }
345 
346 //==============================================================================
resetPositions()347 void PointMass::resetPositions()
348 {
349   getState().mPositions.setZero();
350   mNotifier->dirtyTransform();
351 }
352 
353 //==============================================================================
setVelocity(std::size_t _index,double _velocity)354 void PointMass::setVelocity(std::size_t _index, double _velocity)
355 {
356   assert(_index < 3);
357 
358   getState().mVelocities[_index] = _velocity;
359   mNotifier->dirtyVelocity();
360 }
361 
362 //==============================================================================
getVelocity(std::size_t _index) const363 double PointMass::getVelocity(std::size_t _index) const
364 {
365   assert(_index < 3);
366 
367   return getState().mVelocities[_index];
368 }
369 
370 //==============================================================================
setVelocities(const Vector3d & _velocities)371 void PointMass::setVelocities(const Vector3d& _velocities)
372 {
373   getState().mVelocities = _velocities;
374   mNotifier->dirtyVelocity();
375 }
376 
377 //==============================================================================
getVelocities() const378 const Vector3d& PointMass::getVelocities() const
379 {
380   return getState().mVelocities;
381 }
382 
383 //==============================================================================
resetVelocities()384 void PointMass::resetVelocities()
385 {
386   getState().mVelocities.setZero();
387   mNotifier->dirtyVelocity();
388 }
389 
390 //==============================================================================
setAcceleration(std::size_t _index,double _acceleration)391 void PointMass::setAcceleration(std::size_t _index, double _acceleration)
392 {
393   assert(_index < 3);
394 
395   getState().mAccelerations[_index] = _acceleration;
396   mNotifier->dirtyAcceleration();
397 }
398 
399 //==============================================================================
getAcceleration(std::size_t _index) const400 double PointMass::getAcceleration(std::size_t _index) const
401 {
402   assert(_index < 3);
403 
404   return getState().mAccelerations[_index];
405 }
406 
407 //==============================================================================
setAccelerations(const Eigen::Vector3d & _accelerations)408 void PointMass::setAccelerations(const Eigen::Vector3d& _accelerations)
409 {
410   getState().mAccelerations = _accelerations;
411   mNotifier->dirtyAcceleration();
412 }
413 
414 //==============================================================================
getAccelerations() const415 const Vector3d& PointMass::getAccelerations() const
416 {
417   return getState().mAccelerations;
418 }
419 
420 //==============================================================================
getPartialAccelerations() const421 const Vector3d& PointMass::getPartialAccelerations() const
422 {
423   if (mNotifier->needsPartialAccelerationUpdate())
424     mParentSoftBodyNode->updatePartialAcceleration();
425   return mEta;
426 }
427 
428 //==============================================================================
resetAccelerations()429 void PointMass::resetAccelerations()
430 {
431   getState().mAccelerations.setZero();
432   mNotifier->dirtyAcceleration();
433 }
434 
435 //==============================================================================
setForce(std::size_t _index,double _force)436 void PointMass::setForce(std::size_t _index, double _force)
437 {
438   assert(_index < 3);
439 
440   getState().mForces[_index] = _force;
441 }
442 
443 //==============================================================================
getForce(std::size_t _index)444 double PointMass::getForce(std::size_t _index)
445 {
446   assert(_index < 3);
447 
448   return getState().mForces[_index];
449 }
450 
451 //==============================================================================
setForces(const Vector3d & _forces)452 void PointMass::setForces(const Vector3d& _forces)
453 {
454   getState().mForces = _forces;
455 }
456 
457 //==============================================================================
getForces() const458 const Vector3d& PointMass::getForces() const
459 {
460   return getState().mForces;
461 }
462 
463 //==============================================================================
resetForces()464 void PointMass::resetForces()
465 {
466   getState().mForces.setZero();
467 }
468 
469 //==============================================================================
setVelocityChange(std::size_t _index,double _velocityChange)470 void PointMass::setVelocityChange(std::size_t _index, double _velocityChange)
471 {
472   assert(_index < 3);
473 
474   mVelocityChanges[_index] = _velocityChange;
475 }
476 
477 //==============================================================================
getVelocityChange(std::size_t _index)478 double PointMass::getVelocityChange(std::size_t _index)
479 {
480   assert(_index < 3);
481 
482   return mVelocityChanges[_index];
483 }
484 
485 //==============================================================================
resetVelocityChanges()486 void PointMass::resetVelocityChanges()
487 {
488   mVelocityChanges.setZero();
489 }
490 
491 //==============================================================================
setConstraintImpulse(std::size_t _index,double _impulse)492 void PointMass::setConstraintImpulse(std::size_t _index, double _impulse)
493 {
494   assert(_index < 3);
495 
496   mConstraintImpulses[_index] = _impulse;
497 }
498 
499 //==============================================================================
getConstraintImpulse(std::size_t _index)500 double PointMass::getConstraintImpulse(std::size_t _index)
501 {
502   assert(_index < 3);
503 
504   return mConstraintImpulses[_index];
505 }
506 
507 //==============================================================================
resetConstraintImpulses()508 void PointMass::resetConstraintImpulses()
509 {
510   mConstraintImpulses.setZero();
511 }
512 
513 //==============================================================================
integratePositions(double _dt)514 void PointMass::integratePositions(double _dt)
515 {
516   setPositions(getPositions() + getVelocities() * _dt);
517 }
518 
519 //==============================================================================
integrateVelocities(double _dt)520 void PointMass::integrateVelocities(double _dt)
521 {
522   setVelocities(getVelocities() + getAccelerations() * _dt);
523 }
524 
525 //==============================================================================
addExtForce(const Eigen::Vector3d & _force,bool _isForceLocal)526 void PointMass::addExtForce(const Eigen::Vector3d& _force, bool _isForceLocal)
527 {
528   if (_isForceLocal)
529   {
530     mFext += _force;
531   }
532   else
533   {
534     mFext += mParentSoftBodyNode->getWorldTransform().linear().transpose()
535              * _force;
536   }
537 }
538 
539 //==============================================================================
clearExtForce()540 void PointMass::clearExtForce()
541 {
542   mFext.setZero();
543 }
544 
545 //==============================================================================
setConstraintImpulse(const Eigen::Vector3d & _constImp,bool _isLocal)546 void PointMass::setConstraintImpulse(
547     const Eigen::Vector3d& _constImp, bool _isLocal)
548 {
549   if (_isLocal)
550   {
551     mConstraintImpulses = _constImp;
552   }
553   else
554   {
555     const Matrix3d Rt
556         = mParentSoftBodyNode->getWorldTransform().linear().transpose();
557     mConstraintImpulses = Rt * _constImp;
558   }
559 }
560 
561 //==============================================================================
addConstraintImpulse(const Eigen::Vector3d & _constImp,bool _isLocal)562 void PointMass::addConstraintImpulse(
563     const Eigen::Vector3d& _constImp, bool _isLocal)
564 {
565   if (_isLocal)
566   {
567     mConstraintImpulses += _constImp;
568   }
569   else
570   {
571     const Matrix3d Rt
572         = mParentSoftBodyNode->getWorldTransform().linear().transpose();
573     mConstraintImpulses.noalias() += Rt * _constImp;
574   }
575 }
576 
577 //==============================================================================
getConstraintImpulses() const578 Eigen::Vector3d PointMass::getConstraintImpulses() const
579 {
580   return mConstraintImpulses;
581 }
582 
583 //==============================================================================
clearConstraintImpulse()584 void PointMass::clearConstraintImpulse()
585 {
586   assert(getNumDofs() == 3);
587   mConstraintImpulses.setZero();
588   mDelV.setZero();
589   mImpB.setZero();
590   mImpAlpha.setZero();
591   mImpBeta.setZero();
592   mImpF.setZero();
593 }
594 
595 //==============================================================================
setRestingPosition(const Eigen::Vector3d & _p)596 void PointMass::setRestingPosition(const Eigen::Vector3d& _p)
597 {
598 
599   Eigen::Vector3d& mRest
600       = mParentSoftBodyNode->mAspectProperties.mPointProps[mIndex].mX0;
601   if (_p == mRest)
602     return;
603 
604   mRest = _p;
605   mParentSoftBodyNode->incrementVersion();
606   mNotifier->dirtyTransform();
607 }
608 
609 //==============================================================================
getRestingPosition() const610 const Eigen::Vector3d& PointMass::getRestingPosition() const
611 {
612   return mParentSoftBodyNode->mAspectProperties.mPointProps[mIndex].mX0;
613 }
614 
615 //==============================================================================
getLocalPosition() const616 const Eigen::Vector3d& PointMass::getLocalPosition() const
617 {
618   if (mNotifier->needsTransformUpdate())
619     mParentSoftBodyNode->updateTransform();
620   return mX;
621 }
622 
623 //==============================================================================
getWorldPosition() const624 const Eigen::Vector3d& PointMass::getWorldPosition() const
625 {
626   if (mNotifier && mNotifier->needsTransformUpdate())
627     mParentSoftBodyNode->updateTransform();
628   return mW;
629 }
630 
631 //==============================================================================
getBodyJacobian()632 Eigen::Matrix<double, 3, Eigen::Dynamic> PointMass::getBodyJacobian()
633 {
634   assert(mParentSoftBodyNode != nullptr);
635 
636   int dof = mParentSoftBodyNode->getNumDependentGenCoords();
637   int totalDof = mParentSoftBodyNode->getNumDependentGenCoords() + 3;
638 
639   Eigen::Matrix<double, 3, Eigen::Dynamic> J
640       = Eigen::MatrixXd::Zero(3, totalDof);
641 
642   Eigen::Isometry3d T = Eigen::Isometry3d::Identity();
643   T.translation() = getLocalPosition();
644 
645   J.leftCols(dof)
646       = math::AdInvTJac(T, mParentSoftBodyNode->getJacobian()).bottomRows<3>();
647   J.rightCols<3>() = Eigen::Matrix3d::Identity();
648 
649   return J;
650 }
651 
652 //==============================================================================
getWorldJacobian()653 Eigen::Matrix<double, 3, Eigen::Dynamic> PointMass::getWorldJacobian()
654 {
655   return mParentSoftBodyNode->getWorldTransform().linear() * getBodyJacobian();
656 }
657 
658 //==============================================================================
getBodyVelocityChange() const659 const Eigen::Vector3d& PointMass::getBodyVelocityChange() const
660 {
661   return mDelV;
662 }
663 
664 //==============================================================================
getParentSoftBodyNode()665 SoftBodyNode* PointMass::getParentSoftBodyNode()
666 {
667   return mParentSoftBodyNode;
668 }
669 
670 //==============================================================================
getParentSoftBodyNode() const671 const SoftBodyNode* PointMass::getParentSoftBodyNode() const
672 {
673   return mParentSoftBodyNode;
674 }
675 
676 //==============================================================================
677 // int PointMass::getNumDependentGenCoords() const
678 //{
679 //  return mDependentGenCoordIndices.size();
680 //}
681 
682 //==============================================================================
683 // int PointMass::getDependentGenCoord(int _arrayIndex) const
684 //{
685 //  assert(0 <= _arrayIndex && _arrayIndex < mDependentGenCoordIndices.size());
686 //  return mDependentGenCoordIndices[_arrayIndex];
687 //}
688 
689 //==============================================================================
getBodyVelocity() const690 const Eigen::Vector3d& PointMass::getBodyVelocity() const
691 {
692   if (mNotifier->needsVelocityUpdate())
693     mParentSoftBodyNode->updateVelocity();
694   return mV;
695 }
696 
697 //==============================================================================
getWorldVelocity() const698 Eigen::Vector3d PointMass::getWorldVelocity() const
699 {
700   return mParentSoftBodyNode->getWorldTransform().linear() * getBodyVelocity();
701 }
702 
703 //==============================================================================
getBodyAcceleration() const704 const Eigen::Vector3d& PointMass::getBodyAcceleration() const
705 {
706   if (mNotifier->needsAccelerationUpdate())
707     mParentSoftBodyNode->updateAccelerationID();
708   return mA;
709 }
710 
711 //==============================================================================
getWorldAcceleration() const712 Eigen::Vector3d PointMass::getWorldAcceleration() const
713 {
714   return mParentSoftBodyNode->getWorldTransform().linear()
715          * getBodyAcceleration();
716 }
717 
718 //==============================================================================
init()719 void PointMass::init()
720 {
721   mDependentGenCoordIndices
722       = mParentSoftBodyNode->getDependentGenCoordIndices();
723 }
724 
725 //==============================================================================
updateTransform() const726 void PointMass::updateTransform() const
727 {
728   // Local translation
729   mX = getPositions() + getRestingPosition();
730   assert(!math::isNan(mX));
731 
732   // World translation
733   const Eigen::Isometry3d& parentW = mParentSoftBodyNode->getWorldTransform();
734   mW = parentW.translation() + parentW.linear() * mX;
735   assert(!math::isNan(mW));
736 }
737 
738 //==============================================================================
updateVelocity() const739 void PointMass::updateVelocity() const
740 {
741   // v = w(parent) x mX + v(parent) + dq
742   const Eigen::Vector6d& v_parent = mParentSoftBodyNode->getSpatialVelocity();
743   mV = v_parent.head<3>().cross(getLocalPosition()) + v_parent.tail<3>()
744        + getVelocities();
745   assert(!math::isNan(mV));
746 }
747 
748 //==============================================================================
updatePartialAcceleration() const749 void PointMass::updatePartialAcceleration() const
750 {
751   // eta = w(parent) x dq
752   const Eigen::Vector3d& dq = getVelocities();
753   mEta = mParentSoftBodyNode->getSpatialVelocity().head<3>().cross(dq);
754   assert(!math::isNan(mEta));
755 }
756 
757 //==============================================================================
updateAccelerationID() const758 void PointMass::updateAccelerationID() const
759 {
760   // dv = dw(parent) x mX + dv(parent) + eata + ddq
761   const Eigen::Vector6d& a_parent
762       = mParentSoftBodyNode->getSpatialAcceleration();
763   mA = a_parent.head<3>().cross(getLocalPosition()) + a_parent.tail<3>()
764        + getPartialAccelerations() + getAccelerations();
765   assert(!math::isNan(mA));
766 }
767 
768 //==============================================================================
updateTransmittedForceID(const Eigen::Vector3d & _gravity,bool)769 void PointMass::updateTransmittedForceID(
770     const Eigen::Vector3d& _gravity, bool /*_withExternalForces*/)
771 {
772   // f = m*dv + w(parent) x m*v - fext
773   mF.noalias() = getMass() * getBodyAcceleration();
774   mF += mParentSoftBodyNode->getSpatialVelocity().head<3>().cross(
775             getMass() * getBodyVelocity())
776         - mFext;
777   if (mParentSoftBodyNode->getGravityMode() == true)
778   {
779     mF -= getMass()
780           * (mParentSoftBodyNode->getWorldTransform().linear().transpose()
781              * _gravity);
782   }
783   assert(!math::isNan(mF));
784 }
785 
786 //==============================================================================
updateArtInertiaFD(double _timeStep) const787 void PointMass::updateArtInertiaFD(double _timeStep) const
788 {
789   // Articulated inertia
790   // - Do nothing
791 
792   // Cache data: PsiK and Psi
793   mPsi = 1.0 / getMass();
794   mImplicitPsi
795       = 1.0
796         / (getMass() + _timeStep * mParentSoftBodyNode->getDampingCoefficient()
797            + _timeStep * _timeStep
798                  * mParentSoftBodyNode->getVertexSpringStiffness());
799   assert(!math::isNan(mImplicitPsi));
800 
801   // Cache data: AI_S_Psi
802   // - Do nothing
803 
804   // Cache data: Pi
805   mPi = getMass() - getMass() * getMass() * mPsi;
806   mImplicitPi = getMass() - getMass() * getMass() * mImplicitPsi;
807   assert(!math::isNan(mPi));
808   assert(!math::isNan(mImplicitPi));
809 }
810 
811 //==============================================================================
updateJointForceID(double,double,double)812 void PointMass::updateJointForceID(
813     double /*_timeStep*/,
814     double /*_withDampingForces*/,
815     double /*_withSpringForces*/)
816 {
817   // tau = f
818   getState().mForces = mF;
819   // TODO: need to add spring and damping forces
820 }
821 
822 //==============================================================================
updateBiasForceFD(double _dt,const Eigen::Vector3d & _gravity)823 void PointMass::updateBiasForceFD(double _dt, const Eigen::Vector3d& _gravity)
824 {
825   // B = w(parent) x m*v - fext - fgravity
826   // - w(parent) x m*v - fext
827   mB = mParentSoftBodyNode->getSpatialVelocity().head<3>().cross(
828            getMass() * getBodyVelocity())
829        - mFext;
830   // - fgravity
831   if (mParentSoftBodyNode->getGravityMode() == true)
832   {
833     mB -= getMass()
834           * (mParentSoftBodyNode->getWorldTransform().linear().transpose()
835              * _gravity);
836   }
837   assert(!math::isNan(mB));
838 
839   const State& state = getState();
840 
841   // Cache data: alpha
842   double kv = mParentSoftBodyNode->getVertexSpringStiffness();
843   double ke = mParentSoftBodyNode->getEdgeSpringStiffness();
844   double kd = mParentSoftBodyNode->getDampingCoefficient();
845   std::size_t nN = getNumConnectedPointMasses();
846   mAlpha = state.mForces - (kv + nN * ke) * getPositions()
847            - (_dt * (kv + nN * ke) + kd) * getVelocities()
848            - getMass() * getPartialAccelerations() - mB;
849   for (std::size_t i = 0; i < getNumConnectedPointMasses(); ++i)
850   {
851     const State& i_state = getConnectedPointMass(i)->getState();
852     mAlpha += ke * (i_state.mPositions + _dt * i_state.mVelocities);
853   }
854   assert(!math::isNan(mAlpha));
855 
856   // Cache data: beta
857   mBeta = mB;
858   mBeta.noalias()
859       += getMass() * (getPartialAccelerations() + getImplicitPsi() * mAlpha);
860   assert(!math::isNan(mBeta));
861 }
862 
863 //==============================================================================
updateAccelerationFD()864 void PointMass::updateAccelerationFD()
865 {
866   // ddq = imp_psi*(alpha - m*(dw(parent) x mX + dv(parent))
867   const Eigen::Vector3d& X = getLocalPosition();
868   const Eigen::Vector6d& a_parent
869       = mParentSoftBodyNode->getSpatialAcceleration();
870   Eigen::Vector3d ddq
871       = getImplicitPsi()
872         * (mAlpha
873            - getMass() * (a_parent.head<3>().cross(X) + a_parent.tail<3>()));
874   setAccelerations(ddq);
875   assert(!math::isNan(ddq));
876 
877   // dv = dw(parent) x mX + dv(parent) + eata + ddq
878   mA = a_parent.head<3>().cross(X) + a_parent.tail<3>()
879        + getPartialAccelerations() + getAccelerations();
880   assert(!math::isNan(mA));
881 }
882 
883 //==============================================================================
updateTransmittedForce()884 void PointMass::updateTransmittedForce()
885 {
886   // f = m*dv + B
887   mF = mB;
888   mF.noalias() += getMass() * getBodyAcceleration();
889   assert(!math::isNan(mF));
890 }
891 
892 //==============================================================================
updateMassMatrix()893 void PointMass::updateMassMatrix()
894 {
895   mM_dV = getAccelerations()
896           + mParentSoftBodyNode->mM_dV.head<3>().cross(getLocalPosition())
897           + mParentSoftBodyNode->mM_dV.tail<3>();
898   assert(!math::isNan(mM_dV));
899 }
900 
901 //==============================================================================
updateBiasImpulseFD()902 void PointMass::updateBiasImpulseFD()
903 {
904   mImpB = -mConstraintImpulses;
905   assert(!math::isNan(mImpB));
906 
907   // Cache data: alpha
908   mImpAlpha = -mImpB;
909   assert(!math::isNan(mImpAlpha));
910 
911   // Cache data: beta
912   mImpBeta.setZero();
913   assert(!math::isNan(mImpBeta));
914 }
915 
916 //==============================================================================
updateVelocityChangeFD()917 void PointMass::updateVelocityChangeFD()
918 {
919   //  Eigen::Vector3d del_dq
920   //      = mPsi
921   //        * (mImpAlpha - mMass
922   //           *
923   //           (mParentSoftBodyNode->getBodyVelocityChange().head<3>().cross(mX)
924   //              + mParentSoftBodyNode->getBodyVelocityChange().tail<3>()));
925 
926   const Eigen::Vector3d& X = getLocalPosition();
927   Eigen::Vector3d del_dq
928       = getPsi() * mImpAlpha
929         - mParentSoftBodyNode->getBodyVelocityChange().head<3>().cross(X)
930         - mParentSoftBodyNode->getBodyVelocityChange().tail<3>();
931 
932   //  del_dq = Eigen::Vector3d::Zero();
933 
934   mVelocityChanges = del_dq;
935   assert(!math::isNan(del_dq));
936 
937   mDelV = mParentSoftBodyNode->getBodyVelocityChange().head<3>().cross(X)
938           + mParentSoftBodyNode->getBodyVelocityChange().tail<3>()
939           + mVelocityChanges;
940   assert(!math::isNan(mDelV));
941 }
942 
943 //==============================================================================
updateTransmittedImpulse()944 void PointMass::updateTransmittedImpulse()
945 {
946   mImpF = mImpB;
947   mImpF.noalias() += getMass() * mDelV;
948   assert(!math::isNan(mImpF));
949 }
950 
951 //==============================================================================
updateConstrainedTermsFD(double _timeStep)952 void PointMass::updateConstrainedTermsFD(double _timeStep)
953 {
954   // 1. dq = dq + del_dq
955   setVelocities(getVelocities() + mVelocityChanges);
956 
957   // 2. ddq = ddq + del_dq / dt
958   setAccelerations(getAccelerations() + mVelocityChanges / _timeStep);
959 
960   // 3. tau = tau + imp / dt
961   getState().mForces.noalias() += mConstraintImpulses / _timeStep;
962 
963   ///
964   //  mA += mDelV / _timeStep;
965   setAccelerations(getAccelerations() + mDelV / _timeStep);
966 
967   ///
968   mF += _timeStep * mImpF;
969 }
970 
971 //==============================================================================
aggregateMassMatrix(MatrixXd &,int)972 void PointMass::aggregateMassMatrix(MatrixXd& /*_MCol*/, int /*_col*/)
973 {
974   // TODO(JS): Not implemented
975   //  // Assign
976   //  // We assume that the three generalized coordinates are in a row.
977   //  int iStart = mIndexInSkeleton[0];
978   //  mM_F.noalias() = mMass * mM_dV;
979   //  _MCol->block<3, 1>(iStart, _col).noalias() = mM_F;
980 }
981 
982 //==============================================================================
aggregateAugMassMatrix(Eigen::MatrixXd &,int,double)983 void PointMass::aggregateAugMassMatrix(
984     Eigen::MatrixXd& /*_MCol*/, int /*_col*/, double /*_timeStep*/)
985 {
986   // TODO(JS): Not implemented
987   //  // Assign
988   //  // We assume that the three generalized coordinates are in a row.
989   //  int iStart = mIndexInSkeleton[0];
990   //  mM_F.noalias() = mMass * mM_dV;
991 
992   //  double d = mParentSoftBodyNode->getDampingCoefficient();
993   //  double kv = mParentSoftBodyNode->getVertexSpringStiffness();
994   //  _MCol->block<3, 1>(iStart, _col).noalias()
995   //      = mM_F + (_timeStep * _timeStep * kv + _timeStep * d) *
996   //      mAccelerations;
997 }
998 
999 //==============================================================================
updateInvMassMatrix()1000 void PointMass::updateInvMassMatrix()
1001 {
1002   mBiasForceForInvMeta = getState().mForces;
1003 }
1004 
1005 //==============================================================================
updateInvAugMassMatrix()1006 void PointMass::updateInvAugMassMatrix()
1007 {
1008   //  mBiasForceForInvMeta = mMass * mImplicitPsi * mForces;
1009 }
1010 
1011 //==============================================================================
aggregateInvMassMatrix(Eigen::MatrixXd &,int)1012 void PointMass::aggregateInvMassMatrix(
1013     Eigen::MatrixXd& /*_MInvCol*/, int /*_col*/)
1014 {
1015   // TODO(JS): Not implemented
1016   //  // Assign
1017   //  // We assume that the three generalized coordinates are in a row.
1018   //  int iStart = mIndexInSkeleton[0];
1019   //  _MInvCol->block<3, 1>(iStart, _col)
1020   //      = mPsi * mForces
1021   //        - mParentSoftBodyNode->mInvM_U.head<3>().cross(mX)
1022   //        - mParentSoftBodyNode->mInvM_U.tail<3>();
1023 }
1024 
1025 //==============================================================================
aggregateInvAugMassMatrix(Eigen::MatrixXd &,int,double)1026 void PointMass::aggregateInvAugMassMatrix(
1027     Eigen::MatrixXd& /*_MInvCol*/, int /*_col*/, double /*_timeStep*/)
1028 {
1029   // TODO(JS): Not implemented
1030   //  // Assign
1031   //  // We assume that the three generalized coordinates are in a row.
1032   //  int iStart = mIndexInSkeleton[0];
1033   //  _MInvCol->block<3, 1>(iStart, _col)
1034   //      = mImplicitPsi
1035   //        * (mForces
1036   //           - mMass * (mParentSoftBodyNode->mInvM_U.head<3>().cross(mX)
1037   //                      + mParentSoftBodyNode->mInvM_U.tail<3>()));
1038 }
1039 
1040 //==============================================================================
aggregateGravityForceVector(VectorXd &,const Eigen::Vector3d &)1041 void PointMass::aggregateGravityForceVector(
1042     VectorXd& /*_g*/, const Eigen::Vector3d& /*_gravity*/)
1043 {
1044   // TODO(JS): Not implemented
1045   //  mG_F = mMass *
1046   //  (mParentSoftBodyNode->getWorldTransform().linear().transpose()
1047   //                  * _gravity);
1048 
1049   //  // Assign
1050   //  // We assume that the three generalized coordinates are in a row.
1051   //  int iStart = mIndexInSkeleton[0];
1052   //  _g->segment<3>(iStart) = mG_F;
1053 }
1054 
1055 //==============================================================================
updateCombinedVector()1056 void PointMass::updateCombinedVector()
1057 {
1058   mCg_dV = getPartialAccelerations()
1059            + mParentSoftBodyNode->mCg_dV.head<3>().cross(getLocalPosition())
1060            + mParentSoftBodyNode->mCg_dV.tail<3>();
1061 }
1062 
1063 //==============================================================================
aggregateCombinedVector(Eigen::VectorXd &,const Eigen::Vector3d &)1064 void PointMass::aggregateCombinedVector(
1065     Eigen::VectorXd& /*_Cg*/, const Eigen::Vector3d& /*_gravity*/)
1066 {
1067   // TODO(JS): Not implemented
1068   //  mCg_F.noalias() = mMass * mCg_dV;
1069   //  mCg_F -= mMass
1070   //           * (mParentSoftBodyNode->getWorldTransform().linear().transpose()
1071   //              * _gravity);
1072   //  mCg_F += mParentSoftBodyNode->getBodyVelocity().head<3>().cross(mMass *
1073   //  mV);
1074 
1075   //  // Assign
1076   //  // We assume that the three generalized coordinates are in a row.
1077   //  int iStart = mIndexInSkeleton[0];
1078   //  _Cg->segment<3>(iStart) = mCg_F;
1079 }
1080 
1081 //==============================================================================
aggregateExternalForces(VectorXd &)1082 void PointMass::aggregateExternalForces(VectorXd& /*_Fext*/)
1083 {
1084   // TODO(JS): Not implemented
1085   //  int iStart = mIndexInSkeleton[0];
1086   //  _Fext->segment<3>(iStart) = mFext;
1087 }
1088 
1089 //==============================================================================
PointMassNotifier(SoftBodyNode * _parentSoftBody,const std::string & _name)1090 PointMassNotifier::PointMassNotifier(
1091     SoftBodyNode* _parentSoftBody, const std::string& _name)
1092   : Entity(_parentSoftBody, false),
1093     mNeedPartialAccelerationUpdate(true),
1094     mParentSoftBodyNode(_parentSoftBody)
1095 {
1096   setName(_name);
1097 }
1098 
1099 //==============================================================================
needsPartialAccelerationUpdate() const1100 bool PointMassNotifier::needsPartialAccelerationUpdate() const
1101 {
1102   return mNeedPartialAccelerationUpdate;
1103 }
1104 
1105 //==============================================================================
clearTransformNotice()1106 void PointMassNotifier::clearTransformNotice()
1107 {
1108   mNeedTransformUpdate = false;
1109 }
1110 
1111 //==============================================================================
clearVelocityNotice()1112 void PointMassNotifier::clearVelocityNotice()
1113 {
1114   mNeedVelocityUpdate = false;
1115 }
1116 
1117 //==============================================================================
clearPartialAccelerationNotice()1118 void PointMassNotifier::clearPartialAccelerationNotice()
1119 {
1120   mNeedPartialAccelerationUpdate = false;
1121 }
1122 
1123 //==============================================================================
clearAccelerationNotice()1124 void PointMassNotifier::clearAccelerationNotice()
1125 {
1126   mNeedAccelerationUpdate = false;
1127 }
1128 
1129 //==============================================================================
dirtyTransform()1130 void PointMassNotifier::dirtyTransform()
1131 {
1132   mNeedTransformUpdate = true;
1133   mNeedVelocityUpdate = true;
1134   mNeedPartialAccelerationUpdate = true;
1135   mNeedAccelerationUpdate = true;
1136 
1137   mParentSoftBodyNode->dirtyArticulatedInertia();
1138   mParentSoftBodyNode->dirtyExternalForces();
1139 }
1140 
1141 //==============================================================================
dirtyVelocity()1142 void PointMassNotifier::dirtyVelocity()
1143 {
1144   mNeedVelocityUpdate = true;
1145   mNeedPartialAccelerationUpdate = true;
1146   mNeedAccelerationUpdate = true;
1147 
1148   mParentSoftBodyNode->dirtyCoriolisForces();
1149 }
1150 
1151 //==============================================================================
dirtyAcceleration()1152 void PointMassNotifier::dirtyAcceleration()
1153 {
1154   mNeedAccelerationUpdate = true;
1155 }
1156 
1157 //==============================================================================
setName(const std::string & _name)1158 const std::string& PointMassNotifier::setName(const std::string& _name)
1159 {
1160   if (_name == mName)
1161     return mName;
1162 
1163   const std::string oldName = mName;
1164 
1165   mName = _name;
1166 
1167   Entity::mNameChangedSignal.raise(this, oldName, mName);
1168 
1169   return mName;
1170 }
1171 
1172 //==============================================================================
getName() const1173 const std::string& PointMassNotifier::getName() const
1174 {
1175   return mName;
1176 }
1177 
1178 } // namespace dynamics
1179 } // namespace dart
1180