ODESolid.cpp

Go to the documentation of this file.
00001 /*************************************************************************
00002 *                                                                       *
00003 * Open Physics Abstraction Layer                                        *
00004 * Copyright (C) 2004-2005                                               *
00005 * Alan Fischer  alan.fischer@gmail.com                                  *
00006 * Andres Reinot  andres@reinot.com                                      *
00007 * Tyler Streeter  tylerstreeter@gmail.com                               *
00008 * All rights reserved.                                                  *
00009 * Web: opal.sourceforge.net                                             *
00010 *                                                                       *
00011 * This library is free software; you can redistribute it and/or         *
00012 * modify it under the terms of EITHER:                                  *
00013 *   (1) The GNU Lesser General Public License as published by the Free  *
00014 *       Software Foundation; either version 2.1 of the License, or (at  *
00015 *       your option) any later version. The text of the GNU Lesser      *
00016 *       General Public License is included with this library in the     *
00017 *       file license-LGPL.txt.                                          *
00018 *   (2) The BSD-style license that is included with this library in     *
00019 *       the file license-BSD.txt.                                       *
00020 *                                                                       *
00021 * This library is distributed in the hope that it will be useful,       *
00022 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
00024 * license-LGPL.txt and license-BSD.txt for more details.                *
00025 *                                                                       *
00026 *************************************************************************/
00027 
00028 // class headers
00029 #include "ODESolid.h"
00030 
00031 // project headers
00032 #include "ODESpace.h"
00033 #include "ODETools.h"
00034 #include "../BoxShapeData.h"
00035 #include "../SphereShapeData.h"
00036 #include "../CapsuleShapeData.h"
00037 #include "../PlaneShapeData.h"
00038 #include "../MeshShapeData.h"
00039 #include "../Mass.h"
00040 
00041 namespace opal
00042 {
00043         ODESolid::ODESolid( dWorldID worldID, dSpaceID spaceID )
00044                         : Solid()
00045         {
00046                 mWorldID = worldID;
00047                 mSpaceID = spaceID;
00048                 mIsPlaceable = true;
00049                 mCollisionCount = 0;
00050                 mNonSymmetricInertia = false;
00051                 mIsFreelySpinning = true;
00052                 mPrevAngVelMagSquared = 0;
00053 
00054                 if ( !mData.isStatic )
00055                 {
00056                         // Create an ODE body with default ODE mass parameters (total
00057                         // mass = 1).  This should have an initial mass of 0 until shapes
00058                         // are added, but ODE won't allow a mass of 0.  This will be
00059                         // adjusted appropriately when the first shape is added.
00060                         mBodyID = dBodyCreate( mWorldID );
00061                 }
00062 
00063                 init( mData );
00064         }
00065 
00066         ODESolid::~ODESolid()
00067         {
00068                 destroyGeoms();
00069 
00070                 if ( !mData.isStatic )
00071                 {
00072                         // This is a dynamic solid, so it has an ODE body that needs
00073                         // to be destroyed.
00074                         dBodyDestroy( mBodyID );
00075                 }
00076         }
00077 
00078         void ODESolid::clearShapes()
00079         {
00080                 destroyGeoms();
00081                 resetAABB();
00082                 mData.destroyShapes();
00083         }
00084 
00085         void ODESolid::destroyGeoms()
00086         {
00087                 for ( size_t i = 0; i < mGeomDataList.size(); ++i )
00088                 {
00089                         if ( 0 != mGeomDataList[ i ] ->transformID )
00090                         {
00091                                 dGeomDestroy( mGeomDataList[ i ] ->transformID );
00092                         }
00093 
00094                         if ( 0 != mGeomDataList[ i ] ->trimeshDataID )
00095                         {
00096                                 // This geom uses a trimesh.  Destroy it.  (This does NOT
00097                                 // touch the user's mesh data, just internal ODE trimesh
00098                                 // data.)
00099                                 dGeomTriMeshDataDestroy( mGeomDataList[ i ] ->trimeshDataID );
00100                         }
00101 
00102                         // Destroy the ODE geom.
00103                         dGeomDestroy( mGeomDataList[ i ] ->geomID );
00104 
00105                         // Delete the geom data object.
00106                         delete mGeomDataList[ i ];
00107                 }
00108                 mGeomDataList.clear();
00109         }
00110 
00111         void ODESolid::init( const SolidData& data )
00112         {
00113                 // The order of function calls here is important.
00114 
00115                 // Destroy the old Shapes.
00116                 mData.destroyShapes();
00117 
00118                 // Destroy the old ODE geoms.
00119                 destroyGeoms();
00120 
00121                 // Set whether the Solid is static.
00122                 setStatic( data.isStatic );
00123 
00124                 // Set the new transform.
00125                 setTransform( data.transform );
00126 
00127                 // Add the new Shapes.
00128                 for ( unsigned int i = 0; i < data.getNumShapes(); ++i )
00129                 {
00130                         addShape( *( data.getShapeData( i ) ) );
00131                 }
00132 
00133                 // Set whether the Solid is sleeping.
00134                 setSleeping( data.sleeping );
00135 
00136                 // Set the Solid's sleepiness level.
00137                 setSleepiness( data.sleepiness );
00138 
00139                 // Set whether the Solid is enabled.
00140                 setEnabled( data.enabled );
00141 
00142                 // Set damping levels.
00143                 setLinearDamping( data.linearDamping );
00144                 setAngularDamping( data.angularDamping );
00145 
00146                 // Set velocities.
00147                 setGlobalLinearVel( data.globalLinearVel );
00148                 setGlobalAngularVel( data.globalAngularVel );
00149 
00150                 // Set the Solid's name.
00151                 setName( data.name );
00152         }
00153 
00154         void ODESolid::setEnabled( bool e )
00155         {
00156                 if ( e )
00157                 {
00158                         // If this Solid is dynamic, enable the ODE body.
00159                         if ( !mData.isStatic )
00160                         {
00161                                 dBodyEnable( mBodyID );
00162                         }
00163 
00164                         // Enable the ODE geoms.
00165                         std::vector<GeomData*>::iterator iter;
00166                         for ( iter = mGeomDataList.begin();
00167                                 iter != mGeomDataList.end(); ++iter )
00168                         {
00169                                 dGeomEnable( ( *iter ) ->geomID );
00170                         }
00171                 }
00172                 else // Disable the Solid.
00173                 {
00174                         // If this Solid is dynamic, disable the ODE body.
00175                         if ( !mData.isStatic )
00176                         {
00177                                 dBodyDisable( mBodyID );
00178                         }
00179 
00180                         // Disable the ODE geoms.
00181                         std::vector<GeomData*>::iterator iter;
00182                         for ( iter = mGeomDataList.begin();
00183                                 iter != mGeomDataList.end(); ++iter )
00184                         {
00185                                 dGeomDisable( ( *iter ) ->geomID );
00186                         }
00187                 }
00188         }
00189 
00190         void ODESolid::internal_updateOPALTransform()
00191         {
00192                 const real * R = ( const real* ) dBodyGetRotation( mBodyID );
00193                 const real* P = ( const real* ) dBodyGetPosition( mBodyID );
00194 
00195                 mData.transform.set( R[ 0 ], R[ 1 ], R[ 2 ], P[ 0 ],
00196                                      R[ 4 ], R[ 5 ], R[ 6 ], P[ 1 ],
00197                                      R[ 8 ], R[ 9 ], R[ 10 ], P[ 2 ],
00198                                      0, 0, 0, 1 );
00199         }
00200 
00201         void ODESolid::internal_updateEngineTransform()
00202         {
00203                 dMatrix3 R = {mData.transform[ 0 ], mData.transform[ 4 ],
00204                               mData.transform[ 8 ], 0, mData.transform[ 1 ], mData.transform[ 5 ],
00205                               mData.transform[ 9 ], 0, mData.transform[ 2 ], mData.transform[ 6 ],
00206                               mData.transform[ 10 ], 0};
00207 
00208                 if ( !mData.isStatic )
00209                 {
00210                         dBodySetRotation( mBodyID, R );
00211                         dBodySetPosition( mBodyID, mData.transform[ 12 ],
00212                                           mData.transform[ 13 ], mData.transform[ 14 ] );
00213                 }
00214                 else if ( mIsPlaceable )
00215                 {
00216                         std::vector<GeomData*>::iterator iter;
00217                         for ( iter = mGeomDataList.begin(); iter != mGeomDataList.end();
00218                                 ++iter )
00219                         {
00220                                 GeomData* geomData = ( *iter );
00221                                 if ( 0 == geomData->transformID )
00222                                 {
00223                                         // No geom transform.
00224                                         dGeomSetRotation( geomData->geomID, R );
00225                                         dGeomSetPosition( geomData->geomID, mData.transform[ 12 ],
00226                                                           mData.transform[ 13 ], mData.transform[ 14 ] );
00227                                 }
00228                                 else
00229                                 {
00230                                         // Using geom transform.
00231                                         dGeomSetRotation( geomData->transformID, R );
00232                                         dGeomSetPosition( geomData->transformID,
00233                                                           mData.transform[ 12 ], mData.transform[ 13 ],
00234                                                           mData.transform[ 14 ] );
00235                                 }
00236                         }
00237                 }
00238         }
00239 
00240         void ODESolid::setSpace( Space* newSpace )
00241         {
00242                 // update solid's space which will be used for future shapes
00243                 mSpaceID = ( ( ODESpace* ) newSpace ) ->internal_getSpaceID();
00244 
00245                 moveToSpace();
00246         }
00247 
00248         void ODESolid::setStatic( bool s )
00249         {
00250                 if ( true == mData.isStatic )
00251                 {
00252                         if ( false == s )
00253                         {
00254                                 // Make this object dynamic.
00255                                 mData.isStatic = false;
00256 
00257                                 // Create a new body.
00258                                 mBodyID = dBodyCreate( mWorldID );                      
00259 
00260                                 // Set the ODE sleepiness params using the stored Solid
00261                                 // sleepiness param.
00262                                 setSleepiness( mData.sleepiness );
00263 
00264                                 // Set the position of the new body.
00265                                 dMatrix3 R =
00266                                     {mData.transform[ 0 ], mData.transform[ 4 ],
00267                                      mData.transform[ 8 ], 0, mData.transform[ 1 ],
00268                                      mData.transform[ 5 ], mData.transform[ 9 ], 0,
00269                                      mData.transform[ 2 ], mData.transform[ 6 ],
00270                                      mData.transform[ 10 ], 0};
00271                                 dBodySetRotation( mBodyID, R );
00272                                 dBodySetPosition( mBodyID, mData.transform[ 12 ],
00273                                                   mData.transform[ 13 ], mData.transform[ 14 ] );
00274 
00275                                 // Loop over the geoms.
00276                                 std::vector<GeomData*>::iterator iter;
00277                                 for ( iter = mGeomDataList.begin();
00278                                         iter != mGeomDataList.end(); ++iter )
00279                                 {
00280                                         dMass newMass;
00281 
00282                                         // Get a pointer to this geom's ShapeData.
00283                                         ShapeData* shapeData = ( *iter ) ->shape;
00284 
00285                                         // Setup mass.
00286                                         switch ( shapeData->getType() )
00287                                         {
00288                                                 case BOX_SHAPE:
00289                                                         {
00290                                                                 BoxShapeData * boxData = ( BoxShapeData* ) shapeData;
00291                                                                 dMassSetBox( &newMass,
00292                                                                              shapeData->material.density,
00293                                                                              boxData->dimensions[ 0 ],
00294                                                                              boxData->dimensions[ 1 ],
00295                                                                              boxData->dimensions[ 2 ] );
00296                                                                 break;
00297                                                         }
00298                                                 case SPHERE_SHAPE:
00299                                                         {
00300                                                                 SphereShapeData* sphereData =
00301                                                                     ( SphereShapeData* ) shapeData;
00302                                                                 dMassSetSphere( &newMass,
00303                                                                                 shapeData->material.density,
00304                                                                                 sphereData->radius );
00305                                                                 break;
00306                                                         }
00307                                                 case CAPSULE_SHAPE:
00308                                                         {
00309                                                                 CapsuleShapeData* capsuleData =
00310                                                                     ( CapsuleShapeData* ) shapeData;
00311                                                                 dMassSetCappedCylinder( &newMass,
00312                                                                                         shapeData->material.density, 3,
00313                                                                                         capsuleData->radius,
00314                                                                                         capsuleData->length );
00315                                                                 break;
00316                                                         }
00317                                                 case PLANE_SHAPE:
00318                                                         // Planes have no mass.
00319                                                         break;
00320                                                         //case RAY_SHAPE:
00321                                                         //      // Rays have no mass.
00322                                                         //      break;
00323                                                 case MESH_SHAPE:
00324                                                         // This is a simple way to set the mass of an
00325                                                         // arbitrary mesh.  Ideally we would compute
00326                                                         // the exact volume and intertia tensor.
00327                                                         // Instead we just use a box inertia tensor
00328                                                         // from its axis-aligned bounding box.
00329                                                         dReal aabb[ 6 ];
00330                                                         dGeomGetAABB( ( *iter ) ->geomID, aabb );
00331                                                         dMassSetBox( &newMass,
00332                                                                      shapeData->material.density,
00333                                                                      aabb[ 1 ] - aabb[ 0 ], aabb[ 3 ] - aabb[ 2 ],
00334                                                                      aabb[ 5 ] - aabb[ 4 ] );
00335                                                         break;
00336                                                 default:
00337                                                         assert( false );
00338                                         }
00339 
00340                                         // Setup the new mass.
00341                                         if ( iter == mGeomDataList.begin() )
00342                                                 setMass( newMass, shapeData->offset );
00343                                         else
00344                                                 addMass( newMass, shapeData->offset );
00345 
00346                                         // Add each geom to the new body.
00347                                         if ( 0 == ( *iter ) ->transformID )
00348                                         {
00349                                                 // No geom transform.
00350                                                 dGeomSetBody( ( *iter ) ->geomID, mBodyID );
00351                                         }
00352                                         else
00353                                         {
00354                                                 // Use geom transform.
00355                                                 dGeomSetBody( ( *iter ) ->transformID, mBodyID );
00356                                         }
00357                                 }
00358 
00359                                 moveToSpace();
00360                         }
00361                         else
00362                         {
00363                                 // do nothing
00364                         }
00365                 }
00366                 else // this object is not static
00367                 {
00368                         if ( true == s )
00369                         {
00370                                 // make this object static
00371                                 mData.isStatic = true;
00372 
00373                                 // destroy the body
00374                                 dBodyDestroy( mBodyID );
00375 
00376                                 moveToSpace();
00377                         }
00378                         else
00379                         {
00380                                 // do nothing
00381                         }
00382                 }
00383         }
00384 
00385         void ODESolid::moveToSpace()
00386         {
00387                 // remove all current shapes from their spaces and add them to the
00388                 // new one
00389                 std::vector<GeomData*>::iterator iter;
00390                 for ( iter = mGeomDataList.begin(); iter != mGeomDataList.end();
00391                         ++iter )
00392                 {
00393                         if ( 0 != ( *iter ) ->transformID )
00394                         {
00395                                 // This geom uses a transform, so apply the new space only
00396                                 // to the transform geom.
00397                                 dSpaceRemove( ( *iter ) ->spaceID, ( *iter ) ->transformID );
00398                                 dSpaceAdd( mSpaceID, ( *iter ) ->transformID );
00399                         }
00400                         else
00401                         {
00402                                 // Normal geom with no transform.
00403                                 dSpaceRemove( ( *iter ) ->spaceID, ( *iter ) ->geomID );
00404                                 dSpaceAdd( mSpaceID, ( *iter ) ->geomID );
00405                         }
00406 
00407                         ( *iter ) ->spaceID = mSpaceID;
00408                 }
00409         }
00410 
00411         void ODESolid::setSleeping( bool sleeping )
00412         {
00413                 if ( mData.isStatic )
00414                 {
00415                         return ;
00416                 }
00417 
00418                 // Note: mData.sleeping gets updated in Solid::getData.
00419 
00420                 if ( sleeping )
00421                 {
00422                         dBodyDisable( mBodyID );
00423                 }
00424                 else
00425                 {
00426                         dBodyEnable( mBodyID );
00427                 }
00428         }
00429 
00430         bool ODESolid::isSleeping() const
00431         {
00432                 if ( mData.isStatic )
00433                 {
00434                         return true;
00435                 }
00436 
00437                 // The ODE body may fall asleep at unknown times, so we need to
00438                 // get the data straight from ODE.
00439                 if ( dBodyIsEnabled( mBodyID ) )
00440                 {
00441                         return false;
00442                 }
00443                 else
00444                 {
00445                         return true;
00446                 }
00447         }
00448 
00449         void ODESolid::setSleepiness( real s )
00450         {
00451                 Solid::setSleepiness( s );
00452 
00456                 if ( mData.isStatic )
00457                 {
00458                         return ;
00459                 }
00460 
00461                 if ( 0 == s )
00462                 {
00463                         // No sleeping at all for the Solid.
00464                         dBodySetAutoDisableFlag( mBodyID, false );
00465                 }
00466                 else
00467                 {
00468                         // Enable sleeping for the Solid..
00469                         dBodySetAutoDisableFlag( mBodyID, true );
00470                 }
00471 
00472                 // As value goes from 0.0 to 1.0:
00473                 // AutoDisableLinearThreshold goes from min to max,
00474                 // AutoDisableAngularThreshold goes from min to max,
00475                 // AutoDisableSteps goes from max to min,
00476                 // AutoDisableTime goes from max to min.
00477 
00478                 real range = defaults::ode::autoDisableLinearMax -
00479                              defaults::ode::autoDisableLinearMin;
00480                 dBodySetAutoDisableLinearThreshold( mBodyID, s * range +
00481                                                     defaults::ode::autoDisableLinearMin );
00482 
00483                 range = defaults::ode::autoDisableAngularMax -
00484                         defaults::ode::autoDisableAngularMin;
00485                 dBodySetAutoDisableAngularThreshold( mBodyID, s * range +
00486                                                      defaults::ode::autoDisableAngularMin );
00487 
00488                 range = ( real ) ( defaults::ode::autoDisableStepsMax -
00489                                    defaults::ode::autoDisableStepsMin );
00490                 dBodySetAutoDisableSteps( mBodyID,
00491                                           ( int ) ( ( real ) defaults::ode::autoDisableStepsMax - s * range ) );
00492 
00493                 range = defaults::ode::autoDisableTimeMax -
00494                         defaults::ode::autoDisableTimeMin;
00495                 dBodySetAutoDisableTime( mBodyID,
00496                                          defaults::ode::autoDisableTimeMax - s * range );
00497         }
00498 
00499         void ODESolid::translateMass( const Vec3r& offset )
00500         {
00501                 if ( !mData.isStatic )
00502                 {
00503                         dMass m;
00504                         dBodyGetMass( mBodyID, &m );
00505                         dMassTranslate( &m, offset[ 0 ], offset[ 1 ], offset[ 2 ] );
00506                         dBodySetMass( mBodyID, &m );
00507 
00508                         // Update this since the mass changed.
00509                         mNonSymmetricInertia = isInertiaNonSymmetric( m );
00510                 }
00511         }
00512 
00513         void ODESolid::addShape( ShapeData& data )
00514         {
00515                 assert( data.material.density >= 0 );
00516 
00517                 dGeomID newGeomID = NULL;
00518                 dGeomID newTransformID = NULL;
00519                 dTriMeshDataID newTrimeshDataID = NULL;
00520                 dSpaceID spaceID = NULL;
00521                 dMass newMass;
00522 
00523                 if ( Matrix44r() == data.offset )
00524                 {
00525                         // No offset transform.
00526                         spaceID = mSpaceID;
00527                         newTransformID = 0;
00528                 }
00529                 else
00530                 {
00531                         // Use ODE's geom transform object.
00532                         spaceID = 0;
00533                         newTransformID = dCreateGeomTransform( mSpaceID );
00534                 }
00535 
00536                 // Allocate a new GeomData object.
00537                 GeomData* newGeomData = new GeomData;
00538 
00539                 switch ( data.getType() )
00540                 {
00541                         case BOX_SHAPE:
00542                                 {
00543                                         BoxShapeData & boxData = ( BoxShapeData& ) data;
00544                                         newGeomID = dCreateBox( spaceID,
00545                                                                 ( dReal ) boxData.dimensions[ 0 ],
00546                                                                 ( dReal ) boxData.dimensions[ 1 ],
00547                                                                 ( dReal ) boxData.dimensions[ 2 ] );
00548                                         dMassSetBox( &newMass, ( dReal ) data.material.density,
00549                                                      ( dReal ) boxData.dimensions[ 0 ],
00550                                                      ( dReal ) boxData.dimensions[ 1 ],
00551                                                      ( dReal ) boxData.dimensions[ 2 ] );
00552                                         break;
00553                                 }
00554                         case SPHERE_SHAPE:
00555                                 {
00556                                         SphereShapeData& sphereData = ( SphereShapeData& ) data;
00557                                         newGeomID = dCreateSphere( spaceID,
00558                                                                    ( dReal ) sphereData.radius );
00559                                         dMassSetSphere( &newMass, ( dReal ) data.material.density,
00560                                                         ( dReal ) sphereData.radius );
00561                                         break;
00562                                 }
00563                         case CAPSULE_SHAPE:
00564                                 {
00565                                         CapsuleShapeData& capsuleData = ( CapsuleShapeData& ) data;
00566                                         newGeomID = dCreateCCylinder( spaceID,
00567                                                                       ( dReal ) capsuleData.radius, ( dReal ) capsuleData.length );
00568 
00569                                         // The "direction" parameter orients the mass along one of the
00570                                         // body's local axes; x=1, y=2, z=3.  This axis MUST
00571                                         // correspond with the axis along which the capsule is
00572                                         // initially aligned, which is the capsule's local Z axis.
00573                                         dMassSetCappedCylinder( &newMass, ( dReal ) data.material.density,
00574                                                                 3, ( dReal ) capsuleData.radius, ( dReal ) capsuleData.length );
00575                                         break;
00576                                 }
00577                         case PLANE_SHAPE:
00578                                 {
00579                                         PlaneShapeData& planeData = ( PlaneShapeData& ) data;
00580                                         if ( !mData.isStatic )
00581                                         {
00582                                                 OPAL_LOGGER( "warning" ) << "opal::ODESolid::addPlane: " <<
00583                                                 "Plane Shape added to a non-static Solid.  " <<
00584                                                 "The Solid will be made static." << std::endl;
00585 
00586                                                 // ODE planes can't have bodies, so make it static.
00587                                                 setStatic( true );
00588                                         }
00589 
00590                                         // TODO: make this fail gracefully and print warning: plane
00591                                         // offset transform ignored.
00592                                         assert( !newTransformID );
00593 
00594                                         // ODE planes must have their normal vector (abc) normalized.
00595                                         Vec3r normal( planeData.abcd[ 0 ], planeData.abcd[ 1 ],
00596                                                       planeData.abcd[ 2 ] );
00597                                         normal.normalize();
00598 
00599                                         newGeomID = dCreatePlane( spaceID, ( dReal ) normal[ 0 ],
00600                                                                   ( dReal ) normal[ 1 ], ( dReal ) normal[ 2 ],
00601                                                                   ( dReal ) planeData.abcd[ 3 ] );
00602 
00603                                         // Note: ODE planes cannot have mass, but this is already
00604                                         // handled since static Solids ignore mass.
00605 
00606                                         // Solids with planes are the only non-"placeable" Solids.
00607                                         mIsPlaceable = false;
00608                                         break;
00609                                 }
00610                                 //case RAY_SHAPE:
00611                                 //{
00612                                 //      RayShapeData& rayData = (RayShapeData&)data;
00613                                 //      newGeomID = dCreateRay(spaceID,
00614                                 //              (dReal)rayData.ray.getLength());
00615                                 //      Point3r origin = rayData.ray.getOrigin();
00616                                 //      Vec3r dir = rayData.ray.getDir();
00617                                 //      dGeomRaySet(newGeomID, (dReal)origin[0], (dReal)origin[1],
00618                                 //              (dReal)origin[2], (dReal)dir[0], (dReal)dir[1],
00619                                 //              (dReal)dir[2]);
00620                                 //      // Note: rays don't have mass.
00621                                 //      break;
00622                                 //}
00623                         case MESH_SHAPE:
00624                                 {
00625                                         MeshShapeData& meshData = ( MeshShapeData& ) data;
00626 
00627                                         // Setup trimesh data pointer.  It is critical that the
00628                                         // size of OPAL reals at this point match the size of ODE's
00629                                         // dReals.
00630                                         newTrimeshDataID = dGeomTriMeshDataCreate();
00631 
00632                                         // Old way... This is problematic because ODE interprets
00633                                         // the vertex array as an array of dVector3s which each
00634                                         // have 4 elements.
00635                                         //dGeomTriMeshDataBuildSimple(newTrimeshDataID,
00636                                         //      (dReal*)meshData.vertexArray, meshData.numVertices,
00637                                         //      (int*)meshData.triangleArray, 3 * meshData.numTriangles);
00638 
00639 #ifdef dSINGLE
00640                                         dGeomTriMeshDataBuildSingle( newTrimeshDataID,
00641                                                                      ( void* ) meshData.vertexArray, 3 * sizeof( real ),
00642                                                                      meshData.numVertices, ( void* ) meshData.triangleArray,
00643                                                                      3 * meshData.numTriangles, 3 * sizeof( unsigned int ) );
00644 #else
00645                                         dGeomTriMeshDataBuildDouble( newTrimeshDataID,
00646                                                                                                  ( void* ) meshData.vertexArray, 3 * sizeof( real ),
00647                                                                                                  meshData.numVertices, ( void* ) meshData.triangleArray,
00648                                                                                                  3 * meshData.numTriangles, 3 * sizeof( unsigned int ) );
00649 #endif
00650 
00651                                         newGeomID = dCreateTriMesh( spaceID,
00652                                                                     newTrimeshDataID, NULL, NULL, NULL );
00653 
00654                                         // This is a simple way to set the mass of an arbitrary
00655                                         // mesh.  Ideally we would compute the exact volume and
00656                                         // intertia tensor.  Instead we just use a box
00657                                         // inertia tensor from its axis-aligned bounding box.
00658                                         dReal aabb[ 6 ];
00659                                         dGeomGetAABB( newGeomID, aabb );
00660                                         dMassSetBox( &newMass, ( dReal ) data.material.density,
00661                                                      aabb[ 1 ] - aabb[ 0 ], aabb[ 3 ] - aabb[ 2 ],
00662                                                      aabb[ 5 ] - aabb[ 4 ] );
00663                                         break;
00664                                 }
00665                         default:
00666                                 assert( false );
00667                 }
00668 
00669                 // This will do nothing if this is a static Solid.
00670                 addMass( newMass, data.offset );
00671 
00672                 // Store new Shape.
00673                 mData.addShape( data );
00674 
00675                 // Update the Solid's local AABB.  The new shape's local AABB
00676                 // must be transformed using the shape's offset from the Solid.
00677                 real shapeAABB[ 6 ] = {0, 0, 0, 0, 0, 0};
00678                 data.getLocalAABB( shapeAABB );
00679                 Point3r minExtents( shapeAABB[ 0 ], shapeAABB[ 2 ], shapeAABB[ 4 ] );
00680                 Point3r maxExtents( shapeAABB[ 1 ], shapeAABB[ 3 ], shapeAABB[ 5 ] );
00681                 minExtents = data.offset * minExtents;
00682                 maxExtents = data.offset * maxExtents;
00683                 shapeAABB[ 0 ] = minExtents[ 0 ];
00684                 shapeAABB[ 1 ] = maxExtents[ 0 ];
00685                 shapeAABB[ 2 ] = minExtents[ 1 ];
00686                 shapeAABB[ 3 ] = maxExtents[ 1 ];
00687                 shapeAABB[ 4 ] = minExtents[ 2 ];
00688                 shapeAABB[ 5 ] = maxExtents[ 2 ];
00689                 addToLocalAABB( shapeAABB );
00690 
00691                 // Setup GeomData.
00692                 newGeomData->solid = this;
00693                 newGeomData->shape = mData.getShapeData( mData.getNumShapes() - 1 );
00694                 newGeomData->geomID = newGeomID;
00695                 newGeomData->transformID = newTransformID;
00696                 newGeomData->spaceID = mSpaceID;
00697                 newGeomData->trimeshDataID = newTrimeshDataID;
00698 
00699                 // Setup the geom.
00700                 setupNewGeom( newGeomData );
00701         }
00702 
00703         void ODESolid::setLocalLinearVel( const Vec3r& vel )
00704         {
00705                 if ( !mData.isStatic )
00706                 {
00707                         dVector3 worldVel;
00708                         dBodyVectorToWorld( mBodyID, vel[ 0 ], vel[ 1 ], vel[ 2 ], worldVel );
00709                         dBodySetLinearVel( mBodyID, worldVel[ 0 ], worldVel[ 1 ], worldVel[ 2 ] );
00710 
00711                         // Invalidate the "freely-spinning" parameter.
00712                         internal_setFreelySpinning( false );
00713                 }
00714         }
00715 
00716         Vec3r ODESolid::getLocalLinearVel() const
00717         {
00718                 if ( !mData.isStatic )
00719                 {
00720                         const dReal * vel = dBodyGetLinearVel( mBodyID );
00721 
00722                         // Convert the vector from global to local coordinates.
00723                         dVector3 localVel;
00724                         dBodyVectorFromWorld( mBodyID, vel[ 0 ], vel[ 1 ], vel[ 2 ], localVel );
00725                         return toVec3r( localVel );
00726                 }
00727                 else
00728                 {
00729                         return Vec3r( 0, 0, 0 );
00730                 }
00731         }
00732 
00733         Vec3r ODESolid::getLocalLinearVelAtLocalPos( const Point3r& p ) const
00734         {
00735                 if ( !mData.isStatic )
00736                 {
00737                         // First find the global velocity at the given point.
00738                         dVector3 result;
00739                         dBodyGetRelPointVel( mBodyID, p[ 0 ], p[ 1 ], p[ 2 ], result );
00740 
00741                         // Now convert the velocity from global to local coordinates.
00742                         dBodyVectorFromWorld( mBodyID, result[ 0 ], result[ 1 ], result[ 2 ],
00743                                               result );
00744                         return toVec3r( result );
00745                 }
00746                 else
00747                 {
00748                         return Vec3r( 0, 0, 0 );
00749                 }
00750         }
00751 
00752         void ODESolid::setLocalAngularVel( const Vec3r& vel )
00753         {
00754                 if ( !mData.isStatic )
00755                 {
00756                         dVector3 worldVel;
00757                         dBodyVectorToWorld( mBodyID, vel[ 0 ], vel[ 1 ], vel[ 2 ], worldVel );
00758                         Vec3r velRad = toVec3r_DegToRad( worldVel );
00759                         dBodySetAngularVel( mBodyID, velRad[ 0 ], velRad[ 1 ], velRad[ 2 ] );
00760 
00761                         // Invalidate the "freely-spinning" parameter.
00762                         internal_setFreelySpinning( false );
00763                 }
00764         }
00765 
00766         Vec3r ODESolid::getLocalAngularVel() const
00767         {
00768                 if ( !mData.isStatic )
00769                 {
00770                         const dReal * vel = dBodyGetAngularVel( mBodyID );
00771 
00772                         // Convert the vector from global to local coordinates.
00773                         dVector3 localVel;
00774                         dBodyVectorFromWorld( mBodyID, vel[ 0 ], vel[ 1 ], vel[ 2 ], localVel );
00775                         return toVec3r_RadToDeg( localVel );
00776                 }
00777                 else
00778                 {
00779                         return Vec3r( 0, 0, 0 );
00780                 }
00781         }
00782 
00783         void ODESolid::setGlobalLinearVel( const Vec3r& vel )
00784         {
00785                 if ( !mData.isStatic )
00786                 {
00787                         dBodySetLinearVel( mBodyID, vel[ 0 ], vel[ 1 ], vel[ 2 ] );
00788 
00789                         // Invalidate the "freely-spinning" parameter.
00790                         internal_setFreelySpinning( false );
00791                 }
00792         }
00793 
00794         Vec3r ODESolid::getGlobalLinearVel() const
00795         {
00796                 if ( !mData.isStatic )
00797                 {
00798                         const dReal * vel = dBodyGetLinearVel( mBodyID );
00799                         return toVec3r( vel );
00800                 }
00801                 else
00802                 {
00803                         return Vec3r( 0, 0, 0 );
00804                 }
00805         }
00806 
00807         Vec3r ODESolid::getGlobalLinearVelAtLocalPos( const Point3r& p ) const
00808         {
00809                 if ( !mData.isStatic )
00810                 {
00811                         // First find the global velocity at the given point.
00812                         dVector3 result;
00813                         dBodyGetRelPointVel( mBodyID, p[ 0 ], p[ 1 ], p[ 2 ], result );
00814                         return toVec3r( result );
00815                 }
00816                 else
00817                 {
00818                         return Vec3r( 0, 0, 0 );
00819                 }
00820         }
00821 
00822         void ODESolid::setGlobalAngularVel( const Vec3r& vel )
00823         {
00824                 if ( !mData.isStatic )
00825                 {
00826                         Vec3r velRad( degToRad( vel[ 0 ] ), degToRad( vel[ 1 ] ), degToRad( vel[ 2 ] ) );
00827                         dBodySetAngularVel( mBodyID, velRad[ 0 ], velRad[ 1 ], velRad[ 2 ] );
00828 
00829                         // Invalidate the "freely-spinning" parameter.
00830                         internal_setFreelySpinning( false );
00831                 }
00832         }
00833 
00834         Vec3r ODESolid::getGlobalAngularVel() const
00835         {
00836                 if ( !mData.isStatic )
00837                 {
00838                         const dReal * vel = dBodyGetAngularVel( mBodyID );
00839                         return toVec3r_RadToDeg( vel );
00840                 }
00841                 else
00842                 {
00843                         return Vec3r( 0, 0, 0 );
00844                 }
00845         }
00846 
00847         dBodyID ODESolid::internal_getBodyID() const
00848         {
00849                 return mBodyID;
00850         }
00851 
00852         void ODESolid::internal_setCollisionCount( long int count )
00853         {
00854                 mCollisionCount = count;
00855         }
00856 
00857         long int ODESolid::internal_getCollisionCount() const
00858         {
00859                 return mCollisionCount;
00860         }
00861 
00862         //void ODESolid::setFastRotation(bool fast)
00863         //{
00864         //      if (mStatic)
00865         //      {
00866         //              return;
00867         //      }
00868         //
00869         //      if (fast)
00870         //      {
00871         //              //if used, call dBodySetFiniteRotationAxis every step; see ODE docs
00872         //              dBodySetFiniteRotationMode(mBodyID, 1);
00873         //      }
00874         //      else
00875         //      {
00876         //              dBodySetFiniteRotationMode(mBodyID, 0);
00877         //      }
00878         //}
00879 
00880         //bool ODESolid::getFastRotation()const
00881         //{
00882         //      if (mStatic)
00883         //      {
00884         //              return false;
00885         //      }
00886         //
00887         //      if(1 == dBodyGetFiniteRotationMode(mBodyID))
00888         //      {
00889         //              return true;
00890         //      }
00891         //      else
00892         //      {
00893         //              return false;
00894         //      }
00895         //}
00896 
00897         //void ODESolid::setFastRotationAxis(Vec3r axis)
00898         //{
00899         //      dBodySetFiniteRotationAxis(mBodyID, axis[0], axis[1], axis[2]);
00900         //}
00901 
00902         void ODESolid::zeroForces()
00903         {
00904                 if ( !mData.isStatic )
00905                 {
00906                         dBodySetForce( mBodyID, 0, 0, 0 );
00907                         dBodySetTorque( mBodyID, 0, 0, 0 );
00908 
00909                         while ( !mForceList.empty() )
00910                         {
00911                                 mForceList.pop_back();
00912                         }
00913                 }
00914         }
00915 
00916         real ODESolid::getMass() const
00917         {
00918                 if ( mData.isStatic )
00919                 {
00920                         return 0;
00921                 }
00922                 else
00923                 {
00924                         dMass mass;
00925                         dBodyGetMass( mBodyID, &mass );
00926                         return ( real ) mass.mass;
00927                 }
00928         }
00929 
00930         Matrix44r ODESolid::getInertiaTensor() const
00931         {
00932                 Matrix44r m;
00933 
00934                 if ( mData.isStatic )
00935                 {
00936                         return m;
00937                 }
00938                 else
00939                 {
00940                         dMass mass;
00941                         dBodyGetMass( mBodyID, &mass );
00942                         m.set(
00943                             ( real ) mass.I[ 0 ], ( real ) mass.I[ 1 ], ( real ) mass.I[ 2 ], 0,
00944                             ( real ) mass.I[ 4 ], ( real ) mass.I[ 5 ], ( real ) mass.I[ 6 ], 0,
00945                             ( real ) mass.I[ 8 ], ( real ) mass.I[ 9 ], ( real ) mass.I[ 10 ], 0,
00946                             0, 0, 0, 1 );
00947 
00948                         return m;
00949                 }
00950         }
00951 
00952         void ODESolid::setupNewGeom( GeomData* newGeom )
00953         {
00954                 if ( !mData.isStatic )
00955                 {
00956                         if ( 0 == newGeom->transformID )
00957                         {
00958                                 // No geom transform.
00959                                 dGeomSetBody( newGeom->geomID, mBodyID );
00960                         }
00961                         else
00962                         {
00963                                 // Use geom transform.
00964                                 dGeomSetBody( newGeom->transformID, mBodyID );
00965                         }
00966                 }
00967 
00968                 if ( 0 != newGeom->transformID )
00969                 {
00970                         // Setup geom transform.
00971                         dGeomTransformSetGeom( newGeom->transformID, newGeom->geomID );
00972                         dMatrix3 R =
00973                             {newGeom->shape->offset[ 0 ], newGeom->shape->offset[ 4 ],
00974                              newGeom->shape->offset[ 8 ], 0,
00975                              newGeom->shape->offset[ 1 ], newGeom->shape->offset[ 5 ],
00976                              newGeom->shape->offset[ 9 ], 0,
00977                              newGeom->shape->offset[ 2 ], newGeom->shape->offset[ 6 ],
00978                              newGeom->shape->offset[ 10 ], 0};
00979                         dGeomSetRotation( newGeom->geomID, R );
00980                         dGeomSetPosition( newGeom->geomID, newGeom->shape->offset[ 12 ],
00981                                           newGeom->shape->offset[ 13 ],
00982                                           newGeom->shape->offset[ 14 ] );
00983                 }
00984 
00985                 // Set the GeomData reference for later use (e.g. in collision
00986                 // handling).
00987                 if ( 0 == newGeom->transformID )
00988                 {
00989                         // No geom transform.
00990                         dGeomSetData( newGeom->geomID, newGeom );
00991                 }
00992                 else
00993                 {
00994                         // Using geom transform.
00995                         dGeomSetData( newGeom->transformID, newGeom );
00996                 }
00997 
00998                 // Store the GeomData pointer.
00999                 mGeomDataList.push_back( newGeom );
01000 
01001                 // Make sure the initial transform is setup; this needs to come after
01002                 // the geom data has been added.
01003                 if ( mData.isStatic && mIsPlaceable )
01004                 {
01005                         setTransform( mData.transform );
01006                 }
01007         }
01008 
01009         void ODESolid::applyForce( const Force& f )
01010         {
01011                 switch ( f.type )
01012                 {
01013                         case LOCAL_FORCE:
01014                                 dBodyAddRelForce( mBodyID, f.vec[ 0 ], f.vec[ 1 ], f.vec[ 2 ] );
01015                                 break;
01016                         case GLOBAL_FORCE:
01017                                 dBodyAddForce( mBodyID, f.vec[ 0 ], f.vec[ 1 ], f.vec[ 2 ] );
01018                                 break;
01019                         case LOCAL_TORQUE:
01020                                 dBodyAddRelTorque( mBodyID, f.vec[ 0 ], f.vec[ 1 ], f.vec[ 2 ] );
01021                                 break;
01022                         case GLOBAL_TORQUE:
01023                                 dBodyAddTorque( mBodyID, f.vec[ 0 ], f.vec[ 1 ], f.vec[ 2 ] );
01024                                 break;
01025                         case LOCAL_FORCE_AT_LOCAL_POS:
01026                                 dBodyAddRelForceAtRelPos( mBodyID, f.vec[ 0 ], f.vec[ 1 ],
01027                                                           f.vec[ 2 ], f.pos[ 0 ], f.pos[ 1 ], f.pos[ 2 ] );
01028                                 break;
01029                         case LOCAL_FORCE_AT_GLOBAL_POS:
01030                                 dBodyAddRelForceAtPos( mBodyID, f.vec[ 0 ], f.vec[ 1 ], f.vec[ 2 ],
01031                                                        f.pos[ 0 ], f.pos[ 1 ], f.pos[ 2 ] );
01032                                 break;
01033                         case GLOBAL_FORCE_AT_LOCAL_POS:
01034                                 dBodyAddForceAtRelPos( mBodyID, f.vec[ 0 ], f.vec[ 1 ], f.vec[ 2 ],
01035                                                        f.pos[ 0 ], f.pos[ 1 ], f.pos[ 2 ] );
01036                                 break;
01037                         case GLOBAL_FORCE_AT_GLOBAL_POS:
01038                                 dBodyAddForceAtPos( mBodyID, f.vec[ 0 ], f.vec[ 1 ], f.vec[ 2 ],
01039                                                     f.pos[ 0 ], f.pos[ 1 ], f.pos[ 2 ] );
01040                                 break;
01041                 }
01042 
01043                 // Invalidate the "freely-spinning" parameter.
01044                 internal_setFreelySpinning( false );
01045         }
01046 
01047         void ODESolid::setMass( const Mass & newmass, const Matrix44r & offset )
01048         {
01049                 if ( mData.isStatic )
01050                 {
01051                         return ;
01052                 }
01053 
01054                 // first create mass object
01055                 dMass newMass;
01056                 newMass.setParameters( newmass.mass,
01057                                        newmass.center.x,
01058                                        newmass.center.y,
01059                                        newmass.center.z,
01060                                        newmass.inertia[ 0 ],
01061                                        newmass.inertia[ 5 ],
01062                                        newmass.inertia[ 10 ],
01063                                        newmass.inertia[ 1 ],
01064                                        newmass.inertia[ 2 ],
01065                                        newmass.inertia[ 6 ] );
01066 
01067                 // First rotate and translate the new mass.
01068                 dMatrix3 R = {offset[ 0 ], offset[ 4 ], offset[ 8 ], 0,
01069                               offset[ 1 ], offset[ 5 ], offset[ 9 ], 0,
01070                               offset[ 2 ], offset[ 6 ], offset[ 10 ], 0};
01071 
01072                 dMassRotate( &newMass, R );
01073                 dMassTranslate( &newMass, offset[ 12 ], offset[ 13 ], offset[ 14 ] );
01074 
01075                 dBodySetMass( mBodyID, &newMass );
01076 
01077                 // Update this since the mass changed.
01078                 dMass m;
01079                 dBodyGetMass( mBodyID, &m );
01080                 mNonSymmetricInertia = isInertiaNonSymmetric( m );
01081         }
01082 
01083         void ODESolid::addMass( dMass& newMass, const Matrix44r& offset )
01084         {
01085                 if ( mData.isStatic )
01086                 {
01087                         return ;
01088                 }
01089 
01090                 // First rotate and translate the new mass.
01091                 dMatrix3 R = {offset[ 0 ], offset[ 4 ], offset[ 8 ], 0,
01092                               offset[ 1 ], offset[ 5 ], offset[ 9 ], 0,
01093                               offset[ 2 ], offset[ 6 ], offset[ 10 ], 0};
01094 
01095                 dMassRotate( &newMass, R );
01096                 dMassTranslate( &newMass, offset[ 12 ], offset[ 13 ], offset[ 14 ] );
01097 
01098                 // If this mass is for the first Shape, just set the Solid's mass
01099                 // equal to the new one.  ODE bodies start with an initial mass
01100                 // already setup, but we want to ignore that, not add to it.
01101                 if ( 0 == mGeomDataList.size() )
01102                 {
01103                         dBodySetMass( mBodyID, &newMass );
01104                 }
01105                 else
01106                 {
01107                         // Add new mass to the Solid's existing mass.  First get the
01108                         // existing mass struct from ODE.
01109                         dMass totalMass;
01110                         dBodyGetMass( mBodyID, &totalMass );
01111                         dMassAdd( &totalMass, &newMass );
01112                         dBodySetMass( mBodyID, &totalMass );
01113                 }
01114 
01115                 // Update this since the mass changed.
01116                 dMass m;
01117                 dBodyGetMass( mBodyID, &m );
01118                 mNonSymmetricInertia = isInertiaNonSymmetric( m );
01119         }
01120 
01121         void ODESolid::setMass( dMass& newMass, const Matrix44r& offset )
01122         {
01123                 if ( mData.isStatic )
01124                 {
01125                         return ;
01126                 }
01127 
01128                 // First rotate and translate the new mass.
01129                 dMatrix3 R = {offset[ 0 ], offset[ 4 ], offset[ 8 ], 0,
01130                               offset[ 1 ], offset[ 5 ], offset[ 9 ], 0,
01131                               offset[ 2 ], offset[ 6 ], offset[ 10 ], 0};
01132 
01133                 dMassRotate( &newMass, R );
01134                 dMassTranslate( &newMass, offset[ 12 ], offset[ 13 ], offset[ 14 ] );
01135 
01136                 dBodySetMass( mBodyID, &newMass );
01137 
01138                 // Update this since the mass changed.
01139                 dMass m;
01140                 dBodyGetMass( mBodyID, &m );
01141                 mNonSymmetricInertia = isInertiaNonSymmetric( m );
01142         }
01143 
01144         const std::vector<GeomData*>* ODESolid::internal_getGeomDataList() const
01145         {
01146                 return & mGeomDataList;
01147         }
01148 
01149         void ODESolid::internal_doAngularVelFix()
01150         {
01151                 if ( mNonSymmetricInertia )
01152                 {
01153                         Vec3r vel = getGlobalAngularVel();
01154                         real currentAngVelMagSquared = vel.lengthSquared();
01155 
01156                         if ( mIsFreelySpinning )
01157                         {
01158                                 // If the current angular velocity magnitude is greater than
01159                                 // that of the previous step, scale it by that of the previous
01160                                 // step; otherwise, update the previous value to that of the
01161                                 // current step.  This ensures that angular velocity never
01162                                 // increases for freely-spinning objects.
01163 
01164                                 if ( currentAngVelMagSquared > mPrevAngVelMagSquared )
01165                                 {
01166                                         real currentAngVelMag = sqrt( currentAngVelMagSquared );
01167                                         vel = vel / currentAngVelMag;
01168                                         // Vel is now a unit vector.  Next, scale this vector
01169                                         // by the previous angular velocity magnitude.
01170                                         real prevAngVelMag = sqrt( mPrevAngVelMagSquared );
01171                                         setGlobalAngularVel( vel * prevAngVelMag );
01172                                 }
01173                         }
01174 
01175                         mPrevAngVelMagSquared = currentAngVelMagSquared;
01176                 }
01177 
01178                 // Reset the "freely-spinning" parameter for the next time step.
01179                 internal_setFreelySpinning( true );
01180         }
01181 
01182         void ODESolid::internal_setFreelySpinning( bool fs )
01183         {
01184                 mIsFreelySpinning = fs;
01185         }
01186 
01187         bool ODESolid::isInertiaNonSymmetric( const dMass& mass ) const
01188         {
01189                 if ( !areEqual( ( real ) mass.I[ 0 ], ( real ) mass.I[ 5 ] )
01190                         || !areEqual( ( real ) mass.I[ 5 ], ( real ) mass.I[ 10 ] ) )
01191                 {
01192                         return true;
01193                 }
01194                 else
01195                 {
01196                         return false;
01197                 }
01198         }
01199 }

Generated on Tue May 16 17:49:51 2006 for OPAL by  doxygen 1.4.6-NO