Simbody  3.4 (development)
MassProperties.h
Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines