worldsim/src/world.cpp

00001 /********************************************************************************
00002  *  WorldSim -- library for robot simulations                                   *
00003  *  Copyright (C) 2008-2011 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
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     // --- setting callbacks
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     // --- setting nonCollidable material
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     // This is to avoid the warning regarding the unsed parameter LocalYarpPorts
00181     Q_UNUSED( LocalYarpPorts )
00182 #endif
00183     timerId = 0;
00184     state = stoppedS;
00185     namev = name;
00186     time = 0.0;
00187     timestepv = 0.0150f; //--- about 66.66666 frame per second
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      // keep at least to 100 for stability
00199     NewtonSetMinimumFrameRate( priv->world, 100 );
00200     // exact model as default
00201     NewtonSetSolverModel( priv->world, 0 );
00202     NewtonSetFrictionModel( priv->world, 0 );
00203     // enable multi-thread 
00204     //--- for works we before check that all callbacks implementation are thread-safe
00205     //--- REMEMBER: connect, signal-slot of non-QT data needs to register the type with
00206     //---           qRegisterMetaType
00207     //NewtonSetThreadsCount( priv->world, 2 );
00208 #endif
00209 
00210     mats = new MaterialDB( this );
00211     return;
00212 }
00213 
00214 World::~World() {
00215     // Here we can't use foreach because lists could be modified while we are iterating on them
00216     // by the popObject(), popJoint() or popMotorController() functions. See the comment in the
00217     // declaration of objs for more information
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     //--- preUpdate Objects
00262     for( QLinkedList<WObject*>::iterator it = objs.begin(); it != objs.end(); it++ ) {
00263         (*it)->preUpdate();
00264     }
00265     //--- preUpdate Joints
00266     for( QLinkedList<PhyJoint*>::iterator it = jointsv.begin(); it != jointsv.end(); it++ ) {
00267         (*it)->preUpdate();
00268     }
00269     //--- simulate physic
00270 #ifdef WORLDSIM_USE_NEWTON
00271     NewtonUpdate( priv->world, timestepv );
00272 #endif
00273     //--- postUpdate Objects
00274     for( QLinkedList<WObject*>::iterator it = objs.begin(); it != objs.end(); it++ ) {
00275         (*it)->postUpdate();
00276     }
00277     //--- postUpdate Joints
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     /* nothing else to do ?!?! */
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     //--- not very efficient, FIX adding a QMap
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     //qDebug() << "Memory Used by" << name() << NewtonGetMemoryUsed();
00515     NewtonInvalidateCache( priv->world );
00516     cmap.clear();
00517     /*
00518     qDebug() << "Objects: " << objs.size();
00519     qDebug() << "Joints: " << jointsv.size();
00520     qDebug() << "Map Obj-Joints: " << mapObjJoints.size();
00521     qDebug() << "Contacts: " << cmap.size();
00522     qDebug() << "Non-Collidable Objs: " << nobjs.size();
00523     */
00524     /*
00525     qDebug() << "Materials: " << mats->mats.size();
00526     qDebug() << "Gravities: " << mats->gravities.size();
00527     qDebug() << "Material Infos: " << mats->pmap.size();
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     // Allocating the vector we use to get data from NewtonCollisionCollide
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     // Computing contacts
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     // Now copying contacts information into user vectors
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         // Taking the vector of contacts
00588         const contactVec& c = cmap[obj1];
00589         bool collision = false;
00590         if (contacts != NULL) {
00591             contacts->clear();
00592         }
00593 
00594         // Now extracting all collisions between obj1 and obj2
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                     // Adding contact point
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     // The vector storing the normal to the contact point and the attribute (unused)
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     // Computing the contact
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     // Casting the ray
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 // bool World::checkContacts( PhyObject* obj1, PhyObject* obj2 ) {
00648 // #ifdef WORLDSIM_USE_NEWTON
00649 //  const int maxsize = 4;
00650 //  real contacts[3*maxsize];
00651 //  real normals[3*maxsize];
00652 //  real penetra[3*maxsize];
00653 //  wMatrix t1 = obj1->matrix();
00654 //  wMatrix t2 = obj2->matrix();
00655 //  bool ret = ( NewtonCollisionCollide( priv->world, maxsize, obj1->priv->collision, &t1[0][0], obj2->priv->collision, &t2[0][0], contacts, normals, penetra, 0 ) != 0 );
00656 //  return ret;
00657 // #endif
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 } // end namespace farsa