00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "world.h"
00021 #include "phyobject.h"
00022 #include "phyjoint.h"
00023 #include "private/phyobjectprivate.h"
00024 #include "private/worldprivate.h"
00025 #include "motorcontrollers.h"
00026
00027 #ifdef __GNUC__
00028 #pragma GCC diagnostic ignored "-Wunused-parameter"
00029 #endif
00030 #ifdef FARSA_USE_YARP_AND_ICUB
00031 #include "yarp/os/Network.h"
00032 #endif
00033 #ifdef __GNUC__
00034 #pragma GCC diagnostic warning "-Wunused-parameter"
00035 #endif
00036
00037 #include <QPair>
00038
00039 namespace farsa {
00040
00041 WObject::WObject( World* w, QString name, const wMatrix& tm, bool addToWorld ) {
00042 this->worldv = w;
00043 this->tm = tm;
00044 namev = name;
00045 texturev = "tile2";
00046 colorv = Qt::white;
00047 invisible = false;
00048 usecolortextureofowner = true;
00049 if ( addToWorld ) {
00050 worldv->pushObject( this );
00051 }
00052 }
00053
00054 WObject::~WObject() {
00055 worldv->popObject( this );
00056 }
00057
00058 MaterialDB::MaterialDB( World* w ) : mats(), pmap() {
00059 this->worldv = w;
00060 createMaterial( "nonCollidable" );
00061 createMaterial( "default" );
00062 }
00063
00064 bool MaterialDB::createMaterial( QString name ) {
00065 if ( mats.contains( name ) ) {
00066 return false;
00067 }
00068 #ifdef WORLDSIM_USE_NEWTON
00069 NewtonWorld* ngdWorld = worldv->priv->world;
00070 int newm;
00071 if ( name == "default" ) {
00072 newm = NewtonMaterialGetDefaultGroupID( ngdWorld );
00073 } else {
00074 newm = NewtonMaterialCreateGroupID( ngdWorld );
00075 }
00076 worldv->priv->matIDs[name] = newm;
00077 NewtonMaterialSetCollisionCallback( ngdWorld, newm, newm, (void*)worldv, NULL, (WorldPrivate::processCollisionHandler) );
00078
00079 foreach( QString k, mats.values() ) {
00080 int kid = worldv->priv->matIDs[k];
00081 NewtonMaterialSetCollisionCallback( ngdWorld, newm, kid, (void*)worldv, NULL, (WorldPrivate::processCollisionHandler) );
00082 }
00083
00084 NewtonMaterialSetDefaultCollidable( ngdWorld, worldv->priv->matIDs["nonCollidable"], newm, 0 );
00085 #endif
00086 mats.insert( name );
00087 return true;
00088 }
00089
00090 void MaterialDB::setFrictions( QString mat1, QString mat2, real st, real kn ) {
00091 if ( !mats.contains( mat1 ) ) return;
00092 if ( !mats.contains( mat2 ) ) return;
00093 QString pkey = createKey( mat1, mat2 );
00094 pmap[pkey].staticFriction = st;
00095 pmap[pkey].dynamicFriction = kn;
00096 #ifdef WORLDSIM_USE_NEWTON
00097 int id1 = worldv->priv->matIDs[mat1];
00098 int id2 = worldv->priv->matIDs[mat2];
00099 NewtonMaterialSetDefaultFriction( worldv->priv->world, id1, id2, st, kn );
00100 #endif
00101 return;
00102 }
00103
00104 void MaterialDB::setElasticity( QString mat1, QString mat2, real el ) {
00105 if ( !mats.contains( mat1 ) ) return;
00106 if ( !mats.contains( mat2 ) ) return;
00107 QString pkey = createKey( mat1, mat2 );
00108 pmap[pkey].elasticity = el;
00109 #ifdef WORLDSIM_USE_NEWTON
00110 int id1 = worldv->priv->matIDs[mat1];
00111 int id2 = worldv->priv->matIDs[mat2];
00112 NewtonMaterialSetDefaultElasticity( worldv->priv->world, id1, id2, el );
00113 #endif
00114 return;
00115 }
00116
00117 void MaterialDB::setSoftness( QString mat1, QString mat2, real sf ) {
00118 if ( !mats.contains( mat1 ) ) return;
00119 if ( !mats.contains( mat2 ) ) return;
00120 QString pkey = createKey( mat1, mat2 );
00121 pmap[pkey].softness = sf;
00122 #ifdef WORLDSIM_USE_NEWTON
00123 int id1 = worldv->priv->matIDs[mat1];
00124 int id2 = worldv->priv->matIDs[mat2];
00125 NewtonMaterialSetDefaultSoftness( worldv->priv->world, id1, id2, sf );
00126 #endif
00127 return;
00128 }
00129
00130 void MaterialDB::setGravityForce( QString mat, real force ) {
00131 gravities[mat] = force;
00132 }
00133
00134 real MaterialDB::gravityForce( QString mat ) {
00135 if ( gravities.contains( mat ) ) {
00136 return gravities[mat];
00137 } else {
00138 return worldv->gravityForce();
00139 }
00140 }
00141
00142
00143 void MaterialDB::enableCollision( QString mat1, QString mat2, bool enable ) {
00144 if ( !mats.contains( mat1 ) ) return;
00145 if ( !mats.contains( mat2 ) ) return;
00146 QString pkey = createKey( mat1, mat2 );
00147 pmap[pkey].collisions = enable;
00148 #ifdef WORLDSIM_USE_NEWTON
00149 int id1 = worldv->priv->matIDs[mat1];
00150 int id2 = worldv->priv->matIDs[mat2];
00151 NewtonMaterialSetDefaultCollidable( worldv->priv->world, id1, id2, enable );
00152 #endif
00153 }
00154
00155 void MaterialDB::setProperties( QString mat1, QString mat2, real fs, real fk, real el, real sf, bool en ) {
00156 setFrictions( mat1, mat2, fs, fk );
00157 setElasticity( mat1, mat2, el );
00158 setSoftness( mat1, mat2, sf );
00159 enableCollision( mat1, mat2, en );
00160 }
00161
00162 QString MaterialDB::createKey( QString mat1, QString mat2 ) {
00163 if ( mat1 < mat2 ) {
00164 return mat1 + ":" + mat2;
00165 } else {
00166 return mat1 + ":" + mat2;
00167 }
00168 }
00169
00170 World::World( QString name, bool LocalYarpPorts )
00171 : QObject(), minP(-100,-100,-100), maxP(100,100,100), objs(), jointsv(), mapObjJoints(),
00172 cmap(), nobjs() {
00173 #ifdef FARSA_USE_YARP_AND_ICUB
00174 static yarp::os::Network networkYarp;
00175 if ( LocalYarpPorts ) {
00176 networkYarp.setLocalMode( LocalYarpPorts );
00177 networkYarp.setVerbosity( -1 );
00178 }
00179 #else
00180
00181 Q_UNUSED( LocalYarpPorts )
00182 #endif
00183 timerId = 0;
00184 state = stoppedS;
00185 namev = name;
00186 time = 0.0;
00187 timestepv = 0.0150f;
00188 isrealtimev = false;
00189 isInit = false;
00190 isFinish = true;
00191 gforce = -9.8f;
00192 priv = new WorldPrivate();
00193
00194 #ifdef WORLDSIM_USE_NEWTON
00195 priv->world = NewtonCreate();
00196 NewtonInvalidateCache( priv->world );
00197 NewtonSetWorldSize( priv->world, &minP[0], &maxP[0] );
00198
00199 NewtonSetMinimumFrameRate( priv->world, 100 );
00200
00201 NewtonSetSolverModel( priv->world, 0 );
00202 NewtonSetFrictionModel( priv->world, 0 );
00203
00204
00205
00206
00207
00208 #endif
00209
00210 mats = new MaterialDB( this );
00211 return;
00212 }
00213
00214 World::~World() {
00215
00216
00217
00218 while ( !jointsv.isEmpty() ) {
00219 PhyJoint* js = jointsv.takeFirst();
00220 if ( js->owner() == NULL ) {
00221 delete js;
00222 }
00223 }
00224 while ( !objs.isEmpty() ) {
00225 WObject* obj = objs.takeFirst();
00226 if ( obj->owner() == NULL ) {
00227 delete obj;
00228 }
00229 }
00230 #ifdef WORLDSIM_USE_NEWTON
00231 NewtonDestroy( priv->world );
00232 #endif
00233 delete priv;
00234 }
00235
00236 QString World::name() const {
00237 return namev;
00238 }
00239
00240 void World::initialize() {
00241 if ( isInit ) return;
00242 if ( !isFinish ) {
00243 finalize();
00244 }
00245 time = 0.0;
00246 timer.tic();
00247 state = stoppedS;
00248 isInit = true;
00249 isFinish = false;
00250 emit initialized();
00251 }
00252
00253 void World::advance() {
00254 if ( !isInit ) {
00255 initialize();
00256 }
00257 while( isrealtimev && timer.tac()/1000000.0 < timestepv ) { };
00258
00259 timer.tic();
00260 cmap.clear();
00261
00262 for( QLinkedList<WObject*>::iterator it = objs.begin(); it != objs.end(); it++ ) {
00263 (*it)->preUpdate();
00264 }
00265
00266 for( QLinkedList<PhyJoint*>::iterator it = jointsv.begin(); it != jointsv.end(); it++ ) {
00267 (*it)->preUpdate();
00268 }
00269
00270 #ifdef WORLDSIM_USE_NEWTON
00271 NewtonUpdate( priv->world, timestepv );
00272 #endif
00273
00274 for( QLinkedList<WObject*>::iterator it = objs.begin(); it != objs.end(); it++ ) {
00275 (*it)->postUpdate();
00276 }
00277
00278 for( QLinkedList<PhyJoint*>::iterator it = jointsv.begin(); it != jointsv.end(); it++ ) {
00279 (*it)->postUpdate();
00280 }
00281 time += timestepv;
00282 emit advanced();
00283 }
00284
00285 void World::finalize() {
00286 if ( isFinish ) return;
00287
00288 isFinish = true;
00289 isInit = false;
00290 emit finished();
00291 }
00292
00293 int World::play() {
00294 if ( state == playingS ) return timerId;
00295 if ( timerId != 0 ) return timerId;
00296 state = playingS;
00297 timerId = startTimer( 0 );
00298 return timerId;
00299 }
00300
00301 void World::pause() {
00302 state = pausedS;
00303 if ( timerId != 0 ) killTimer( timerId );
00304 timerId = 0;
00305 emit paused();
00306 return;
00307 }
00308
00309 void World::stop() {
00310 finalize();
00311 state = stoppedS;
00312 if ( timerId != 0 ) killTimer( timerId );
00313 timerId = 0;
00314 emit stopped();
00315 return;
00316 }
00317
00318 void World::timerEvent( QTimerEvent* ) {
00319 advance();
00320 return;
00321 }
00322
00323 void World::customEvent( QEvent* e ) {
00324 switch( e->type() ) {
00325 case E_Advance:
00326 advance();
00327 e->accept();
00328 break;
00329 case E_Play:
00330 play();
00331 e->accept();
00332 break;
00333 case E_Stop:
00334 stop();
00335 e->accept();
00336 break;
00337 case E_Pause:
00338 pause();
00339 e->accept();
00340 break;
00341 default:
00342 e->ignore();
00343 break;
00344 }
00345 return;
00346 }
00347
00348 real World::elapsedTime() const {
00349 return time;
00350 }
00351
00352 void World::resetElapsedTime() {
00353 time = 0.0;
00354 }
00355
00356 void World::setIsRealTime( bool b ) {
00357 isrealtimev = b;
00358 }
00359
00360 bool World::isRealTime() const {
00361 return isrealtimev;
00362 }
00363
00364 void World::setTimeStep( real ts ) {
00365 timestepv = ts;
00366 }
00367
00368 void World::setMinimumFrameRate( unsigned int frames ) {
00369 #ifdef WORLDSIM_USE_NEWTON
00370 NewtonSetMinimumFrameRate( priv->world, frames );
00371 #endif
00372 }
00373
00374 real World::timeStep() const {
00375 return timestepv;
00376 }
00377
00378 void World::setGravityForce( real g ) {
00379 gforce = g;
00380 }
00381
00382 real World::gravityForce() const {
00383 return gforce;
00384 }
00385
00386 void World::advanceUntil( real t ) {
00387 blockSignals( true );
00388 bool b = isrealtimev;
00389 isrealtimev = false;
00390 while ( time < t ) {
00391 advance();
00392 }
00393 isrealtimev = b;
00394 blockSignals( false );
00395 }
00396
00397 const QLinkedList<WObject*> World::objects() {
00398 return objs;
00399 }
00400
00401 WObject* World::getObject( QString name ) {
00402
00403 foreach( WObject* obj, objs ) {
00404 if ( obj->name() == name ) return obj;
00405 }
00406 return NULL;
00407 }
00408
00409 const QLinkedList<PhyJoint*> World::joints() {
00410 return jointsv;
00411 }
00412
00413 const QHash<WObject*, QList<PhyJoint*> > World::mapObjectsToJoints() {
00414 return mapObjJoints;
00415 }
00416
00417 void World::disableCollision( PhyObject* obj1, PhyObject* obj2 ) {
00418 nobjs.insert( qMakePair( obj1, obj2 ) );
00419 nobjs.insert( qMakePair( obj2, obj1 ) );
00420 }
00421
00422 void World::enableCollision( PhyObject* obj1, PhyObject* obj2 ) {
00423 nobjs.remove( qMakePair( obj1, obj2 ) );
00424 nobjs.remove( qMakePair( obj2, obj1 ) );
00425 }
00426
00427 void World::setSolverModel( QString model ) {
00428 #ifdef WORLDSIM_USE_NEWTON
00429 if ( model =="exact" ) {
00430 NewtonSetSolverModel( priv->world, 0 );
00431 } else if ( model == "linear" ) {
00432 NewtonSetSolverModel( priv->world, 1 );
00433 }
00434 #endif
00435 }
00436
00437 void World::setFrictionModel( QString model ) {
00438 #ifdef WORLDSIM_USE_NEWTON
00439 if ( model =="exact" ) {
00440 NewtonSetFrictionModel( priv->world, 0 );
00441 } else if ( model == "linear" ) {
00442 NewtonSetFrictionModel( priv->world, 1 );
00443 }
00444 #endif
00445 }
00446
00447 void World::setMultiThread( int numThreads ) {
00448 #ifdef WORLDSIM_USE_NEWTON
00449 numThreads = max( 1, numThreads );
00450 NewtonSetThreadsCount( priv->world, numThreads );
00451 #endif
00452 }
00453
00454 void World::setSize( const wVector& minPoint, const wVector& maxPoint ) {
00455 minP = minPoint;
00456 maxP = maxPoint;
00457 #ifdef WORLDSIM_USE_NEWTON
00458 NewtonSetWorldSize( priv->world, &minP[0], &maxP[0] );
00459 #endif
00460 emit resized();
00461 }
00462
00463 void World::size( wVector &minPoint, wVector &maxPoint ) {
00464 minPoint = minP;
00465 maxPoint = maxP;
00466 }
00467
00468 void World::pushObject( WObject* phy ) {
00469 objs.push_back( phy );
00470 emit addedObject( phy );
00471 }
00472
00473 void World::popObject( WObject* phy ) {
00474 const int numRemoved = objs.removeAll( phy );
00475 if ( numRemoved == 1 ) {
00476 emit removedObject( phy );
00477 }
00478 #ifdef FARSA_DEBUG
00479 else if (numRemoved > 1) {
00480 qDebug( "INTERNAL ERROR: more than one object with the same address found in the World::objs list" );
00481 }
00482 #endif
00483 }
00484
00485 void World::pushJoint( PhyJoint* phy ) {
00486 jointsv.push_back( phy );
00487 mapObjJoints[ phy->child() ].push_back( phy );
00488 if ( phy->parent() ) {
00489 mapObjJoints[ phy->parent() ].push_back( phy );
00490 }
00491 emit addedJoint( phy );
00492 }
00493
00494 void World::popJoint( PhyJoint* phy ) {
00495 const int numRemoved = jointsv.removeAll( phy );
00496 if ( numRemoved == 1 ) {
00497 mapObjJoints[ phy->child() ].removeAll( phy );
00498 mapObjJoints.remove( phy->child() );
00499 if ( phy->parent() ) {
00500 mapObjJoints[ phy->parent() ].removeAll( phy );
00501 mapObjJoints.remove( phy->parent() );
00502 }
00503 emit removedJoint( phy );
00504 }
00505 #ifdef FARSA_DEBUG
00506 else if (numRemoved > 1) {
00507 qDebug( "INTERNAL ERROR: more than one joint with the same address found in the World::jointsv list" );
00508 }
00509 #endif
00510 }
00511
00512 void World::cleanUpMemory() {
00513 #ifdef WORLDSIM_USE_NEWTON
00514
00515 NewtonInvalidateCache( priv->world );
00516 cmap.clear();
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 #endif
00530 }
00531
00532 const contactMap& World::contacts() {
00533 return cmap;
00534 }
00535
00536 bool World::checkContacts( PhyObject* obj1, PhyObject* obj2, int maxContacts, QVector<wVector>* contacts, QVector<wVector>* normals, QVector<real>* penetra ) {
00537 #ifdef WORLDSIM_USE_NEWTON
00538
00539 real *const tmp_data = new real[2 * 3 * maxContacts + maxContacts];
00540 real *const tmp_contacts = &tmp_data[0 * 3 * maxContacts];
00541 real *const tmp_normals = &tmp_data[1 * 3 * maxContacts];
00542 real *const tmp_penetra = &tmp_data[2 * 3 * maxContacts];
00543
00544
00545 wMatrix t1 = obj1->matrix();
00546 wMatrix t2 = obj2->matrix();
00547 const int numContacts = NewtonCollisionCollide( priv->world, maxContacts, obj1->priv->collision, &t1[0][0], obj2->priv->collision, &t2[0][0], tmp_contacts, tmp_normals, tmp_penetra, 0 );
00548
00549
00550 if (contacts != NULL) {
00551 contacts->resize(numContacts);
00552 for (int i = 0; i < numContacts; i++) {
00553 (*contacts)[i].x = tmp_contacts[0 + i * 3];
00554 (*contacts)[i].y = tmp_contacts[1 + i * 3];
00555 (*contacts)[i].z = tmp_contacts[2 + i * 3];
00556 }
00557 }
00558 if (normals != NULL) {
00559 normals->resize(numContacts);
00560 for (int i = 0; i < numContacts; i++) {
00561 (*normals)[i].x = tmp_normals[0 + i * 3];
00562 (*normals)[i].y = tmp_normals[1 + i * 3];
00563 (*normals)[i].z = tmp_normals[2 + i * 3];
00564 }
00565 }
00566 if (penetra != NULL) {
00567 penetra->resize(numContacts);
00568 for (int i = 0; i < numContacts; i++) {
00569 (*penetra)[i] = tmp_penetra[i];
00570 }
00571 }
00572
00573 delete[] tmp_data;
00574 return (numContacts != 0);
00575 #endif
00576 }
00577
00578 bool World::smartCheckContacts( PhyObject* obj1, PhyObject* obj2, int maxContacts, QVector<wVector>* contacts )
00579 {
00580 if (obj1->getKinematic() || obj2->getKinematic() || (obj1->getStatic() && obj2->getStatic())) {
00581 return checkContacts( obj1, obj2, maxContacts, contacts, NULL, NULL);
00582 } else {
00583 if (!cmap.contains(obj1)) {
00584 return false;
00585 }
00586
00587
00588 const contactVec& c = cmap[obj1];
00589 bool collision = false;
00590 if (contacts != NULL) {
00591 contacts->clear();
00592 }
00593
00594
00595 for (int i = 0; i < c.size(); i++) {
00596 if (c[i].collide == obj2) {
00597 collision = true;
00598 if ((contacts != NULL) && (contacts->size() < maxContacts)) {
00599
00600 contacts->append(c[i].worldPos);
00601 }
00602 }
00603 }
00604
00605 return collision;
00606 }
00607 }
00608
00609 real World::collisionRayCast( PhyObject* obj, wVector start, wVector end, wVector* normal )
00610 {
00611 #ifdef WORLDSIM_USE_NEWTON
00612
00613 dFloat n[3];
00614 int attribute;
00615 wVector localStart = obj->matrix().inverse().transformVector(start);
00616 wVector localEnd = obj->matrix().inverse().transformVector(end);
00617
00618
00619 const real contact = NewtonCollisionRayCast(obj->priv->collision, &localStart[0], &localEnd[0], n, &attribute);
00620
00621 if (normal != NULL) {
00622 (*normal)[0] = n[0];
00623 (*normal)[1] = n[1];
00624 (*normal)[2] = n[2];
00625 }
00626
00627 return contact;
00628 #else
00629 return 2.0;
00630 #endif
00631 }
00632
00633 rayCastHitVector World::worldRayCast( wVector start, wVector end, bool onlyClosest, const QSet<PhyObject*>& ignoredObjs )
00634 {
00635 #ifdef WORLDSIM_USE_NEWTON
00636 WorldPrivate::WorldRayCastCallbackUserData data(start, end, onlyClosest, ignoredObjs);
00637
00638
00639 NewtonWorldRayCast(priv->world, &start[0], &end[0], WorldPrivate::worldRayFilterCallback, &data, NULL);
00640
00641 return data.vector;
00642 #else
00643 return rayCastHitVector();
00644 #endif
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 bool World::closestPoints( PhyObject* objA, PhyObject* objB, wVector& pointA, wVector& pointB ) {
00661 #ifdef WORLDSIM_USE_NEWTON
00662 wVector normal;
00663 wMatrix t1 = objA->matrix();
00664 wMatrix t2 = objB->matrix();
00665 int ret = NewtonCollisionClosestPoint( priv->world,
00666 objA->priv->collision, &t1[0][0],
00667 objB->priv->collision, &t2[0][0],
00668 &pointA[0], &pointB[0], &normal[0], 0 );
00669 if ( ret == 0 ) {
00670 pointA = wVector(0,0,0);
00671 pointB = wVector(0,0,0);
00672 return false;
00673 }
00674 return true;
00675 #endif
00676 }
00677
00678 }