Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

physics/MassProperties.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: MassProperties.cpp 1031 2004-02-11 20:46:36Z jungd $
00019   $Revision: 1.4 $
00020   $Date: 2004-02-11 15:46:36 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <physics/MassProperties>
00026 #include <physics/Material>
00027 #include <gfx/TriangleContainer>
00028 #include <gfx/TriangleIterator>
00029 #include <gfx/Triangle3>
00030 
00031 using physics::MassProperties;
00032 using physics::Material;
00033 using gfx::TriangleContainer;
00034 using gfx::TriangleIterator;
00035 using gfx::Triangle3;
00036 
00037 
00038 
00039 MassProperties::MassProperties()
00040         : mass(1.0), centerOfMass(0,0,0)
00041 {
00042 }
00043 
00044 MassProperties::MassProperties(const TriangleContainer& triangles, ref<const Material> material)
00045 {
00046   computeMassProperties(triangles, material);
00047 }
00048 
00049 void MassProperties::setIbody(const Matrix3& Ibody) 
00050 {
00051   _Ibody = Ibody;
00052   try {
00053     _IbodyInv = base::inverse(Ibody);
00054   } catch (std::invalid_argument& e) {
00055     Logln("Warning: Invalid Inertia matrix (body frame) - cannot be inverted. Setting to identity.");
00056     _Ibody.setIdentity();
00057     _IbodyInv.setIdentity();
00058   }
00059 }
00060 
00061 class MassProperties::VolData {
00062 public:
00063   SInt A,B,C;
00064   Real P1, Pa, Pb, Paa, Pab, Pbb, Paaa, Paab, Pabb, Pbbb; // projection integrals
00065   Real Fa, Fb, Fc, Faa, Fbb, Fcc, Faaa, Fbbb, Fccc, Faab, Fbbc, Fcca; // face integrals
00066   /// volume integrals
00067   Real T0;
00068   Real T1[4]; // using only 1..3
00069   Real T2[4];
00070   Real TP[4];
00071 };
00072 
00073 
00074 class MassProperties::WTriangle : public gfx::Triangle3
00075 {
00076 public:
00077   WTriangle() { compNorm(); compW(); }
00078   WTriangle(const gfx::Triangle3& t) : gfx::Triangle3(t) { compNorm(); compW(); }
00079   WTriangle(const WTriangle& t) : gfx::Triangle3(t), norm(t.norm), w(t.w) {}
00080   virtual ~WTriangle() {}
00081 
00082   void compNorm() { norm=normal(); }
00083   void compW() { w = -norm.x*_p1.x - norm.y*_p1.y - norm.z*_p1.z; }
00084 
00085   Vector3 norm;
00086   Real w;
00087 };
00088 
00089 
00090 
00091 void MassProperties::computeMassProperties(const TriangleContainer& triangles, ref<const Material> material)
00092 {
00093   Int X=1, Y=2, Z=3;
00094 
00095   Matrix3 J; // inertia tensor
00096   Point3  r; // center of mass
00097 
00098   VolData v;
00099   compVolumeIntegrals(triangles, v);
00100 
00101   Real density = material->density();
00102 
00103   if ( Math::isNAN(v.T0) || Math::equals(v.T0,0) ) {
00104     Logln("Warning: Mass property calculation failed.  Setting inertia matrix to identity, mass to 1*density and center of mass to 0");
00105     _Ibody.setIdentity();
00106     _IbodyInv.setIdentity();
00107     mass = density * 1.0;
00108     centerOfMass = Point3(0,0,0);
00109   }
00110   else {
00111     mass = density * v.T0;
00112   
00113     // compute center of mass
00114     r.x = v.T1[X]/v.T0;
00115     r.y = v.T1[Y]/v.T0;
00116     r.z = v.T1[Z]/v.T0;
00117 
00118     // compute inertia tensor 
00119     J.e(1,1) = density * (v.T2[Y] + v.T2[Z]);
00120     J.e(2,2) = density * (v.T2[Z] + v.T2[X]);
00121     J.e(3,3) = density * (v.T2[X] + v.T2[Y]);
00122     J.e(1,2) = J.e(2,1) = - density * v.TP[X];
00123     J.e(2,3) = J.e(3,2) = - density * v.TP[Y];
00124     J.e(3,1) = J.e(1,3) = - density * v.TP[Z];
00125 
00126     // translate inertia tensor to center of mass 
00127     J.e(1,1) -= mass * (r.y*r.y + r.z*r.z);
00128     J.e(2,2) -= mass * (r.z*r.z + r.x*r.x);
00129     J.e(3,3) -= mass * (r.x*r.x + r.y*r.y);
00130     J.e(1,2) = J.e(2,1) += mass * r.x * r.y; 
00131     J.e(2,3) = J.e(3,2) += mass * r.y * r.z; 
00132     J.e(3,1) = J.e(1,3) += mass * r.z * r.x; 
00133     
00134     _Ibody = J;
00135     try {
00136       _IbodyInv = base::inverse(_Ibody);
00137     } catch (std::invalid_argument& e) {
00138       Logln("Warning: Inertia matrix (body frame) cannot be inverted - setting to identity");
00139       _Ibody.setIdentity();
00140       _IbodyInv.setIdentity();
00141     }
00142     
00143     centerOfMass = r;
00144 
00145     if (!centerOfMass.equals(Point3(0,0,0))) {
00146       Logln("Warning: Center of mass is not at coordinate origin - it is " << centerOfMass << ".");
00147     }
00148 
00149   }
00150 
00151 }
00152 
00153 
00154 void MassProperties::compVolumeIntegrals(const TriangleContainer& triangles, VolData& v)
00155 {
00156   SInt X=1, Y=2, Z=3;
00157 
00158   TriangleContainer::const_iterator tris = triangles.begin();
00159   TriangleContainer::const_iterator endtris = triangles.end();
00160   
00161   Real nx, ny, nz;
00162 
00163   v.T0 = 0;
00164   v.T1[X] = v.T1[Y] = v.T1[Z] = 0;
00165   v.T2[X] = v.T2[Y] = v.T2[Z] = 0.0;
00166   v.TP[X] = v.TP[Y] = v.TP[Z] = 0.0;
00167   
00168   while (tris != endtris) {
00169 
00170     WTriangle f(*tris);
00171 
00172     nx = base::abs(f.norm.x);
00173     ny = base::abs(f.norm.y);
00174     nz = base::abs(f.norm.z);
00175     if (nx > ny && nx > nz)
00176       v.C = X;
00177     else
00178       v.C = (ny > nz) ? Y : Z;
00179     v.A = ((v.C + 1 -1)%3)+1;
00180     v.B = ((v.A + 1 -1)%3)+1;
00181     
00182     compFaceIntegrals(f,v);
00183     
00184     v.T0 += f.norm.x * ((v.A == X) ? v.Fa : ((v.B == X) ? v.Fb : v.Fc));
00185     
00186     v.T1[v.A] += f.norm[v.A] * v.Faa;
00187     v.T1[v.B] += f.norm[v.B] * v.Fbb;
00188     v.T1[v.C] += f.norm[v.C] * v.Fcc;
00189     v.T2[v.A] += f.norm[v.A] * v.Faaa;
00190     v.T2[v.B] += f.norm[v.B] * v.Fbbb;
00191     v.T2[v.C] += f.norm[v.C] * v.Fccc;
00192     v.TP[v.A] += f.norm[v.A] * v.Faab;
00193     v.TP[v.B] += f.norm[v.B] * v.Fbbc;
00194     v.TP[v.C] += f.norm[v.C] * v.Fcca;
00195 
00196     ++tris;
00197   }
00198   
00199   v.T1[X] /= 2.0; v.T1[Y] /= 2.0; v.T1[Z] /= 2.0;
00200   v.T2[X] /= 3.0; v.T2[Y] /= 3.0; v.T2[Z] /= 3.0;
00201   v.TP[X] /= 2.0; v.TP[Y] /= 2.0; v.TP[Z] /= 2.0;
00202 
00203 }
00204 
00205 void MassProperties::compFaceIntegrals(const WTriangle& t, VolData& v)
00206 {
00207   Real w;
00208   Real k1, k2, k3, k4;
00209 
00210   compProjectionIntegrals(t,v);
00211 
00212   w = t.w;
00213   k1 = 1 / t.norm[v.C]; k2 = k1 * k1; k3 = k2 * k1; k4 = k3 * k1;
00214 
00215   v.Fa = k1 * v.Pa;
00216   v.Fb = k1 * v.Pb;
00217   v.Fc = -k2 * (t.norm[v.A]*v.Pa + t.norm[v.B]*v.Pb + w*v.P1);
00218   
00219   v.Faa = k1 * v.Paa;
00220   v.Fbb = k1 * v.Pbb;
00221   v.Fcc = k3 * (Math::sqr(t.norm[v.A])*v.Paa + 2*t.norm[v.A]*t.norm[v.B]*v.Pab + Math::sqr(t.norm[v.B])*v.Pbb
00222                 + w*(2*(t.norm[v.A]*v.Pa + t.norm[v.B]*v.Pb) + w*v.P1));
00223   
00224   v.Faaa = k1 * v.Paaa;
00225   v.Fbbb = k1 * v.Pbbb;
00226   v.Fccc = -k4 * (Math::cube(t.norm[v.A])*v.Paaa + 3*Math::sqr(t.norm[v.A])*t.norm[v.B]*v.Paab 
00227                   + 3*t.norm[v.A]*Math::sqr(t.norm[v.B])*v.Pabb + Math::cube(t.norm[v.B])*v.Pbbb
00228                   + 3*w*(Math::sqr(t.norm[v.A])*v.Paa + 2*t.norm[v.A]*t.norm[v.B]*v.Pab + Math::sqr(t.norm[v.B])*v.Pbb)
00229                   + w*w*(3*(t.norm[v.A]*v.Pa + t.norm[v.B]*v.Pb) + w*v.P1));
00230   
00231   v.Faab = k1 * v.Paab;
00232   v.Fbbc = -k2 * (t.norm[v.A]*v.Pabb + t.norm[v.B]*v.Pbbb + w*v.Pbb);
00233   v.Fcca = k3 * (Math::sqr(t.norm[v.A])*v.Paaa + 2*t.norm[v.A]*t.norm[v.B]*v.Paab + Math::sqr(t.norm[v.B])*v.Pabb
00234                  + w*(2*(t.norm[v.A]*v.Paa + t.norm[v.B]*v.Pab) + w*v.Pa));
00235 }
00236 
00237 
00238 void MassProperties::compProjectionIntegrals(const WTriangle& t, VolData& v)
00239 {
00240    Real a0, a1, da;
00241    Real b0, b1, db;
00242    Real a0_2, a0_3, a0_4, b0_2, b0_3, b0_4;
00243    Real a1_2, a1_3, b1_2, b1_3;
00244    Real C1, Ca, Caa, Caaa, Cb, Cbb, Cbbb;
00245    Real Cab, Kab, Caab, Kaab, Cabb, Kabb;
00246 
00247    v.P1 = v.Pa = v.Pb = v.Paa = v.Pab = v.Pbb = v.Paaa = v.Paab = v.Pabb = v.Pbbb = 0.0;
00248 
00249    for (int i = 1; i <= 3; i++) {
00250      a0 = t(i)[v.A];
00251      b0 = t(i)[v.B];
00252      a1 = t(((i+1-1)%3)+1)[v.A];
00253      b1 = t(((i+1-1)%3)+1)[v.B];
00254      da = a1 - a0;
00255      db = b1 - b0;
00256      a0_2 = a0 * a0; a0_3 = a0_2 * a0; a0_4 = a0_3 * a0;
00257      b0_2 = b0 * b0; b0_3 = b0_2 * b0; b0_4 = b0_3 * b0;
00258      a1_2 = a1 * a1; a1_3 = a1_2 * a1; 
00259      b1_2 = b1 * b1; b1_3 = b1_2 * b1;
00260      
00261      C1 = a1 + a0;
00262      Ca = a1*C1 + a0_2; Caa = a1*Ca + a0_3; Caaa = a1*Caa + a0_4;
00263      Cb = b1*(b1 + b0) + b0_2; Cbb = b1*Cb + b0_3; Cbbb = b1*Cbb + b0_4;
00264      Cab = 3*a1_2 + 2*a1*a0 + a0_2; Kab = a1_2 + 2*a1*a0 + 3*a0_2;
00265      Caab = a0*Cab + 4*a1_3; Kaab = a1*Kab + 4*a0_3;
00266      Cabb = 4*b1_3 + 3*b1_2*b0 + 2*b1*b0_2 + b0_3;
00267      Kabb = b1_3 + 2*b1_2*b0 + 3*b1*b0_2 + 4*b0_3;
00268      
00269      v.P1 += db*C1;
00270      v.Pa += db*Ca;
00271      v.Paa += db*Caa;
00272      v.Paaa += db*Caaa;
00273      v.Pb += da*Cb;
00274      v.Pbb += da*Cbb;
00275      v.Pbbb += da*Cbbb;
00276      v.Pab += db*(b1*Cab + b0*Kab);
00277      v.Paab += db*(b1*Caab + b0*Kaab);
00278      v.Pabb += da*(a1*Cabb + a0*Kabb);
00279    }
00280    
00281    v.P1 /= 2.0;
00282    v.Pa /= 6.0;
00283    v.Paa /= 12.0;
00284    v.Paaa /= 20.0;
00285    v.Pb /= -6.0;
00286    v.Pbb /= -12.0;
00287    v.Pbbb /= -20.0;
00288    v.Pab /= 24.0;
00289    v.Paab /= 60.0;
00290    v.Pabb /= -60.0;
00291 }
00292 
00293 
00294 std::ostream& physics::operator<<(std::ostream& out, const MassProperties& mp) // Output
00295 {
00296   return out << "Ibody:" << mp.Ibody() << std::endl 
00297              << "mass:" << mp.mass << std::endl
00298              << "centerOfMass:" << mp.centerOfMass << std::endl;
00299 }

Generated on Thu Jul 29 15:56:24 2004 for OpenSim by doxygen 1.3.6