ode/src/mass.cpp
changeset 0 2f259fa3e83a
equal deleted inserted replaced
-1:000000000000 0:2f259fa3e83a
       
     1 /*************************************************************************
       
     2  *                                                                       *
       
     3  * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
       
     4  * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
       
     5  *                                                                       *
       
     6  * This library is free software; you can redistribute it and/or         *
       
     7  * modify it under the terms of EITHER:                                  *
       
     8  *   (1) The GNU Lesser General Public License as published by the Free  *
       
     9  *       Software Foundation; either version 2.1 of the License, or (at  *
       
    10  *       your option) any later version. The text of the GNU Lesser      *
       
    11  *       General Public License is included with this library in the     *
       
    12  *       file LICENSE.TXT.                                               *
       
    13  *   (2) The BSD-style license that is included with this library in     *
       
    14  *       the file LICENSE-BSD.TXT.                                       *
       
    15  *                                                                       *
       
    16  * This library is distributed in the hope that it will be useful,       *
       
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
       
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
       
    19  * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
       
    20  *                                                                       *
       
    21  *************************************************************************/
       
    22 
       
    23 #include <ode/config.h>
       
    24 #include <ode/mass.h>
       
    25 #include <ode/odemath.h>
       
    26 #include <ode/matrix.h>
       
    27 
       
    28 // Local dependencies
       
    29 #include "collision_kernel.h"
       
    30 
       
    31 #define	SQR(x)			(dMUL((x),(x)))						//!< Returns x square
       
    32 #define	CUBE(x)			(dMUL((x),dMUL((x),(x))))					//!< Returns x cube
       
    33 
       
    34 #define _I(i,j) I[(i)*4+(j)]
       
    35 
       
    36 
       
    37 // return 1 if ok, 0 if bad
       
    38 
       
    39 EXPORT_C int dMassCheck (const dMass *m)
       
    40 {
       
    41   int i;
       
    42 
       
    43   if (m->mass <= 0) {
       
    44     return 0;
       
    45   }
       
    46   if (!dIsPositiveDefinite (m->I,3)) {
       
    47     return 0;
       
    48   }
       
    49 
       
    50   // verify that the center of mass position is consistent with the mass
       
    51   // and inertia matrix. this is done by checking that the inertia around
       
    52   // the center of mass is also positive definite. from the comment in
       
    53   // dMassTranslate(), if the body is translated so that its center of mass
       
    54   // is at the point of reference, then the new inertia is:
       
    55   //   I + mass*crossmat(c)^2
       
    56   // note that requiring this to be positive definite is exactly equivalent
       
    57   // to requiring that the spatial inertia matrix
       
    58   //   [ mass*eye(3,3)   M*crossmat(c)^T ]
       
    59   //   [ M*crossmat(c)   I               ]
       
    60   // is positive definite, given that I is PD and mass>0. see the theorem
       
    61   // about partitioned PD matrices for proof.
       
    62 
       
    63   dMatrix3 I2,chat;
       
    64   dSetZero (chat,12);
       
    65   dCROSSMAT (chat,m->c,4,+,-);
       
    66   dMULTIPLY0_333 (I2,chat,chat);
       
    67   for (i=0; i<3; i++) I2[i] = m->I[i] + dMUL(m->mass,I2[i]);
       
    68   for (i=4; i<7; i++) I2[i] = m->I[i] + dMUL(m->mass,I2[i]);
       
    69   for (i=8; i<11; i++) I2[i] = m->I[i] + dMUL(m->mass,I2[i]);
       
    70   if (!dIsPositiveDefinite (I2,3)) {
       
    71     return 0;
       
    72   }
       
    73   return 1;
       
    74 }
       
    75 
       
    76 
       
    77 EXPORT_C void dMassSetZero (dMass *m)
       
    78 {
       
    79   m->mass = REAL(0.0);
       
    80   dSetZero (m->c,sizeof(m->c) / sizeof(dReal));
       
    81   dSetZero (m->I,sizeof(m->I) / sizeof(dReal));
       
    82 }
       
    83 
       
    84 
       
    85 EXPORT_C void dMassSetParameters (dMass *m, dReal themass,
       
    86 			 dReal cgx, dReal cgy, dReal cgz,
       
    87 			 dReal I11, dReal I22, dReal I33,
       
    88 			 dReal I12, dReal I13, dReal I23)
       
    89 {
       
    90   dMassSetZero (m);
       
    91   m->mass = themass;
       
    92   m->c[0] = cgx;
       
    93   m->c[1] = cgy;
       
    94   m->c[2] = cgz;
       
    95   m->_I(0,0) = I11;
       
    96   m->_I(1,1) = I22;
       
    97   m->_I(2,2) = I33;
       
    98   m->_I(0,1) = I12;
       
    99   m->_I(0,2) = I13;
       
   100   m->_I(1,2) = I23;
       
   101   m->_I(1,0) = I12;
       
   102   m->_I(2,0) = I13;
       
   103   m->_I(2,1) = I23;
       
   104   dMassCheck (m);
       
   105 }
       
   106 
       
   107 
       
   108 EXPORT_C void dMassSetSphere (dMass *m, dReal density, dReal radius)
       
   109 {
       
   110   dMassSetSphereTotal (m, dMUL(dDIV(REAL(4.0),REAL(3.0)), dMUL(dPI,dMUL(CUBE(radius),density))), radius);
       
   111 }
       
   112 
       
   113 
       
   114 EXPORT_C void dMassSetSphereTotal (dMass *m, dReal total_mass, dReal radius)
       
   115 {
       
   116   dMassSetZero (m);
       
   117   m->mass = total_mass;
       
   118   dReal II = dMUL(REAL(0.4),dMUL(total_mass,SQR(radius)));
       
   119   m->_I(0,0) = II;
       
   120   m->_I(1,1) = II;
       
   121   m->_I(2,2) = II;
       
   122 
       
   123 # ifndef dNODEBUG
       
   124   dMassCheck (m);
       
   125 # endif
       
   126 }
       
   127 
       
   128 
       
   129 EXPORT_C void dMassSetCapsule (dMass *m, dReal density, int direction,
       
   130 		      dReal radius, dReal length)
       
   131 {
       
   132   dReal M1,M2,Ia,Ib;
       
   133   dMassSetZero (m);
       
   134   M1 = dMUL(dPI,dMUL(SQR(radius),dMUL(length,density)));			// cylinder mass
       
   135   M2 = dMUL(dDIV(REAL(4.0),REAL(3.0)),dMUL(dPI,dMUL(CUBE(radius),density)));	// total cap mass
       
   136   m->mass = M1+M2;
       
   137   Ia = dMUL(M1,(dMUL(REAL(0.25),SQR(radius)) + dMUL(dDIV(REAL(1.0),REAL(12.0)),SQR(length)))) +
       
   138     dMUL(M2,(dMUL(REAL(0.4),SQR(radius)) + dMUL(REAL(0.375),dMUL(radius,length)) + dMUL(REAL(0.25),SQR(length))));
       
   139   Ib = dMUL((dMUL(M1,REAL(0.5)) + dMUL(M2,REAL(0.4))),SQR(radius));
       
   140   m->_I(0,0) = Ia;
       
   141   m->_I(1,1) = Ia;
       
   142   m->_I(2,2) = Ia;
       
   143   m->_I(direction-1,direction-1) = Ib;
       
   144 
       
   145 # ifndef dNODEBUG
       
   146   dMassCheck (m);
       
   147 # endif
       
   148 }
       
   149 
       
   150 
       
   151 EXPORT_C void dMassSetCapsuleTotal (dMass *m, dReal total_mass, int direction,
       
   152 			   dReal a, dReal b)
       
   153 {
       
   154   dMassSetCapsule (m, REAL(1.0), direction, a, b);
       
   155   dMassAdjust (m, total_mass);
       
   156 }
       
   157 
       
   158 
       
   159 EXPORT_C void dMassSetCylinder (dMass *m, dReal density, int direction,
       
   160 		       dReal radius, dReal length)
       
   161 {
       
   162   dMassSetCylinderTotal (m, dMUL(dPI,dMUL(SQR(radius),dMUL(length,density))),
       
   163 			    direction, radius, length);
       
   164 }
       
   165 
       
   166 EXPORT_C void dMassSetCylinderTotal (dMass *m, dReal total_mass, int direction,
       
   167 			    dReal radius, dReal length)
       
   168 {
       
   169   dReal r2,I;
       
   170   dMassSetZero (m);
       
   171   r2 = SQR(radius);
       
   172   m->mass = total_mass;
       
   173   I = dMUL(total_mass,(dMUL(REAL(0.25),r2) + dMUL(dDIV(REAL(1.0),REAL(12.0)),SQR(length))));
       
   174   m->_I(0,0) = I;
       
   175   m->_I(1,1) = I;
       
   176   m->_I(2,2) = I;
       
   177   m->_I(direction-1,direction-1) = dMUL(total_mass,dMUL(REAL(0.5),r2));
       
   178 
       
   179 # ifndef dNODEBUG
       
   180   dMassCheck (m);
       
   181 # endif
       
   182 }
       
   183 
       
   184 
       
   185 EXPORT_C void dMassSetBox (dMass *m, dReal density,
       
   186 		  dReal lx, dReal ly, dReal lz)
       
   187 {
       
   188   dMassSetBoxTotal (m, dMUL(lx,dMUL(ly,dMUL(lz,density))), lx, ly, lz);
       
   189 }
       
   190 
       
   191 
       
   192 EXPORT_C void dMassSetBoxTotal (dMass *m, dReal total_mass,
       
   193 		       dReal lx, dReal ly, dReal lz)
       
   194 {
       
   195   dMassSetZero (m);
       
   196   m->mass = total_mass;
       
   197   m->_I(0,0) = dMUL(dDIV(total_mass,REAL(12.0)),(SQR(ly) + SQR(lz)));
       
   198   m->_I(1,1) = dMUL(dDIV(total_mass,REAL(12.0)),(SQR(lx) + SQR(lz)));
       
   199   m->_I(2,2) = dMUL(dDIV(total_mass,REAL(12.0)),(SQR(lx) + SQR(ly)));
       
   200 
       
   201 # ifndef dNODEBUG
       
   202   dMassCheck (m);
       
   203 # endif
       
   204 }
       
   205 
       
   206 EXPORT_C void dMassAdjust (dMass *m, dReal newmass)
       
   207 {
       
   208   dReal scale = dDIV(newmass,m->mass);
       
   209   m->mass = newmass;
       
   210   for (int i=0; i<3; i++) for (int j=0; j<3; j++) m->_I(i,j) = dMUL(m->_I(i,j),scale);
       
   211 
       
   212 # ifndef dNODEBUG
       
   213   dMassCheck (m);
       
   214 # endif
       
   215 }
       
   216 
       
   217 
       
   218 EXPORT_C void dMassTranslate (dMass *m, dReal x, dReal y, dReal z)
       
   219 {
       
   220   // if the body is translated by `a' relative to its point of reference,
       
   221   // the new inertia about the point of reference is:
       
   222   //
       
   223   //   I + mass*(crossmat(c)^2 - crossmat(c+a)^2)
       
   224   //
       
   225   // where c is the existing center of mass and I is the old inertia.
       
   226 
       
   227   int i,j;
       
   228   dMatrix3 ahat,chat,t1,t2;
       
   229   dReal a[3];
       
   230 
       
   231   // adjust inertia matrix
       
   232   dSetZero (chat,12);
       
   233   dCROSSMAT (chat,m->c,4,+,-);
       
   234   a[0] = x + m->c[0];
       
   235   a[1] = y + m->c[1];
       
   236   a[2] = z + m->c[2];
       
   237   dSetZero (ahat,12);
       
   238   dCROSSMAT (ahat,a,4,+,-);
       
   239   dMULTIPLY0_333 (t1,ahat,ahat);
       
   240   dMULTIPLY0_333 (t2,chat,chat);
       
   241   for (i=0; i<3; i++) for (j=0; j<3; j++)
       
   242     m->_I(i,j) += dMUL(m->mass,(t2[i*4+j]-t1[i*4+j]));
       
   243 
       
   244   // ensure perfect symmetry
       
   245   m->_I(1,0) = m->_I(0,1);
       
   246   m->_I(2,0) = m->_I(0,2);
       
   247   m->_I(2,1) = m->_I(1,2);
       
   248 
       
   249   // adjust center of mass
       
   250   m->c[0] += x;
       
   251   m->c[1] += y;
       
   252   m->c[2] += z;
       
   253 
       
   254 # ifndef dNODEBUG
       
   255   dMassCheck (m);
       
   256 # endif
       
   257 }
       
   258 
       
   259 
       
   260 EXPORT_C void dMassRotate (dMass *m, const dMatrix3 R)
       
   261 {
       
   262   // if the body is rotated by `R' relative to its point of reference,
       
   263   // the new inertia about the point of reference is:
       
   264   //
       
   265   //   R * I * R'
       
   266   //
       
   267   // where I is the old inertia.
       
   268 
       
   269   dMatrix3 t1;
       
   270   dReal t2[3];
       
   271 
       
   272   // rotate inertia matrix
       
   273   dMULTIPLY2_333 (t1,m->I,R);
       
   274   dMULTIPLY0_333 (m->I,R,t1);
       
   275 
       
   276   // ensure perfect symmetry
       
   277   m->_I(1,0) = m->_I(0,1);
       
   278   m->_I(2,0) = m->_I(0,2);
       
   279   m->_I(2,1) = m->_I(1,2);
       
   280 
       
   281   // rotate center of mass
       
   282   dMULTIPLY0_331 (t2,R,m->c);
       
   283   m->c[0] = t2[0];
       
   284   m->c[1] = t2[1];
       
   285   m->c[2] = t2[2];
       
   286 
       
   287 # ifndef dNODEBUG
       
   288   dMassCheck (m);
       
   289 # endif
       
   290 }
       
   291 
       
   292 
       
   293 EXPORT_C void dMassAdd (dMass *a, const dMass *b)
       
   294 {
       
   295   int i;
       
   296   dReal denom = dRecip (a->mass + b->mass);
       
   297   for (i=0; i<3; i++) a->c[i] = dMUL((dMUL(a->c[i],a->mass) + dMUL(b->c[i],b->mass)),denom);
       
   298   a->mass += b->mass;
       
   299   for (i=0; i<12; i++) a->I[i] += b->I[i];
       
   300 }