Simbody
|
00001 #ifndef SimTK_SIMMATRIX_MASS_PROPERTIES_H_ 00002 #define SimTK_SIMMATRIX_MASS_PROPERTIES_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTK Simmatrix(tm) * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core 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. * 00011 * * 00012 * Portions copyright (c) 2005-11 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00041 #include "SimTKcommon/Scalar.h" 00042 #include "SimTKcommon/SmallMatrix.h" 00043 #include "SimTKcommon/Orientation.h" 00044 00045 #include <iostream> 00046 00047 namespace SimTK { 00058 typedef Vec<2, Vec3> SpatialVec; 00061 typedef Vec<2, Vec<3,float> > fSpatialVec; 00064 typedef Vec<2, Vec<3,double> > dSpatialVec; 00065 00068 typedef Row<2, Row3> SpatialRow; 00071 typedef Row<2, Row<3,float> > fSpatialRow; 00074 typedef Row<2, Row<3,double> > dSpatialRow; 00075 00080 typedef Mat<2,2, Mat33> SpatialMat; 00083 typedef Mat<2,2, Mat<3,3,float> > fSpatialMat; 00086 typedef Mat<2,2, Mat<3,3,double> > dSpatialMat; 00087 00088 // These are templatized by precision (float or double). 00089 template <class P> class UnitInertia_; 00090 template <class P> class Inertia_; 00091 template <class P> class SpatialInertia_; 00092 template <class P> class ArticulatedInertia_; 00093 template <class P> class MassProperties_; 00094 00095 // The "no trailing underscore" typedefs use whatever the 00096 // compile-time precision is set to. 00097 00099 typedef UnitInertia_<Real> UnitInertia; 00101 typedef UnitInertia_<float> fUnitInertia; 00103 typedef UnitInertia_<double> dUnitInertia; 00104 00106 typedef Inertia_<Real> Inertia; 00108 typedef Inertia_<float> fInertia; 00110 typedef Inertia_<double> dInertia; 00111 00113 typedef MassProperties_<Real> MassProperties; 00115 typedef MassProperties_<float> fMassProperties; 00117 typedef MassProperties_<double> dMassProperties; 00118 00120 typedef SpatialInertia_<Real> SpatialInertia; 00122 typedef SpatialInertia_<float> fSpatialInertia; 00124 typedef SpatialInertia_<double> dSpatialInertia; 00125 00127 typedef ArticulatedInertia_<Real> ArticulatedInertia; 00129 typedef ArticulatedInertia_<float> fArticulatedInertia; 00131 typedef ArticulatedInertia_<double> dArticulatedInertia; 00132 00134 typedef UnitInertia Gyration; 00135 00136 // ----------------------------------------------------------------------------- 00137 // INERTIA MATRIX 00138 // ----------------------------------------------------------------------------- 00200 template <class P> 00201 class SimTK_SimTKCOMMON_EXPORT Inertia_ { 00202 typedef P RealP; 00203 typedef Vec<3,P> Vec3P; 00204 typedef SymMat<3,P> SymMat33P; 00205 typedef Mat<3,3,P> Mat33P; 00206 typedef Rotation_<P> RotationP; 00207 public: 00210 Inertia_() : I_OF_F(NTraits<P>::getNaN()) {} 00211 00212 // Default copy constructor, copy assignment, destructor. 00213 00220 explicit Inertia_(const RealP& moment) : I_OF_F(moment) 00221 { errChk("Inertia::Inertia(moment)"); } 00222 00226 Inertia_(const Vec3P& p, const RealP& mass) : I_OF_F(pointMassAt(p,mass)) {} 00227 00232 explicit Inertia_(const Vec3P& moments, const Vec3P& products=Vec3P(0)) 00233 { I_OF_F.updDiag() = moments; 00234 I_OF_F.updLower() = products; 00235 errChk("Inertia::Inertia(moments,products)"); } 00236 00238 Inertia_(const RealP& xx, const RealP& yy, const RealP& zz) 00239 { I_OF_F = SymMat33P(xx, 00240 0, yy, 00241 0, 0, zz); 00242 errChk("Inertia::setInertia(xx,yy,zz)"); } 00243 00246 Inertia_(const RealP& xx, const RealP& yy, const RealP& zz, 00247 const RealP& xy, const RealP& xz, const RealP& yz) 00248 { I_OF_F = SymMat33P(xx, 00249 xy, yy, 00250 xz, yz, zz); 00251 errChk("Inertia::setInertia(xx,yy,zz,xy,xz,yz)"); } 00252 00255 explicit Inertia_(const SymMat33P& I) : I_OF_F(I) 00256 { errChk("Inertia::Inertia(SymMat33)"); } 00257 00261 explicit Inertia_(const Mat33P& m) 00262 { SimTK_ERRCHK(m.isNumericallySymmetric(), 00263 "Inertia(Mat33)", "The supplied matrix was not symmetric."); 00264 I_OF_F = SymMat33P(m); 00265 errChk("Inertia(Mat33)"); } 00266 00267 00270 Inertia_& setInertia(const RealP& xx, const RealP& yy, const RealP& zz) { 00271 I_OF_F = RealP(0); I_OF_F(0,0) = xx; I_OF_F(1,1) = yy; I_OF_F(2,2) = zz; 00272 errChk("Inertia::setInertia(xx,yy,zz)"); 00273 return *this; 00274 } 00275 00278 Inertia_& setInertia(const Vec3P& moments, const Vec3P& products=Vec3P(0)) { 00279 I_OF_F.updDiag() = moments; 00280 I_OF_F.updLower() = products; 00281 errChk("Inertia::setInertia(moments,products)"); 00282 return *this; 00283 } 00284 00290 Inertia_& setInertia(const RealP& xx, const RealP& yy, const RealP& zz, 00291 const RealP& xy, const RealP& xz, const RealP& yz) { 00292 setInertia(Vec3P(xx,yy,zz), Vec3P(xy,xz,yz)); 00293 errChk("Inertia::setInertia(xx,yy,zz,xy,xz,yz)"); 00294 return *this; 00295 } 00296 00297 00300 Inertia_& operator+=(const Inertia_& I) 00301 { I_OF_F += I.I_OF_F; 00302 errChk("Inertia::operator+=()"); 00303 return *this; } 00304 00307 Inertia_& operator-=(const Inertia_& I) 00308 { I_OF_F -= I.I_OF_F; 00309 errChk("Inertia::operator-=()"); 00310 return *this; } 00311 00313 Inertia_& operator*=(const P& s) {I_OF_F *= s; return *this;} 00314 00317 Inertia_& operator/=(const P& s) {I_OF_F /= s; return *this;} 00318 00328 Inertia_ shiftToMassCenter(const Vec3P& CF, const RealP& mass) const 00329 { Inertia_ I(*this); I -= pointMassAt(CF, mass); 00330 I.errChk("Inertia::shiftToMassCenter()"); 00331 return I; } 00332 00343 Inertia_& shiftToMassCenterInPlace(const Vec3P& CF, const RealP& mass) 00344 { (*this) -= pointMassAt(CF, mass); 00345 errChk("Inertia::shiftToMassCenterInPlace()"); 00346 return *this; } 00347 00355 Inertia_ shiftFromMassCenter(const Vec3P& p, const RealP& mass) const 00356 { Inertia_ I(*this); I += pointMassAt(p, mass); 00357 I.errChk("Inertia::shiftFromMassCenter()"); 00358 return I; } 00359 00368 Inertia_& shiftFromMassCenterInPlace(const Vec3P& p, const RealP& mass) 00369 { (*this) += pointMassAt(p, mass); 00370 errChk("Inertia::shiftFromMassCenterInPlace()"); 00371 return *this; } 00372 00383 Inertia_ reexpress(const Rotation_<P>& R_FB) const 00384 { return Inertia_((~R_FB).reexpressSymMat33(I_OF_F)); } 00385 00388 Inertia_ reexpress(const InverseRotation_<P>& R_FB) const 00389 { return Inertia_((~R_FB).reexpressSymMat33(I_OF_F)); } 00390 00395 Inertia_& reexpressInPlace(const Rotation_<P>& R_FB) 00396 { I_OF_F = (~R_FB).reexpressSymMat33(I_OF_F); return *this; } 00397 00400 Inertia_& reexpressInPlace(const InverseRotation_<P>& R_FB) 00401 { I_OF_F = (~R_FB).reexpressSymMat33(I_OF_F); return *this; } 00402 00403 RealP trace() const {return I_OF_F.trace();} 00404 00406 operator const SymMat33P&() const {return I_OF_F;} 00407 00409 const SymMat33P& asSymMat33() const {return I_OF_F;} 00410 00413 Mat33P toMat33() const {return Mat33P(I_OF_F);} 00414 00416 const Vec3P& getMoments() const {return I_OF_F.getDiag();} 00419 const Vec3P& getProducts() const {return I_OF_F.getLower();} 00420 00421 bool isNaN() const {return I_OF_F.isNaN();} 00422 bool isInf() const {return I_OF_F.isInf();} 00423 bool isFinite() const {return I_OF_F.isFinite();} 00424 00428 bool isNumericallyEqual(const Inertia_<P>& other) const 00429 { return I_OF_F.isNumericallyEqual(other.I_OF_F); } 00430 00434 bool isNumericallyEqual(const Inertia_<P>& other, double tol) const 00435 { return I_OF_F.isNumericallyEqual(other.I_OF_F, tol); } 00436 00440 static bool isValidInertiaMatrix(const SymMat33P& m) { 00441 const RealP Slop = NTraits<P>::getSignificant(); 00442 if (m.isNaN()) return false; 00443 const Vec3P& d = m.diag(); 00444 if (!(d >= 0)) return false; // diagonals must be nonnegative 00445 if (!(d[0]+d[1]+Slop>=d[2] && d[0]+d[2]+Slop>=d[1] && d[1]+d[2]+Slop>=d[0])) 00446 return false; // must satisfy triangle inequality 00447 //TODO: what else? 00448 return true; 00449 } 00450 00453 static Inertia_ pointMassAtOrigin() {return Inertia_(0);} 00454 00459 static Inertia_ pointMassAt(const Vec3P& p, const RealP& m) { 00460 const Vec3P mp = m*p; // 3 flops 00461 const RealP mxx = mp[0]*p[0]; 00462 const RealP myy = mp[1]*p[1]; 00463 const RealP mzz = mp[2]*p[2]; 00464 const RealP nmx = -mp[0]; 00465 const RealP nmy = -mp[1]; 00466 return Inertia_( myy+mzz, mxx+mzz, mxx+myy, 00467 nmx*p[1], nmx*p[2], nmy*p[2] ); 00468 } 00469 00475 00476 00479 inline static Inertia_ sphere(const RealP& r); 00480 00483 inline static Inertia_ cylinderAlongZ(const RealP& r, const RealP& hz); 00484 00487 inline static Inertia_ cylinderAlongY(const RealP& r, const RealP& hy); 00488 00491 inline static Inertia_ cylinderAlongX(const RealP& r, const RealP& hx); 00492 00496 inline static Inertia_ brick(const RealP& hx, const RealP& hy, const RealP& hz); 00497 00499 inline static Inertia_ brick(const Vec3P& halfLengths); 00500 00502 inline static Inertia_ ellipsoid(const RealP& hx, const RealP& hy, const RealP& hz); 00503 00505 inline static Inertia_ ellipsoid(const Vec3P& halfLengths); 00506 00508 00509 protected: 00510 // Reinterpret this Inertia matrix as a UnitInertia matrix, that is, as the 00511 // inertia of something with unit mass. This is useful in implementing 00512 // methods of the UnitInertia class in terms of Inertia methods. Be sure you 00513 // know that this is a unit-mass inertia! 00514 const UnitInertia_<P>& getAsUnitInertia() const 00515 { return *reinterpret_cast<const UnitInertia_<P>*>(this); } 00516 UnitInertia_<P>& updAsUnitInertia() 00517 { return *reinterpret_cast<UnitInertia_<P>*>(this); } 00518 00519 // If error checking is enabled (typically only in Debug mode), this 00520 // method will run some tests on the current contents of this Inertia 00521 // matrix and throw an error message if it is not valid. This should be 00522 // the same set of tests as run by the isValidInertiaMatrix() method above. 00523 void errChk(const char* methodName) const { 00524 const RealP Slop = NTraits<P>::getSignificant(); 00525 SimTK_ERRCHK(!isNaN(), methodName, 00526 "Inertia matrix contains a NaN."); 00527 const Vec3P& d = I_OF_F.diag(); 00528 SimTK_ERRCHK3(d >= 0, methodName, 00529 "Diagonals of an Inertia matrix must be nonnegative; got %g,%g,%g.", 00530 (double)d[0],(double)d[1],(double)d[2]); 00531 SimTK_ERRCHK3(d[0]+d[1]+Slop>=d[2] && d[0]+d[2]+Slop>=d[1] && d[1]+d[2]+Slop>=d[0], 00532 methodName, 00533 "Diagonals of an Inertia matrix must satisfy the triangle " 00534 "inequality; got %g,%g,%g.", 00535 (double)d[0],(double)d[1],(double)d[2]); 00536 } 00537 00538 // Inertia expressed in frame F and about F's origin OF. Note that frame F 00539 // is implicit here; all we actually have are the inertia scalars. 00540 SymMat33P I_OF_F; 00541 }; 00542 00547 template <class P> inline Inertia_<P> 00548 operator+(const Inertia_<P>& l, const Inertia_<P>& r) 00549 { return Inertia_<P>(l) += r; } 00550 00556 template <class P> inline Inertia_<P> 00557 operator-(const Inertia_<P>& l, const Inertia_<P>& r) 00558 { return Inertia_<P>(l) -= r; } 00559 00562 template <class P> inline Inertia_<P> 00563 operator*(const Inertia_<P>& i, const P& r) 00564 { return Inertia_<P>(i) *= r; } 00565 00568 template <class P> inline Inertia_<P> 00569 operator*(const P& r, const Inertia_<P>& i) 00570 { return Inertia_<P>(i) *= r; } 00571 00572 00576 template <class P> inline Inertia_<P> 00577 operator*(const Inertia_<P>& i, int r) 00578 { return Inertia_<P>(i) *= P(r); } 00579 00583 template <class P> inline Inertia_<P> 00584 operator*(int r, const Inertia_<P>& i) 00585 { return Inertia_<P>(i) *= P(r); } 00586 00590 template <class P> inline Inertia_<P> 00591 operator/(const Inertia_<P>& i, const P& r) 00592 { return Inertia_<P>(i) /= r; } 00593 00597 template <class P> inline Inertia_<P> 00598 operator/(const Inertia_<P>& i, int r) 00599 { return Inertia_<P>(i) /= P(r); } 00600 00604 template <class P> inline Vec<3,P> 00605 operator*(const Inertia_<P>& I, const Vec<3,P>& w) 00606 { return I.asSymMat33() * w; } 00607 00612 template <class P> inline bool 00613 operator==(const Inertia_<P>& i1, const Inertia_<P>& i2) 00614 { return i1.asSymMat33() == i2.asSymMat33(); } 00615 00619 template <class P> inline std::ostream& 00620 operator<<(std::ostream& o, const Inertia_<P>& inertia) 00621 { return o << inertia.toMat33(); } 00622 00623 00624 // ----------------------------------------------------------------------------- 00625 // UNIT INERTIA MATRIX 00626 // ----------------------------------------------------------------------------- 00647 template <class P> 00648 class SimTK_SimTKCOMMON_EXPORT UnitInertia_ : public Inertia_<P> { 00649 typedef P RealP; 00650 typedef Vec<3,P> Vec3P; 00651 typedef SymMat<3,P> SymMat33P; 00652 typedef Mat<3,3,P> Mat33P; 00653 typedef Rotation_<P> RotationP; 00654 typedef Inertia_<P> InertiaP; 00655 public: 00658 UnitInertia_() {} 00659 00660 // Default copy constructor, copy assignment, destructor. 00661 00665 explicit UnitInertia_(const RealP& moment) : InertiaP(moment) {} 00666 00671 explicit UnitInertia_(const Vec3P& moments, const Vec3P& products=Vec3P(0)) 00672 : InertiaP(moments,products) {} 00673 00675 UnitInertia_(const RealP& xx, const RealP& yy, const RealP& zz) 00676 : InertiaP(xx,yy,zz) {} 00677 00680 UnitInertia_(const RealP& xx, const RealP& yy, const RealP& zz, 00681 const RealP& xy, const RealP& xz, const RealP& yz) 00682 : InertiaP(xx,yy,zz,xy,xz,yz) {} 00683 00686 explicit UnitInertia_(const SymMat33P& m) : InertiaP(m) {} 00687 00691 explicit UnitInertia_(const Mat33P& m) : InertiaP(m) {} 00692 00697 explicit UnitInertia_(const Inertia_<P>& I) : InertiaP(I) {} 00698 00702 UnitInertia_& setUnitInertia(const RealP& xx, const RealP& yy, const RealP& zz) 00703 { InertiaP::setInertia(xx,yy,zz); return *this; } 00704 00707 UnitInertia_& setUnitInertia(const Vec3P& moments, const Vec3P& products=Vec3P(0)) 00708 { InertiaP::setInertia(moments,products); return *this; } 00709 00715 UnitInertia_& setUnitInertia(const RealP& xx, const RealP& yy, const RealP& zz, 00716 const RealP& xy, const RealP& xz, const RealP& yz) 00717 { InertiaP::setInertia(xx,yy,zz,xy,xz,yz); return *this; } 00718 00719 00720 // No +=, -=, etc. operators because those don't result in a UnitInertia 00721 // matrix. The parent class ones are suppressed below. 00722 00732 UnitInertia_ shiftToCentroid(const Vec3P& CF) const 00733 { UnitInertia_ G(*this); 00734 G.Inertia_<P>::operator-=(pointMassAt(CF)); 00735 return G; } 00736 00749 UnitInertia_& shiftToCentroidInPlace(const Vec3P& CF) 00750 { InertiaP::operator-=(pointMassAt(CF)); 00751 return *this; } 00752 00760 UnitInertia_ shiftFromCentroid(const Vec3P& p) const 00761 { UnitInertia_ G(*this); 00762 G.Inertia_<P>::operator+=(pointMassAt(p)); 00763 return G; } 00764 00773 UnitInertia_& shiftFromCentroidInPlace(const Vec3P& p) 00774 { InertiaP::operator+=(pointMassAt(p)); 00775 return *this; } 00776 00787 UnitInertia_ reexpress(const Rotation_<P>& R_FB) const 00788 { return UnitInertia_((~R_FB).reexpressSymMat33(this->I_OF_F)); } 00789 00792 UnitInertia_ reexpress(const InverseRotation_<P>& R_FB) const 00793 { return UnitInertia_((~R_FB).reexpressSymMat33(this->I_OF_F)); } 00794 00799 UnitInertia_& reexpressInPlace(const Rotation_<P>& R_FB) 00800 { InertiaP::reexpressInPlace(R_FB); return *this; } 00801 00804 UnitInertia_& reexpressInPlace(const InverseRotation_<P>& R_FB) 00805 { InertiaP::reexpressInPlace(R_FB); return *this; } 00806 00807 00809 operator const SymMat33P&() const {return this->I_OF_F;} 00810 00814 const Inertia_<P>& asUnitInertia() const 00815 { return *static_cast<const Inertia_<P>*>(this); } 00816 00819 UnitInertia_& setFromUnitInertia(const Inertia_<P>& I) 00820 { Inertia_<P>::operator=(I); 00821 return *this; } 00822 00826 static bool isValidUnitInertiaMatrix(const SymMat33P& m) 00827 { return isValidInertiaMatrix(m); } 00828 00835 00836 00839 static UnitInertia_ pointMassAtOrigin() {return UnitInertia_(0);} 00840 00845 static UnitInertia_ pointMassAt(const Vec3P& p) 00846 { return UnitInertia_(crossMatSq(p)); } 00847 00850 static UnitInertia_ sphere(const RealP& r) {return UnitInertia_(RealP(0.4)*r*r);} 00851 00854 static UnitInertia_ cylinderAlongZ(const RealP& r, const RealP& hz) { 00855 const RealP Ixx = (r*r)/4 + (hz*hz)/3; 00856 return UnitInertia_(Ixx,Ixx,(r*r)/2); 00857 } 00858 00861 static UnitInertia_ cylinderAlongY(const RealP& r, const RealP& hy) { 00862 const RealP Ixx = (r*r)/4 + (hy*hy)/3; 00863 return UnitInertia_(Ixx,(r*r)/2,Ixx); 00864 } 00865 00868 static UnitInertia_ cylinderAlongX(const RealP& r, const RealP& hx) { 00869 const RealP Iyy = (r*r)/4 + (hx*hx)/3; 00870 return UnitInertia_((r*r)/2,Iyy,Iyy); 00871 } 00872 00876 static UnitInertia_ brick(const RealP& hx, const RealP& hy, const RealP& hz) { 00877 const RealP oo3 = RealP(1)/RealP(3); 00878 const RealP hx2=hx*hx, hy2=hy*hy, hz2=hz*hz; 00879 return UnitInertia_(oo3*(hy2+hz2), oo3*(hx2+hz2), oo3*(hx2+hy2)); 00880 } 00881 00883 static UnitInertia_ brick(const Vec3P& halfLengths) 00884 { return brick(halfLengths[0],halfLengths[1],halfLengths[2]); } 00885 00887 static UnitInertia_ ellipsoid(const RealP& hx, const RealP& hy, const RealP& hz) { 00888 const RealP hx2=hx*hx, hy2=hy*hy, hz2=hz*hz; 00889 return UnitInertia_((hy2+hz2)/5, (hx2+hz2)/5, (hx2+hy2)/5); 00890 } 00891 00893 static UnitInertia_ ellipsoid(const Vec3P& halfLengths) 00894 { return ellipsoid(halfLengths[0],halfLengths[1],halfLengths[2]); } 00895 00897 private: 00898 // Suppress Inertia_ methods which are not allowed for UnitInertia_. 00899 00900 // These kill all flavors of Inertia_::setInertia() and the 00901 // Inertia_ assignment ops. 00902 void setInertia() {} 00903 void operator+=(int) {} 00904 void operator-=(int) {} 00905 void operator*=(int) {} 00906 void operator/=(int) {} 00907 }; 00908 00909 // Implement Inertia methods which are pass-throughs to UnitInertia methods. 00910 00911 template <class P> inline Inertia_<P> Inertia_<P>:: 00912 sphere(const RealP& r) 00913 { return UnitInertia_<P>::sphere(r); } 00914 template <class P> inline Inertia_<P> Inertia_<P>:: 00915 cylinderAlongZ(const RealP& r, const RealP& hz) 00916 { return UnitInertia_<P>::cylinderAlongZ(r,hz); } 00917 template <class P> inline Inertia_<P> Inertia_<P>:: 00918 cylinderAlongY(const RealP& r, const RealP& hy) 00919 { return UnitInertia_<P>::cylinderAlongY(r,hy); } 00920 template <class P> inline Inertia_<P> Inertia_<P>:: 00921 cylinderAlongX(const RealP& r, const RealP& hx) 00922 { return UnitInertia_<P>::cylinderAlongX(r,hx); } 00923 template <class P> inline Inertia_<P> Inertia_<P>:: 00924 brick(const RealP& hx, const RealP& hy, const RealP& hz) 00925 { return UnitInertia_<P>::brick(hx,hy,hz); } 00926 template <class P> inline Inertia_<P> Inertia_<P>:: 00927 brick(const Vec3P& halfLengths) 00928 { return UnitInertia_<P>::brick(halfLengths); } 00929 template <class P> inline Inertia_<P> Inertia_<P>:: 00930 ellipsoid(const RealP& hx, const RealP& hy, const RealP& hz) 00931 { return UnitInertia_<P>::ellipsoid(hx,hy,hz); } 00932 template <class P> inline Inertia_<P> Inertia_<P>:: 00933 ellipsoid(const Vec3P& halfLengths) 00934 { return UnitInertia_<P>::ellipsoid(halfLengths); } 00935 00936 00937 // ----------------------------------------------------------------------------- 00938 // SPATIAL INERTIA MATRIX 00939 // ----------------------------------------------------------------------------- 00971 template <class P> 00972 class SimTK_SimTKCOMMON_EXPORT SpatialInertia_ { 00973 typedef P RealP; 00974 typedef Vec<3,P> Vec3P; 00975 typedef UnitInertia_<P> UnitInertiaP; 00976 typedef Mat<3,3,P> Mat33P; 00977 typedef Rotation_<P> RotationP; 00978 typedef Transform_<P> TransformP; 00979 typedef Inertia_<P> InertiaP; 00980 public: 00982 SpatialInertia_() 00983 : m(nanP()), p(nanP()) {} // inertia is already NaN 00984 SpatialInertia_(RealP mass, const Vec3P& com, const UnitInertiaP& gyration) 00985 : m(mass), p(com), G(gyration) {} 00986 00987 // default copy constructor, copy assignment, destructor 00988 00989 SpatialInertia_& setMass(RealP mass) 00990 { SimTK_ERRCHK1(mass >= 0, "SpatialInertia::setMass()", 00991 "Negative mass %g is illegal.", (double)mass); 00992 m=mass; return *this; } 00993 SpatialInertia_& setMassCenter(const Vec3P& com) 00994 { p=com; return *this;} 00995 SpatialInertia_& setUnitInertia(const UnitInertiaP& gyration) 00996 { G=gyration; return *this; } 00997 00998 RealP getMass() const {return m;} 00999 const Vec3P& getMassCenter() const {return p;} 01000 const UnitInertiaP& getUnitInertia() const {return G;} 01001 01004 Vec3P calcMassMoment() const {return m*p;} 01005 01008 InertiaP calcInertia() const {return m*G;} 01009 01014 SpatialInertia_& operator+=(const SpatialInertia_& src) { 01015 SimTK_ERRCHK(m+src.m != 0, "SpatialInertia::operator+=()", 01016 "The combined mass cannot be zero."); 01017 const RealP mtot = m+src.m, oomtot = 1/mtot; // ~11 flops 01018 p = oomtot*(calcMassMoment() + src.calcMassMoment()); // 10 flops 01019 G.setFromUnitInertia(oomtot*(calcInertia()+src.calcInertia())); // 19 flops 01020 m = mtot; // must do this last 01021 return *this; 01022 } 01023 01028 SpatialInertia_& operator-=(const SpatialInertia_& src) { 01029 SimTK_ERRCHK(m != src.m, "SpatialInertia::operator-=()", 01030 "The combined mass cannot be zero."); 01031 const RealP mtot = m-src.m, oomtot = 1/mtot; // ~11 flops 01032 p = oomtot*(calcMassMoment() - src.calcMassMoment()); // 10 flops 01033 G.setFromUnitInertia(oomtot*(calcInertia()-src.calcInertia())); // 19 flops 01034 m = mtot; // must do this last 01035 return *this; 01036 } 01037 01040 SpatialInertia_& operator*=(const RealP& s) {m *= s; return *this;} 01041 01044 SpatialInertia_& operator/=(const RealP& s) {m /= s; return *this;} 01045 01051 SpatialInertia_ reexpress(const Rotation_<P>& R_FB) const 01052 { return SpatialInertia_(*this).reexpressInPlace(R_FB); } 01053 01056 SpatialInertia_ reexpress(const InverseRotation_<P>& R_FB) const 01057 { return SpatialInertia_(*this).reexpressInPlace(R_FB); } 01058 01063 SpatialInertia_& reexpressInPlace(const Rotation_<P>& R_FB) 01064 { p = (~R_FB)*p; G.reexpressInPlace(R_FB); return *this; } 01065 01068 SpatialInertia_& reexpressInPlace(const InverseRotation_<P>& R_FB) 01069 { p = (~R_FB)*p; G.reexpressInPlace(R_FB); return *this; } 01070 01075 SpatialInertia_ shift(const Vec3P& S) const 01076 { return SpatialInertia_(*this).shiftInPlace(S); } 01077 01082 SpatialInertia_& shiftInPlace(const Vec3P& S) { 01083 G.shiftToCentroidInPlace(p); // change to central inertia 01084 G.shiftFromCentroidInPlace(S); // now inertia is about S 01085 p -= S; // was p=com-OF, now want p'=com-(OF+S)=p-S 01086 return *this; 01087 } 01088 01097 SpatialInertia_ transform(const Transform_<P>& X_FB) const 01098 { return SpatialInertia_(*this).transformInPlace(X_FB); } 01099 01102 SpatialInertia_ transform(const InverseTransform_<P>& X_FB) const 01103 { return SpatialInertia_(*this).transformInPlace(X_FB); } 01104 01114 SpatialInertia_& transformInPlace(const Transform_<P>& X_FB) { 01115 shiftInPlace(X_FB.p()); // shift to the new origin OB. 01116 reexpressInPlace(X_FB.R()); // get everything in B 01117 return *this; 01118 } 01119 01122 SpatialInertia_& transformInPlace(const InverseTransform_<P>& X_FB) { 01123 shiftInPlace(X_FB.p()); // shift to the new origin OB. 01124 reexpressInPlace(X_FB.R()); // get everything in B 01125 return *this; 01126 } 01127 01128 private: 01129 RealP m; // mass of this rigid body F 01130 Vec3P p; // location of body's COM from OF, expressed in F 01131 UnitInertiaP G; // mass distribution; inertia is mass*gyration 01132 01133 static P nanP() {return NTraits<P>::getNaN();} 01134 }; 01135 01138 template <class P> inline SpatialInertia_<P> 01139 operator+(const SpatialInertia_<P>& l, const SpatialInertia_<P>& r) 01140 { return SpatialInertia_<P>(l) += r; } 01141 01145 template <class P> inline SpatialInertia_<P> 01146 operator-(const SpatialInertia_<P>& l, const SpatialInertia_<P>& r) 01147 { return SpatialInertia_<P>(l) -= r; } 01148 01149 01150 // ----------------------------------------------------------------------------- 01151 // ARTICULATED BODY INERTIA MATRIX 01152 // ----------------------------------------------------------------------------- 01199 template <class P> 01200 class ArticulatedInertia_ { 01201 typedef P RealP; 01202 typedef Vec<3,P> Vec3P; 01203 typedef UnitInertia_<P> UnitInertiaP; 01204 typedef Mat<3,3,P> Mat33P; 01205 typedef SymMat<3,P> SymMat33P; 01206 typedef Mat<2,2,Mat33P> SpatialMatP; 01207 typedef Rotation_<P> RotationP; 01208 typedef Transform_<P> TransformP; 01209 typedef Inertia_<P> InertiaP; 01210 public: 01211 ArticulatedInertia_() {} 01212 ArticulatedInertia_(const SymMat33P& mass, const Mat33P& massMoment, const SymMat33P& inertia) 01213 : M(mass), J(inertia), F(massMoment) {} 01214 01217 explicit ArticulatedInertia_(const SpatialInertia_<P>& rbi) 01218 : M(rbi.getMass()), J(rbi.calcInertia()), F(crossMat(rbi.calcMassMoment())) {} 01219 01220 ArticulatedInertia_& setMass (const SymMat33P& mass) {M=mass; return *this;} 01221 ArticulatedInertia_& setMassMoment(const Mat33P& massMoment) {F=massMoment; return *this;} 01222 ArticulatedInertia_& setInertia (const SymMat33P& inertia) {J=inertia; return *this;} 01223 01224 const SymMat33P& getMass() const {return M;} 01225 const Mat33P& getMassMoment() const {return F;} 01226 const SymMat33P& getInertia() const {return J;} 01227 01228 // default destructor, copy constructor, copy assignment 01229 01230 ArticulatedInertia_& operator+=(const ArticulatedInertia_& src) 01231 { M+=src.M; J+=src.J; F+=src.F; return *this; } 01232 ArticulatedInertia_& operator-=(const ArticulatedInertia_& src) 01233 { M-=src.M; J-=src.J; F-=src.F; return *this; } 01234 01242 SimTK_SimTKCOMMON_EXPORT ArticulatedInertia_ shift(const Vec3P& s) const; 01243 01246 SimTK_SimTKCOMMON_EXPORT ArticulatedInertia_& shiftInPlace(const Vec3P& s); 01247 01248 const SpatialMatP toSpatialMat() const { 01249 return SpatialMatP( Mat33P(J), F, 01250 ~F, Mat33P(M) ); 01251 } 01252 private: 01253 SymMat33P M; 01254 SymMat33P J; 01255 Mat33P F; 01256 }; 01257 01258 01259 // ----------------------------------------------------------------------------- 01260 // MASS PROPERTIES 01261 // ----------------------------------------------------------------------------- 01273 template <class P> 01274 class SimTK_SimTKCOMMON_EXPORT MassProperties_ { 01275 typedef P RealP; 01276 typedef Vec<3,P> Vec3P; 01277 typedef UnitInertia_<P> UnitInertiaP; 01278 typedef Mat<3,3,P> Mat33P; 01279 typedef Mat<6,6,P> Mat66P; 01280 typedef SymMat<3,P> SymMat33P; 01281 typedef Mat<2,2,Mat33P> SpatialMatP; 01282 typedef Rotation_<P> RotationP; 01283 typedef Transform_<P> TransformP; 01284 typedef Inertia_<P> InertiaP; 01285 public: 01288 MassProperties_() { setMassProperties(0,Vec3P(0),InertiaP()); } 01291 MassProperties_(const RealP& m, const Vec3P& com, const InertiaP& inertia) 01292 { setMassProperties(m,com,inertia); } 01296 MassProperties_(const RealP& m, const Vec3P& com, const UnitInertiaP& gyration) 01297 { setMassProperties(m,com,gyration); } 01298 01301 MassProperties_& setMassProperties 01302 (const RealP& m, const Vec3P& com, const InertiaP& inertia) 01303 { mass=m; comInB=com; inertia_OB_B=inertia; return *this; } 01304 01308 MassProperties_& setMassProperties 01309 (const RealP& m, const Vec3P& com, const UnitInertiaP& gyration) 01310 { mass=m; comInB=com; inertia_OB_B=m*gyration; return *this; } 01311 01313 const RealP& getMass() const { return mass; } 01318 const Vec3P& getMassCenter() const { return comInB; } 01323 const InertiaP& getInertia() const { return inertia_OB_B; } 01324 01328 InertiaP calcCentralInertia() const { 01329 return inertia_OB_B - InertiaP(comInB, mass); 01330 } 01335 InertiaP calcShiftedInertia(const Vec3P& newOriginB) const { 01336 return calcCentralInertia() + InertiaP(newOriginB-comInB, mass); 01337 } 01342 InertiaP calcTransformedInertia(const TransformP& X_BC) const { 01343 return calcShiftedInertia(X_BC.p()).reexpress(X_BC.R()); 01344 } 01350 MassProperties_ calcShiftedMassProps(const Vec3P& newOriginB) const { 01351 return MassProperties_(mass, comInB-newOriginB, 01352 calcShiftedInertia(newOriginB)); 01353 } 01354 01364 MassProperties_ calcTransformedMassProps(const TransformP& X_BC) const { 01365 return MassProperties_(mass, ~X_BC*comInB, calcTransformedInertia(X_BC)); 01366 } 01367 01376 MassProperties_ reexpress(const RotationP& R_BC) const { 01377 return MassProperties_(mass, ~R_BC*comInB, inertia_OB_B.reexpress(R_BC)); 01378 } 01379 01383 bool isExactlyMassless() const { return mass==0; } 01389 bool isNearlyMassless(const RealP& tol=SignificantReal) const { 01390 return mass <= tol; 01391 } 01392 01396 bool isExactlyCentral() const { return comInB==Vec3P(0); } 01402 bool isNearlyCentral(const RealP& tol=SignificantReal) const { 01403 return comInB.normSqr() <= tol*tol; 01404 } 01405 01408 bool isNaN() const {return SimTK::isNaN(mass) || comInB.isNaN() || inertia_OB_B.isNaN();} 01413 bool isInf() const { 01414 if (isNaN()) return false; 01415 return SimTK::isInf(mass) || comInB.isInf() || inertia_OB_B.isInf(); 01416 } 01420 bool isFinite() const { 01421 return SimTK::isFinite(mass) && comInB.isFinite() && inertia_OB_B.isFinite(); 01422 } 01423 01427 SpatialMatP toSpatialMat() const { 01428 SpatialMatP M; 01429 M(0,0) = inertia_OB_B.toMat33(); 01430 M(0,1) = mass*crossMat(comInB); 01431 M(1,0) = ~M(0,1); 01432 M(1,1) = mass; // a diagonal matrix 01433 return M; 01434 } 01435 01441 Mat66P toMat66() const { 01442 Mat66P M; 01443 M.template updSubMat<3,3>(0,0) = inertia_OB_B.toMat33(); 01444 M.template updSubMat<3,3>(0,3) = mass*crossMat(comInB); 01445 M.template updSubMat<3,3>(3,0) = ~M.template getSubMat<3,3>(0,3); 01446 M.template updSubMat<3,3>(3,3) = mass; // a diagonal matrix 01447 return M; 01448 } 01449 01450 private: 01451 RealP mass; 01452 Vec3P comInB; // meas. from B origin, expr. in B 01453 InertiaP inertia_OB_B; // about B origin, expr. in B 01454 }; 01455 01458 template <class P> static inline std::ostream& 01459 operator<<(std::ostream& o, const MassProperties_<P>& mp) { 01460 return o << "{ mass=" << mp.getMass() 01461 << "\n com=" << mp.getMassCenter() 01462 << "\n Ixx,yy,zz=" << mp.getInertia().getMoments() 01463 << "\n Ixy,xz,yz=" << mp.getInertia().getProducts() 01464 << "\n}\n"; 01465 } 01466 01467 } // namespace SimTK 01468 01469 #endif // SimTK_SIMMATRIX_MASS_PROPERTIES_H_