Simbody
3.4 (development)
|
00001 #ifndef SimTK_SIMMATRIX_MASS_PROPERTIES_H_ 00002 #define SimTK_SIMMATRIX_MASS_PROPERTIES_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2005-12 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: Paul Mitiguy * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00033 #include "SimTKcommon/Scalar.h" 00034 #include "SimTKcommon/SmallMatrix.h" 00035 #include "SimTKcommon/Orientation.h" 00036 00037 #include <iostream> 00038 00039 namespace SimTK { 00050 typedef Vec<2, Vec3> SpatialVec; 00053 typedef Vec<2, Vec<3,float> > fSpatialVec; 00056 typedef Vec<2, Vec<3,double> > dSpatialVec; 00057 00060 typedef Row<2, Row3> SpatialRow; 00063 typedef Row<2, Row<3,float> > fSpatialRow; 00066 typedef Row<2, Row<3,double> > dSpatialRow; 00067 00072 typedef Mat<2,2, Mat33> SpatialMat; 00075 typedef Mat<2,2, Mat<3,3,float> > fSpatialMat; 00078 typedef Mat<2,2, Mat<3,3,double> > dSpatialMat; 00079 00080 // These are templatized by precision (float or double). 00081 template <class P> class UnitInertia_; 00082 template <class P> class Inertia_; 00083 template <class P> class SpatialInertia_; 00084 template <class P> class ArticulatedInertia_; 00085 template <class P> class MassProperties_; 00086 00087 // The "no trailing underscore" typedefs use whatever the 00088 // compile-time precision is set to. 00089 00091 typedef UnitInertia_<Real> UnitInertia; 00093 typedef UnitInertia_<float> fUnitInertia; 00095 typedef UnitInertia_<double> dUnitInertia; 00096 00098 typedef Inertia_<Real> Inertia; 00100 typedef Inertia_<float> fInertia; 00102 typedef Inertia_<double> dInertia; 00103 00105 typedef MassProperties_<Real> MassProperties; 00107 typedef MassProperties_<float> fMassProperties; 00109 typedef MassProperties_<double> dMassProperties; 00110 00112 typedef SpatialInertia_<Real> SpatialInertia; 00114 typedef SpatialInertia_<float> fSpatialInertia; 00116 typedef SpatialInertia_<double> dSpatialInertia; 00117 00119 typedef ArticulatedInertia_<Real> ArticulatedInertia; 00121 typedef ArticulatedInertia_<float> fArticulatedInertia; 00123 typedef ArticulatedInertia_<double> dArticulatedInertia; 00124 00126 typedef UnitInertia Gyration; 00127 00128 // ----------------------------------------------------------------------------- 00129 // INERTIA MATRIX 00130 // ----------------------------------------------------------------------------- 00192 template <class P> 00193 class SimTK_SimTKCOMMON_EXPORT Inertia_ { 00194 typedef P RealP; 00195 typedef Vec<3,P> Vec3P; 00196 typedef SymMat<3,P> SymMat33P; 00197 typedef Mat<3,3,P> Mat33P; 00198 typedef Rotation_<P> RotationP; 00199 public: 00202 Inertia_() : I_OF_F(NTraits<P>::getNaN()) {} 00203 00204 // Default copy constructor, copy assignment, destructor. 00205 00212 explicit Inertia_(const RealP& moment) : I_OF_F(moment) 00213 { errChk("Inertia::Inertia(moment)"); } 00214 00218 Inertia_(const Vec3P& p, const RealP& mass) : I_OF_F(pointMassAt(p,mass)) {} 00219 00224 explicit Inertia_(const Vec3P& moments, const Vec3P& products=Vec3P(0)) 00225 { I_OF_F.updDiag() = moments; 00226 I_OF_F.updLower() = products; 00227 errChk("Inertia::Inertia(moments,products)"); } 00228 00230 Inertia_(const RealP& xx, const RealP& yy, const RealP& zz) 00231 { I_OF_F = SymMat33P(xx, 00232 0, yy, 00233 0, 0, zz); 00234 errChk("Inertia::setInertia(xx,yy,zz)"); } 00235 00238 Inertia_(const RealP& xx, const RealP& yy, const RealP& zz, 00239 const RealP& xy, const RealP& xz, const RealP& yz) 00240 { I_OF_F = SymMat33P(xx, 00241 xy, yy, 00242 xz, yz, zz); 00243 errChk("Inertia::setInertia(xx,yy,zz,xy,xz,yz)"); } 00244 00247 explicit Inertia_(const SymMat33P& I) : I_OF_F(I) 00248 { errChk("Inertia::Inertia(SymMat33)"); } 00249 00253 explicit Inertia_(const Mat33P& m) 00254 { SimTK_ERRCHK(m.isNumericallySymmetric(), 00255 "Inertia(Mat33)", "The supplied matrix was not symmetric."); 00256 I_OF_F = SymMat33P(m); 00257 errChk("Inertia(Mat33)"); } 00258 00259 00262 Inertia_& setInertia(const RealP& xx, const RealP& yy, const RealP& zz) { 00263 I_OF_F = RealP(0); I_OF_F(0,0) = xx; I_OF_F(1,1) = yy; I_OF_F(2,2) = zz; 00264 errChk("Inertia::setInertia(xx,yy,zz)"); 00265 return *this; 00266 } 00267 00270 Inertia_& setInertia(const Vec3P& moments, const Vec3P& products=Vec3P(0)) { 00271 I_OF_F.updDiag() = moments; 00272 I_OF_F.updLower() = products; 00273 errChk("Inertia::setInertia(moments,products)"); 00274 return *this; 00275 } 00276 00282 Inertia_& setInertia(const RealP& xx, const RealP& yy, const RealP& zz, 00283 const RealP& xy, const RealP& xz, const RealP& yz) { 00284 setInertia(Vec3P(xx,yy,zz), Vec3P(xy,xz,yz)); 00285 errChk("Inertia::setInertia(xx,yy,zz,xy,xz,yz)"); 00286 return *this; 00287 } 00288 00289 00292 Inertia_& operator+=(const Inertia_& I) 00293 { I_OF_F += I.I_OF_F; 00294 errChk("Inertia::operator+=()"); 00295 return *this; } 00296 00299 Inertia_& operator-=(const Inertia_& I) 00300 { I_OF_F -= I.I_OF_F; 00301 errChk("Inertia::operator-=()"); 00302 return *this; } 00303 00305 Inertia_& operator*=(const P& s) {I_OF_F *= s; return *this;} 00306 00309 Inertia_& operator/=(const P& s) {I_OF_F /= s; return *this;} 00310 00320 Inertia_ shiftToMassCenter(const Vec3P& CF, const RealP& mass) const 00321 { Inertia_ I(*this); I -= pointMassAt(CF, mass); 00322 I.errChk("Inertia::shiftToMassCenter()"); 00323 return I; } 00324 00335 Inertia_& shiftToMassCenterInPlace(const Vec3P& CF, const RealP& mass) 00336 { (*this) -= pointMassAt(CF, mass); 00337 errChk("Inertia::shiftToMassCenterInPlace()"); 00338 return *this; } 00339 00347 Inertia_ shiftFromMassCenter(const Vec3P& p, const RealP& mass) const 00348 { Inertia_ I(*this); I += pointMassAt(p, mass); 00349 I.errChk("Inertia::shiftFromMassCenter()"); 00350 return I; } 00351 00360 Inertia_& shiftFromMassCenterInPlace(const Vec3P& p, const RealP& mass) 00361 { (*this) += pointMassAt(p, mass); 00362 errChk("Inertia::shiftFromMassCenterInPlace()"); 00363 return *this; } 00364 00375 Inertia_ reexpress(const Rotation_<P>& R_FB) const 00376 { return Inertia_((~R_FB).reexpressSymMat33(I_OF_F)); } 00377 00380 Inertia_ reexpress(const InverseRotation_<P>& R_FB) const 00381 { return Inertia_((~R_FB).reexpressSymMat33(I_OF_F)); } 00382 00387 Inertia_& reexpressInPlace(const Rotation_<P>& R_FB) 00388 { I_OF_F = (~R_FB).reexpressSymMat33(I_OF_F); return *this; } 00389 00392 Inertia_& reexpressInPlace(const InverseRotation_<P>& R_FB) 00393 { I_OF_F = (~R_FB).reexpressSymMat33(I_OF_F); return *this; } 00394 00395 RealP trace() const {return I_OF_F.trace();} 00396 00398 operator const SymMat33P&() const {return I_OF_F;} 00399 00401 const SymMat33P& asSymMat33() const {return I_OF_F;} 00402 00405 Mat33P toMat33() const {return Mat33P(I_OF_F);} 00406 00409 const Vec3P& getMoments() const {return I_OF_F.getDiag();} 00412 const Vec3P& getProducts() const {return I_OF_F.getLower();} 00413 00414 bool isNaN() const {return I_OF_F.isNaN();} 00415 bool isInf() const {return I_OF_F.isInf();} 00416 bool isFinite() const {return I_OF_F.isFinite();} 00417 00421 bool isNumericallyEqual(const Inertia_<P>& other) const 00422 { return I_OF_F.isNumericallyEqual(other.I_OF_F); } 00423 00427 bool isNumericallyEqual(const Inertia_<P>& other, double tol) const 00428 { return I_OF_F.isNumericallyEqual(other.I_OF_F, tol); } 00429 00432 static bool isValidInertiaMatrix(const SymMat33P& m) { 00433 if (m.isNaN()) return false; 00434 00435 const Vec3P& d = m.diag(); 00436 if (!(d >= 0)) return false; // diagonals must be nonnegative 00437 00438 const RealP Slop = std::max(d.sum(),RealP(1)) 00439 * NTraits<P>::getSignificant(); 00440 00441 if (!(d[0]+d[1]+Slop>=d[2] && d[0]+d[2]+Slop>=d[1] && d[1]+d[2]+Slop>=d[0])) 00442 return false; // must satisfy triangle inequality 00443 00444 // Thanks to Paul Mitiguy for this condition on products of inertia. 00445 const Vec3P& p = m.getLower(); 00446 if (!( d[0]+Slop>=std::abs(2*p[2]) 00447 && d[1]+Slop>=std::abs(2*p[1]) 00448 && d[2]+Slop>=std::abs(2*p[0]))) 00449 return false; // max products are limited by moments 00450 00451 return true; 00452 } 00453 00456 static Inertia_ pointMassAtOrigin() {return Inertia_(0);} 00457 00462 static Inertia_ pointMassAt(const Vec3P& p, const RealP& m) { 00463 const Vec3P mp = m*p; // 3 flops 00464 const RealP mxx = mp[0]*p[0]; 00465 const RealP myy = mp[1]*p[1]; 00466 const RealP mzz = mp[2]*p[2]; 00467 const RealP nmx = -mp[0]; 00468 const RealP nmy = -mp[1]; 00469 return Inertia_( myy+mzz, mxx+mzz, mxx+myy, 00470 nmx*p[1], nmx*p[2], nmy*p[2] ); 00471 } 00472 00478 00479 00482 inline static Inertia_ sphere(const RealP& r); 00483 00486 inline static Inertia_ cylinderAlongZ(const RealP& r, const RealP& hz); 00487 00490 inline static Inertia_ cylinderAlongY(const RealP& r, const RealP& hy); 00491 00494 inline static Inertia_ cylinderAlongX(const RealP& r, const RealP& hx); 00495 00499 inline static Inertia_ brick(const RealP& hx, const RealP& hy, const RealP& hz); 00500 00502 inline static Inertia_ brick(const Vec3P& halfLengths); 00503 00505 inline static Inertia_ ellipsoid(const RealP& hx, const RealP& hy, const RealP& hz); 00506 00508 inline static Inertia_ ellipsoid(const Vec3P& halfLengths); 00509 00511 00512 protected: 00513 // Reinterpret this Inertia matrix as a UnitInertia matrix, that is, as the 00514 // inertia of something with unit mass. This is useful in implementing 00515 // methods of the UnitInertia class in terms of Inertia methods. Be sure you 00516 // know that this is a unit-mass inertia! 00517 const UnitInertia_<P>& getAsUnitInertia() const 00518 { return *static_cast<const UnitInertia_<P>*>(this); } 00519 UnitInertia_<P>& updAsUnitInertia() 00520 { return *static_cast<UnitInertia_<P>*>(this); } 00521 00522 // If error checking is enabled (only in Debug mode), this 00523 // method will run some tests on the current contents of this Inertia 00524 // matrix and throw an error message if it is not valid. This should be 00525 // the same set of tests as run by the isValidInertiaMatrix() method above. 00526 void errChk(const char* methodName) const { 00527 #ifndef NDEBUG 00528 SimTK_ERRCHK(!isNaN(), methodName, 00529 "Inertia matrix contains a NaN."); 00530 00531 const Vec3P& d = I_OF_F.getDiag(); // moments 00532 const Vec3P& p = I_OF_F.getLower(); // products 00533 const RealP Ixx = d[0], Iyy = d[1], Izz = d[2]; 00534 const RealP Ixy = p[0], Ixz = p[1], Iyz = p[2]; 00535 00536 SimTK_ERRCHK3(d >= -SignificantReal, methodName, 00537 "Diagonals of an Inertia matrix must be nonnegative; got %g,%g,%g.", 00538 (double)Ixx,(double)Iyy,(double)Izz); 00539 00540 // TODO: This is looser than it should be as a workaround for distorted 00541 // rotation matrices that were produced by an 11,000 body chain that 00542 // Sam Flores encountered. 00543 const RealP Slop = std::max(d.sum(),RealP(1)) 00544 * std::sqrt(NTraits<P>::getEps()); 00545 00546 SimTK_ERRCHK3( Ixx+Iyy+Slop>=Izz 00547 && Ixx+Izz+Slop>=Iyy 00548 && Iyy+Izz+Slop>=Ixx, 00549 methodName, 00550 "Diagonals of an Inertia matrix must satisfy the triangle " 00551 "inequality; got %g,%g,%g.", 00552 (double)Ixx,(double)Iyy,(double)Izz); 00553 00554 // Thanks to Paul Mitiguy for this condition on products of inertia. 00555 SimTK_ERRCHK( Ixx+Slop>=std::abs(2*Iyz) 00556 && Iyy+Slop>=std::abs(2*Ixz) 00557 && Izz+Slop>=std::abs(2*Ixy), 00558 methodName, 00559 "The magnitude of a product of inertia was too large to be physical."); 00560 #endif 00561 } 00562 00563 // Inertia expressed in frame F and about F's origin OF. Note that frame F 00564 // is implicit here; all we actually have are the inertia scalars. 00565 SymMat33P I_OF_F; 00566 }; 00567 00572 template <class P> inline Inertia_<P> 00573 operator+(const Inertia_<P>& l, const Inertia_<P>& r) 00574 { return Inertia_<P>(l) += r; } 00575 00581 template <class P> inline Inertia_<P> 00582 operator-(const Inertia_<P>& l, const Inertia_<P>& r) 00583 { return Inertia_<P>(l) -= r; } 00584 00587 template <class P> inline Inertia_<P> 00588 operator*(const Inertia_<P>& i, const P& r) 00589 { return Inertia_<P>(i) *= r; } 00590 00593 template <class P> inline Inertia_<P> 00594 operator*(const P& r, const Inertia_<P>& i) 00595 { return Inertia_<P>(i) *= r; } 00596 00597 00601 template <class P> inline Inertia_<P> 00602 operator*(const Inertia_<P>& i, int r) 00603 { return Inertia_<P>(i) *= P(r); } 00604 00608 template <class P> inline Inertia_<P> 00609 operator*(int r, const Inertia_<P>& i) 00610 { return Inertia_<P>(i) *= P(r); } 00611 00615 template <class P> inline Inertia_<P> 00616 operator/(const Inertia_<P>& i, const P& r) 00617 { return Inertia_<P>(i) /= r; } 00618 00622 template <class P> inline Inertia_<P> 00623 operator/(const Inertia_<P>& i, int r) 00624 { return Inertia_<P>(i) /= P(r); } 00625 00629 template <class P> inline Vec<3,P> 00630 operator*(const Inertia_<P>& I, const Vec<3,P>& w) 00631 { return I.asSymMat33() * w; } 00632 00637 template <class P> inline bool 00638 operator==(const Inertia_<P>& i1, const Inertia_<P>& i2) 00639 { return i1.asSymMat33() == i2.asSymMat33(); } 00640 00644 template <class P> inline std::ostream& 00645 operator<<(std::ostream& o, const Inertia_<P>& inertia) 00646 { return o << inertia.toMat33(); } 00647 00648 00649 // ----------------------------------------------------------------------------- 00650 // UNIT INERTIA MATRIX 00651 // ----------------------------------------------------------------------------- 00672 template <class P> 00673 class SimTK_SimTKCOMMON_EXPORT UnitInertia_ : public Inertia_<P> { 00674 typedef P RealP; 00675 typedef Vec<3,P> Vec3P; 00676 typedef SymMat<3,P> SymMat33P; 00677 typedef Mat<3,3,P> Mat33P; 00678 typedef Rotation_<P> RotationP; 00679 typedef Inertia_<P> InertiaP; 00680 public: 00683 UnitInertia_() {} 00684 00685 // Default copy constructor, copy assignment, destructor. 00686 00690 explicit UnitInertia_(const RealP& moment) : InertiaP(moment) {} 00691 00696 explicit UnitInertia_(const Vec3P& moments, const Vec3P& products=Vec3P(0)) 00697 : InertiaP(moments,products) {} 00698 00700 UnitInertia_(const RealP& xx, const RealP& yy, const RealP& zz) 00701 : InertiaP(xx,yy,zz) {} 00702 00705 UnitInertia_(const RealP& xx, const RealP& yy, const RealP& zz, 00706 const RealP& xy, const RealP& xz, const RealP& yz) 00707 : InertiaP(xx,yy,zz,xy,xz,yz) {} 00708 00711 explicit UnitInertia_(const SymMat33P& m) : InertiaP(m) {} 00712 00716 explicit UnitInertia_(const Mat33P& m) : InertiaP(m) {} 00717 00722 explicit UnitInertia_(const Inertia_<P>& I) : InertiaP(I) {} 00723 00727 UnitInertia_& setUnitInertia(const RealP& xx, const RealP& yy, const RealP& zz) 00728 { InertiaP::setInertia(xx,yy,zz); return *this; } 00729 00732 UnitInertia_& setUnitInertia(const Vec3P& moments, const Vec3P& products=Vec3P(0)) 00733 { InertiaP::setInertia(moments,products); return *this; } 00734 00740 UnitInertia_& setUnitInertia(const RealP& xx, const RealP& yy, const RealP& zz, 00741 const RealP& xy, const RealP& xz, const RealP& yz) 00742 { InertiaP::setInertia(xx,yy,zz,xy,xz,yz); return *this; } 00743 00744 00745 // No +=, -=, etc. operators because those don't result in a UnitInertia 00746 // matrix. The parent class ones are suppressed below. 00747 00757 UnitInertia_ shiftToCentroid(const Vec3P& CF) const 00758 { UnitInertia_ G(*this); 00759 G.Inertia_<P>::operator-=(pointMassAt(CF)); 00760 return G; } 00761 00774 UnitInertia_& shiftToCentroidInPlace(const Vec3P& CF) 00775 { InertiaP::operator-=(pointMassAt(CF)); 00776 return *this; } 00777 00785 UnitInertia_ shiftFromCentroid(const Vec3P& p) const 00786 { UnitInertia_ G(*this); 00787 G.Inertia_<P>::operator+=(pointMassAt(p)); 00788 return G; } 00789 00798 UnitInertia_& shiftFromCentroidInPlace(const Vec3P& p) 00799 { InertiaP::operator+=(pointMassAt(p)); 00800 return *this; } 00801 00812 UnitInertia_ reexpress(const Rotation_<P>& R_FB) const 00813 { return UnitInertia_((~R_FB).reexpressSymMat33(this->I_OF_F)); } 00814 00817 UnitInertia_ reexpress(const InverseRotation_<P>& R_FB) const 00818 { return UnitInertia_((~R_FB).reexpressSymMat33(this->I_OF_F)); } 00819 00824 UnitInertia_& reexpressInPlace(const Rotation_<P>& R_FB) 00825 { InertiaP::reexpressInPlace(R_FB); return *this; } 00826 00829 UnitInertia_& reexpressInPlace(const InverseRotation_<P>& R_FB) 00830 { InertiaP::reexpressInPlace(R_FB); return *this; } 00831 00832 00834 operator const SymMat33P&() const {return this->I_OF_F;} 00835 00839 const Inertia_<P>& asUnitInertia() const 00840 { return *static_cast<const Inertia_<P>*>(this); } 00841 00844 UnitInertia_& setFromUnitInertia(const Inertia_<P>& I) 00845 { Inertia_<P>::operator=(I); 00846 return *this; } 00847 00851 static bool isValidUnitInertiaMatrix(const SymMat33P& m) 00852 { return Inertia_<P>::isValidInertiaMatrix(m); } 00853 00860 00861 00864 static UnitInertia_ pointMassAtOrigin() {return UnitInertia_(0);} 00865 00870 static UnitInertia_ pointMassAt(const Vec3P& p) 00871 { return UnitInertia_(crossMatSq(p)); } 00872 00875 static UnitInertia_ sphere(const RealP& r) {return UnitInertia_(RealP(0.4)*r*r);} 00876 00879 static UnitInertia_ cylinderAlongZ(const RealP& r, const RealP& hz) { 00880 const RealP Ixx = (r*r)/4 + (hz*hz)/3; 00881 return UnitInertia_(Ixx,Ixx,(r*r)/2); 00882 } 00883 00886 static UnitInertia_ cylinderAlongY(const RealP& r, const RealP& hy) { 00887 const RealP Ixx = (r*r)/4 + (hy*hy)/3; 00888 return UnitInertia_(Ixx,(r*r)/2,Ixx); 00889 } 00890 00893 static UnitInertia_ cylinderAlongX(const RealP& r, const RealP& hx) { 00894 const RealP Iyy = (r*r)/4 + (hx*hx)/3; 00895 return UnitInertia_((r*r)/2,Iyy,Iyy); 00896 } 00897 00901 static UnitInertia_ brick(const RealP& hx, const RealP& hy, const RealP& hz) { 00902 const RealP oo3 = RealP(1)/RealP(3); 00903 const RealP hx2=hx*hx, hy2=hy*hy, hz2=hz*hz; 00904 return UnitInertia_(oo3*(hy2+hz2), oo3*(hx2+hz2), oo3*(hx2+hy2)); 00905 } 00906 00908 static UnitInertia_ brick(const Vec3P& halfLengths) 00909 { return brick(halfLengths[0],halfLengths[1],halfLengths[2]); } 00910 00912 static UnitInertia_ ellipsoid(const RealP& hx, const RealP& hy, const RealP& hz) { 00913 const RealP hx2=hx*hx, hy2=hy*hy, hz2=hz*hz; 00914 return UnitInertia_((hy2+hz2)/5, (hx2+hz2)/5, (hx2+hy2)/5); 00915 } 00916 00918 static UnitInertia_ ellipsoid(const Vec3P& halfLengths) 00919 { return ellipsoid(halfLengths[0],halfLengths[1],halfLengths[2]); } 00920 00922 private: 00923 // Suppress Inertia_ methods which are not allowed for UnitInertia_. 00924 00925 // These kill all flavors of Inertia_::setInertia() and the 00926 // Inertia_ assignment ops. 00927 void setInertia() {} 00928 void operator+=(int) {} 00929 void operator-=(int) {} 00930 void operator*=(int) {} 00931 void operator/=(int) {} 00932 }; 00933 00934 // Implement Inertia methods which are pass-throughs to UnitInertia methods. 00935 00936 template <class P> inline Inertia_<P> Inertia_<P>:: 00937 sphere(const RealP& r) 00938 { return UnitInertia_<P>::sphere(r); } 00939 template <class P> inline Inertia_<P> Inertia_<P>:: 00940 cylinderAlongZ(const RealP& r, const RealP& hz) 00941 { return UnitInertia_<P>::cylinderAlongZ(r,hz); } 00942 template <class P> inline Inertia_<P> Inertia_<P>:: 00943 cylinderAlongY(const RealP& r, const RealP& hy) 00944 { return UnitInertia_<P>::cylinderAlongY(r,hy); } 00945 template <class P> inline Inertia_<P> Inertia_<P>:: 00946 cylinderAlongX(const RealP& r, const RealP& hx) 00947 { return UnitInertia_<P>::cylinderAlongX(r,hx); } 00948 template <class P> inline Inertia_<P> Inertia_<P>:: 00949 brick(const RealP& hx, const RealP& hy, const RealP& hz) 00950 { return UnitInertia_<P>::brick(hx,hy,hz); } 00951 template <class P> inline Inertia_<P> Inertia_<P>:: 00952 brick(const Vec3P& halfLengths) 00953 { return UnitInertia_<P>::brick(halfLengths); } 00954 template <class P> inline Inertia_<P> Inertia_<P>:: 00955 ellipsoid(const RealP& hx, const RealP& hy, const RealP& hz) 00956 { return UnitInertia_<P>::ellipsoid(hx,hy,hz); } 00957 template <class P> inline Inertia_<P> Inertia_<P>:: 00958 ellipsoid(const Vec3P& halfLengths) 00959 { return UnitInertia_<P>::ellipsoid(halfLengths); } 00960 00961 00962 // ----------------------------------------------------------------------------- 00963 // SPATIAL INERTIA MATRIX 00964 // ----------------------------------------------------------------------------- 00996 template <class P> 00997 class SimTK_SimTKCOMMON_EXPORT SpatialInertia_ { 00998 typedef P RealP; 00999 typedef Vec<3,P> Vec3P; 01000 typedef UnitInertia_<P> UnitInertiaP; 01001 typedef Mat<3,3,P> Mat33P; 01002 typedef Vec<2, Vec3P> SpatialVecP; 01003 typedef Mat<2,2,Mat33P> SpatialMatP; 01004 typedef Rotation_<P> RotationP; 01005 typedef Transform_<P> TransformP; 01006 typedef Inertia_<P> InertiaP; 01007 public: 01009 SpatialInertia_() 01010 : m(nanP()), p(nanP()) {} // inertia is already NaN 01011 SpatialInertia_(RealP mass, const Vec3P& com, const UnitInertiaP& gyration) 01012 : m(mass), p(com), G(gyration) {} 01013 01014 // default copy constructor, copy assignment, destructor 01015 01016 SpatialInertia_& setMass(RealP mass) 01017 { SimTK_ERRCHK1(mass >= 0, "SpatialInertia::setMass()", 01018 "Negative mass %g is illegal.", (double)mass); 01019 m=mass; return *this; } 01020 SpatialInertia_& setMassCenter(const Vec3P& com) 01021 { p=com; return *this;} 01022 SpatialInertia_& setUnitInertia(const UnitInertiaP& gyration) 01023 { G=gyration; return *this; } 01024 01025 RealP getMass() const {return m;} 01026 const Vec3P& getMassCenter() const {return p;} 01027 const UnitInertiaP& getUnitInertia() const {return G;} 01028 01031 Vec3P calcMassMoment() const {return m*p;} 01032 01035 InertiaP calcInertia() const {return m*G;} 01036 01041 SpatialInertia_& operator+=(const SpatialInertia_& src) { 01042 SimTK_ERRCHK(m+src.m != 0, "SpatialInertia::operator+=()", 01043 "The combined mass cannot be zero."); 01044 const RealP mtot = m+src.m, oomtot = 1/mtot; // ~11 flops 01045 p = oomtot*(calcMassMoment() + src.calcMassMoment()); // 10 flops 01046 G.setFromUnitInertia(oomtot*(calcInertia()+src.calcInertia())); // 19 flops 01047 m = mtot; // must do this last 01048 return *this; 01049 } 01050 01055 SpatialInertia_& operator-=(const SpatialInertia_& src) { 01056 SimTK_ERRCHK(m != src.m, "SpatialInertia::operator-=()", 01057 "The combined mass cannot be zero."); 01058 const RealP mtot = m-src.m, oomtot = 1/mtot; // ~11 flops 01059 p = oomtot*(calcMassMoment() - src.calcMassMoment()); // 10 flops 01060 G.setFromUnitInertia(oomtot*(calcInertia()-src.calcInertia())); // 19 flops 01061 m = mtot; // must do this last 01062 return *this; 01063 } 01064 01067 SpatialInertia_& operator*=(const RealP& s) {m *= s; return *this;} 01068 01071 SpatialInertia_& operator/=(const RealP& s) {m /= s; return *this;} 01072 01075 SpatialVecP operator*(const SpatialVecP& v) const 01076 { return m*SpatialVecP(G*v[0]+p%v[1], v[1]-p%v[0]); } 01077 01083 SpatialInertia_ reexpress(const Rotation_<P>& R_FB) const 01084 { return SpatialInertia_(*this).reexpressInPlace(R_FB); } 01085 01088 SpatialInertia_ reexpress(const InverseRotation_<P>& R_FB) const 01089 { return SpatialInertia_(*this).reexpressInPlace(R_FB); } 01090 01095 SpatialInertia_& reexpressInPlace(const Rotation_<P>& R_FB) 01096 { p = (~R_FB)*p; G.reexpressInPlace(R_FB); return *this; } 01097 01100 SpatialInertia_& reexpressInPlace(const InverseRotation_<P>& R_FB) 01101 { p = (~R_FB)*p; G.reexpressInPlace(R_FB); return *this; } 01102 01107 SpatialInertia_ shift(const Vec3P& S) const 01108 { return SpatialInertia_(*this).shiftInPlace(S); } 01109 01114 SpatialInertia_& shiftInPlace(const Vec3P& S) { 01115 G.shiftToCentroidInPlace(p); // change to central inertia 01116 G.shiftFromCentroidInPlace(S); // now inertia is about S 01117 p -= S; // was p=com-OF, now want p'=com-(OF+S)=p-S 01118 return *this; 01119 } 01120 01129 SpatialInertia_ transform(const Transform_<P>& X_FB) const 01130 { return SpatialInertia_(*this).transformInPlace(X_FB); } 01131 01134 SpatialInertia_ transform(const InverseTransform_<P>& X_FB) const 01135 { return SpatialInertia_(*this).transformInPlace(X_FB); } 01136 01146 SpatialInertia_& transformInPlace(const Transform_<P>& X_FB) { 01147 shiftInPlace(X_FB.p()); // shift to the new origin OB. 01148 reexpressInPlace(X_FB.R()); // get everything in B 01149 return *this; 01150 } 01151 01154 SpatialInertia_& transformInPlace(const InverseTransform_<P>& X_FB) { 01155 shiftInPlace(X_FB.p()); // shift to the new origin OB. 01156 reexpressInPlace(X_FB.R()); // get everything in B 01157 return *this; 01158 } 01159 01160 const SpatialMatP toSpatialMat() const { 01161 Mat33P offDiag = crossMat(m*p); 01162 return SpatialMatP(m*G.toMat33(), offDiag, 01163 -offDiag, Mat33P(m)); 01164 } 01165 01166 private: 01167 RealP m; // mass of this rigid body F 01168 Vec3P p; // location of body's COM from OF, expressed in F 01169 UnitInertiaP G; // mass distribution; inertia is mass*gyration 01170 01171 static P nanP() {return NTraits<P>::getNaN();} 01172 }; 01173 01176 template <class P> inline SpatialInertia_<P> 01177 operator+(const SpatialInertia_<P>& l, const SpatialInertia_<P>& r) 01178 { return SpatialInertia_<P>(l) += r; } 01179 01183 template <class P> inline SpatialInertia_<P> 01184 operator-(const SpatialInertia_<P>& l, const SpatialInertia_<P>& r) 01185 { return SpatialInertia_<P>(l) -= r; } 01186 01187 01188 // ----------------------------------------------------------------------------- 01189 // ARTICULATED BODY INERTIA MATRIX 01190 // ----------------------------------------------------------------------------- 01237 template <class P> 01238 class ArticulatedInertia_ { 01239 typedef P RealP; 01240 typedef Vec<3,P> Vec3P; 01241 typedef UnitInertia_<P> UnitInertiaP; 01242 typedef Mat<3,3,P> Mat33P; 01243 typedef SymMat<3,P> SymMat33P; 01244 typedef Vec<2, Vec3P> SpatialVecP; 01245 typedef Mat<2,2,Mat33P> SpatialMatP; 01246 typedef Rotation_<P> RotationP; 01247 typedef Transform_<P> TransformP; 01248 typedef Inertia_<P> InertiaP; 01249 public: 01252 ArticulatedInertia_() {} 01254 ArticulatedInertia_(const SymMat33P& mass, const Mat33P& massMoment, const SymMat33P& inertia) 01255 : M(mass), J(inertia), F(massMoment) {} 01256 01259 explicit ArticulatedInertia_(const SpatialInertia_<P>& rbi) 01260 : M(rbi.getMass()), J(rbi.calcInertia()), F(crossMat(rbi.calcMassMoment())) {} 01261 01263 ArticulatedInertia_& setMass (const SymMat33P& mass) {M=mass; return *this;} 01265 ArticulatedInertia_& setMassMoment(const Mat33P& massMoment) {F=massMoment; return *this;} 01267 ArticulatedInertia_& setInertia (const SymMat33P& inertia) {J=inertia; return *this;} 01268 01270 const SymMat33P& getMass() const {return M;} 01272 const Mat33P& getMassMoment() const {return F;} 01274 const SymMat33P& getInertia() const {return J;} 01275 01276 // default destructor, copy constructor, copy assignment 01277 01280 ArticulatedInertia_& operator+=(const ArticulatedInertia_& src) 01281 { M+=src.M; J+=src.J; F+=src.F; return *this; } 01284 ArticulatedInertia_& operator-=(const ArticulatedInertia_& src) 01285 { M-=src.M; J-=src.J; F-=src.F; return *this; } 01286 01288 SpatialVecP operator*(const SpatialVecP& v) const 01289 { return SpatialVecP(J*v[0]+F*v[1], ~F*v[0]+M*v[1]); } 01290 01292 template <int N> 01293 Mat<2,N,Vec3P> operator*(const Mat<2,N,Vec3P>& m) const { 01294 Mat<2,N,Vec3P> res; 01295 for (int j=0; j < N; ++j) 01296 res.col(j) = (*this) * m.col(j); // above this*SpatialVec operator 01297 return res; 01298 } 01299 01307 SimTK_SimTKCOMMON_EXPORT ArticulatedInertia_ shift(const Vec3P& s) const; 01308 01311 SimTK_SimTKCOMMON_EXPORT ArticulatedInertia_& shiftInPlace(const Vec3P& s); 01312 01315 const SpatialMatP toSpatialMat() const { 01316 return SpatialMatP( Mat33P(J), F, 01317 ~F, Mat33P(M) ); 01318 } 01319 private: 01320 SymMat33P M; 01321 SymMat33P J; 01322 Mat33P F; 01323 }; 01324 01327 template <class P> inline ArticulatedInertia_<P> 01328 operator+(const ArticulatedInertia_<P>& l, const ArticulatedInertia_<P>& r) 01329 { return ArticulatedInertia_<P>(l) += r; } 01330 01334 template <class P> inline ArticulatedInertia_<P> 01335 operator-(const ArticulatedInertia_<P>& l, const ArticulatedInertia_<P>& r) 01336 { return ArticulatedInertia_<P>(l) -= r; } 01337 01338 01339 // ----------------------------------------------------------------------------- 01340 // MASS PROPERTIES 01341 // ----------------------------------------------------------------------------- 01354 template <class P> 01355 class SimTK_SimTKCOMMON_EXPORT MassProperties_ { 01356 typedef P RealP; 01357 typedef Vec<3,P> Vec3P; 01358 typedef UnitInertia_<P> UnitInertiaP; 01359 typedef Mat<3,3,P> Mat33P; 01360 typedef Mat<6,6,P> Mat66P; 01361 typedef SymMat<3,P> SymMat33P; 01362 typedef Mat<2,2,Mat33P> SpatialMatP; 01363 typedef Rotation_<P> RotationP; 01364 typedef Transform_<P> TransformP; 01365 typedef Inertia_<P> InertiaP; 01366 public: 01369 MassProperties_() { setMassProperties(0,Vec3P(0),UnitInertiaP()); } 01373 MassProperties_(const RealP& m, const Vec3P& com, const InertiaP& inertia) 01374 { setMassProperties(m,com,inertia); } 01377 MassProperties_(const RealP& m, const Vec3P& com, const UnitInertiaP& gyration) 01378 { setMassProperties(m,com,gyration); } 01379 01383 MassProperties_& setMassProperties(const RealP& m, const Vec3P& com, const InertiaP& inertia) { 01384 mass = m; 01385 comInB = com; 01386 if (m == 0) { 01387 SimTK_ASSERT(inertia.asSymMat33().getAsVec() == 0, "Mass is zero but inertia is nonzero"); 01388 unitInertia_OB_B = UnitInertiaP(0); 01389 } 01390 else { 01391 unitInertia_OB_B = UnitInertiaP(inertia*(1/m)); 01392 } 01393 return *this; 01394 } 01395 01398 MassProperties_& setMassProperties 01399 (const RealP& m, const Vec3P& com, const UnitInertiaP& gyration) 01400 { mass=m; comInB=com; unitInertia_OB_B=gyration; return *this; } 01401 01403 const RealP& getMass() const {return mass;} 01408 const Vec3P& getMassCenter() const {return comInB;} 01413 const UnitInertiaP& getUnitInertia() const {return unitInertia_OB_B;} 01419 const InertiaP calcInertia() const {return mass*unitInertia_OB_B;} 01424 const InertiaP getInertia() const {return calcInertia();} 01425 01429 InertiaP calcCentralInertia() const { 01430 return mass*unitInertia_OB_B - InertiaP(comInB, mass); 01431 } 01436 InertiaP calcShiftedInertia(const Vec3P& newOriginB) const { 01437 return calcCentralInertia() + InertiaP(newOriginB-comInB, mass); 01438 } 01443 InertiaP calcTransformedInertia(const TransformP& X_BC) const { 01444 return calcShiftedInertia(X_BC.p()).reexpress(X_BC.R()); 01445 } 01451 MassProperties_ calcShiftedMassProps(const Vec3P& newOriginB) const { 01452 return MassProperties_(mass, comInB-newOriginB, 01453 calcShiftedInertia(newOriginB)); 01454 } 01455 01465 MassProperties_ calcTransformedMassProps(const TransformP& X_BC) const { 01466 return MassProperties_(mass, ~X_BC*comInB, calcTransformedInertia(X_BC)); 01467 } 01468 01477 MassProperties_ reexpress(const RotationP& R_BC) const { 01478 return MassProperties_(mass, ~R_BC*comInB, unitInertia_OB_B.reexpress(R_BC)); 01479 } 01480 01484 bool isExactlyMassless() const { return mass==0; } 01490 bool isNearlyMassless(const RealP& tol=SignificantReal) const { 01491 return mass <= tol; 01492 } 01493 01497 bool isExactlyCentral() const { return comInB==Vec3P(0); } 01503 bool isNearlyCentral(const RealP& tol=SignificantReal) const { 01504 return comInB.normSqr() <= tol*tol; 01505 } 01506 01509 bool isNaN() const {return SimTK::isNaN(mass) || comInB.isNaN() || unitInertia_OB_B.isNaN();} 01514 bool isInf() const { 01515 if (isNaN()) return false; 01516 return SimTK::isInf(mass) || comInB.isInf() || unitInertia_OB_B.isInf(); 01517 } 01521 bool isFinite() const { 01522 return SimTK::isFinite(mass) && comInB.isFinite() && unitInertia_OB_B.isFinite(); 01523 } 01524 01528 SpatialMatP toSpatialMat() const { 01529 SpatialMatP M; 01530 M(0,0) = mass*unitInertia_OB_B.toMat33(); 01531 M(0,1) = mass*crossMat(comInB); 01532 M(1,0) = ~M(0,1); 01533 M(1,1) = mass; // a diagonal matrix 01534 return M; 01535 } 01536 01542 Mat66P toMat66() const { 01543 Mat66P M; 01544 M.template updSubMat<3,3>(0,0) = mass*unitInertia_OB_B.toMat33(); 01545 M.template updSubMat<3,3>(0,3) = mass*crossMat(comInB); 01546 M.template updSubMat<3,3>(3,0) = ~M.template getSubMat<3,3>(0,3); 01547 M.template updSubMat<3,3>(3,3) = mass; // a diagonal matrix 01548 return M; 01549 } 01550 01551 private: 01552 RealP mass; 01553 Vec3P comInB; // meas. from B origin, expr. in B 01554 UnitInertiaP unitInertia_OB_B; // about B origin, expr. in B 01555 }; 01556 01559 template <class P> static inline std::ostream& 01560 operator<<(std::ostream& o, const MassProperties_<P>& mp) { 01561 return o << "{ mass=" << mp.getMass() 01562 << "\n com=" << mp.getMassCenter() 01563 << "\n Ixx,yy,zz=" << mp.getUnitInertia().getMoments() 01564 << "\n Ixy,xz,yz=" << mp.getUnitInertia().getProducts() 01565 << "\n}\n"; 01566 } 01567 01568 } // namespace SimTK 01569 01570 #endif // SimTK_SIMMATRIX_MASS_PROPERTIES_H_