00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "ODESolid.h"
00030
00031
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
00057
00058
00059
00060 mBodyID = dBodyCreate( mWorldID );
00061 }
00062
00063 init( mData );
00064 }
00065
00066 ODESolid::~ODESolid()
00067 {
00068 destroyGeoms();
00069
00070 if ( !mData.isStatic )
00071 {
00072
00073
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
00097
00098
00099 dGeomTriMeshDataDestroy( mGeomDataList[ i ] ->trimeshDataID );
00100 }
00101
00102
00103 dGeomDestroy( mGeomDataList[ i ] ->geomID );
00104
00105
00106 delete mGeomDataList[ i ];
00107 }
00108 mGeomDataList.clear();
00109 }
00110
00111 void ODESolid::init( const SolidData& data )
00112 {
00113
00114
00115
00116 mData.destroyShapes();
00117
00118
00119 destroyGeoms();
00120
00121
00122 setStatic( data.isStatic );
00123
00124
00125 setTransform( data.transform );
00126
00127
00128 for ( unsigned int i = 0; i < data.getNumShapes(); ++i )
00129 {
00130 addShape( *( data.getShapeData( i ) ) );
00131 }
00132
00133
00134 setSleeping( data.sleeping );
00135
00136
00137 setSleepiness( data.sleepiness );
00138
00139
00140 setEnabled( data.enabled );
00141
00142
00143 setLinearDamping( data.linearDamping );
00144 setAngularDamping( data.angularDamping );
00145
00146
00147 setGlobalLinearVel( data.globalLinearVel );
00148 setGlobalAngularVel( data.globalAngularVel );
00149
00150
00151 setName( data.name );
00152 }
00153
00154 void ODESolid::setEnabled( bool e )
00155 {
00156 if ( e )
00157 {
00158
00159 if ( !mData.isStatic )
00160 {
00161 dBodyEnable( mBodyID );
00162 }
00163
00164
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
00173 {
00174
00175 if ( !mData.isStatic )
00176 {
00177 dBodyDisable( mBodyID );
00178 }
00179
00180
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
00224 dGeomSetRotation( geomData->geomID, R );
00225 dGeomSetPosition( geomData->geomID, mData.transform[ 12 ],
00226 mData.transform[ 13 ], mData.transform[ 14 ] );
00227 }
00228 else
00229 {
00230
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
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
00255 mData.isStatic = false;
00256
00257
00258 mBodyID = dBodyCreate( mWorldID );
00259
00260
00261
00262 setSleepiness( mData.sleepiness );
00263
00264
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
00276 std::vector<GeomData*>::iterator iter;
00277 for ( iter = mGeomDataList.begin();
00278 iter != mGeomDataList.end(); ++iter )
00279 {
00280 dMass newMass;
00281
00282
00283 ShapeData* shapeData = ( *iter ) ->shape;
00284
00285
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
00319 break;
00320
00321
00322
00323 case MESH_SHAPE:
00324
00325
00326
00327
00328
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
00341 if ( iter == mGeomDataList.begin() )
00342 setMass( newMass, shapeData->offset );
00343 else
00344 addMass( newMass, shapeData->offset );
00345
00346
00347 if ( 0 == ( *iter ) ->transformID )
00348 {
00349
00350 dGeomSetBody( ( *iter ) ->geomID, mBodyID );
00351 }
00352 else
00353 {
00354
00355 dGeomSetBody( ( *iter ) ->transformID, mBodyID );
00356 }
00357 }
00358
00359 moveToSpace();
00360 }
00361 else
00362 {
00363
00364 }
00365 }
00366 else
00367 {
00368 if ( true == s )
00369 {
00370
00371 mData.isStatic = true;
00372
00373
00374 dBodyDestroy( mBodyID );
00375
00376 moveToSpace();
00377 }
00378 else
00379 {
00380
00381 }
00382 }
00383 }
00384
00385 void ODESolid::moveToSpace()
00386 {
00387
00388
00389 std::vector<GeomData*>::iterator iter;
00390 for ( iter = mGeomDataList.begin(); iter != mGeomDataList.end();
00391 ++iter )
00392 {
00393 if ( 0 != ( *iter ) ->transformID )
00394 {
00395
00396
00397 dSpaceRemove( ( *iter ) ->spaceID, ( *iter ) ->transformID );
00398 dSpaceAdd( mSpaceID, ( *iter ) ->transformID );
00399 }
00400 else
00401 {
00402
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
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
00438
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
00464 dBodySetAutoDisableFlag( mBodyID, false );
00465 }
00466 else
00467 {
00468
00469 dBodySetAutoDisableFlag( mBodyID, true );
00470 }
00471
00472
00473
00474
00475
00476
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
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
00526 spaceID = mSpaceID;
00527 newTransformID = 0;
00528 }
00529 else
00530 {
00531
00532 spaceID = 0;
00533 newTransformID = dCreateGeomTransform( mSpaceID );
00534 }
00535
00536
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
00570
00571
00572
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
00587 setStatic( true );
00588 }
00589
00590
00591
00592 assert( !newTransformID );
00593
00594
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
00604
00605
00606
00607 mIsPlaceable = false;
00608 break;
00609 }
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 case MESH_SHAPE:
00624 {
00625 MeshShapeData& meshData = ( MeshShapeData& ) data;
00626
00627
00628
00629
00630 newTrimeshDataID = dGeomTriMeshDataCreate();
00631
00632
00633
00634
00635
00636
00637
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
00655
00656
00657
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
00670 addMass( newMass, data.offset );
00671
00672
00673 mData.addShape( data );
00674
00675
00676
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
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
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
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
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
00738 dVector3 result;
00739 dBodyGetRelPointVel( mBodyID, p[ 0 ], p[ 1 ], p[ 2 ], result );
00740
00741
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
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
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
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
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
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
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
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
00959 dGeomSetBody( newGeom->geomID, mBodyID );
00960 }
00961 else
00962 {
00963
00964 dGeomSetBody( newGeom->transformID, mBodyID );
00965 }
00966 }
00967
00968 if ( 0 != newGeom->transformID )
00969 {
00970
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
00986
00987 if ( 0 == newGeom->transformID )
00988 {
00989
00990 dGeomSetData( newGeom->geomID, newGeom );
00991 }
00992 else
00993 {
00994
00995 dGeomSetData( newGeom->transformID, newGeom );
00996 }
00997
00998
00999 mGeomDataList.push_back( newGeom );
01000
01001
01002
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
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
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
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
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
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
01099
01100
01101 if ( 0 == mGeomDataList.size() )
01102 {
01103 dBodySetMass( mBodyID, &newMass );
01104 }
01105 else
01106 {
01107
01108
01109 dMass totalMass;
01110 dBodyGetMass( mBodyID, &totalMass );
01111 dMassAdd( &totalMass, &newMass );
01112 dBodySetMass( mBodyID, &totalMass );
01113 }
01114
01115
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
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
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
01159
01160
01161
01162
01163
01164 if ( currentAngVelMagSquared > mPrevAngVelMagSquared )
01165 {
01166 real currentAngVelMag = sqrt( currentAngVelMagSquared );
01167 vel = vel / currentAngVelMag;
01168
01169
01170 real prevAngVelMag = sqrt( mPrevAngVelMagSquared );
01171 setGlobalAngularVel( vel * prevAngVelMag );
01172 }
01173 }
01174
01175 mPrevAngVelMagSquared = currentAngVelMagSquared;
01176 }
01177
01178
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 }