worldsim/src/phyobject.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 "phyobject.h"
00021 #include "private/phyobjectprivate.h"
00022 #include "private/worldprivate.h"
00023 
00024 namespace farsa {
00025 
00026 PhyObject::PhyObject( World* w, QString name, const wMatrix& tm, bool createPrivate )
00027     : WObject( w, name, tm, false ), materialv("default") {
00028 
00029     priv = new PhyObjectPrivate();
00030     worldpriv = w->priv;
00031     if ( createPrivate ) {
00032         w->pushObject( this );
00033         createPrivateObject();
00034         changedMatrix();
00035     }
00036 
00037     forceAcc = wVector(0,0,0);
00038     torqueAcc = wVector(0,0,0);
00039     isKinematic = false;
00040     isStatic = false;
00041     objInertiaVec = wVector(0.0, 1.0, 1.0, 1.0);
00042     objInvInertiaVec = wVector(0.0, 1.0, 1.0, 1.0);
00043 }
00044 
00045 PhyObject::~PhyObject() {
00046 #ifdef WORLDSIM_USE_NEWTON
00047     if ( priv->body != NULL ) {
00048         NewtonDestroyBody( worldpriv->world, priv->body );
00049         NewtonReleaseCollision( worldpriv->world, priv->collision );
00050     }
00051 #endif
00052     delete priv;
00053 }
00054 
00055 void PhyObject::setKinematic(bool b, bool c)
00056 {
00057     //if (isKinematic == b) return;
00058     isKinematic = b;
00059 #ifdef WORLDSIM_USE_NEWTON
00060     if (b) {
00061         // Unsets the signal-wrappers callback and collision shape
00062         NewtonBodySetTransformCallback( priv->body, 0 );
00063         NewtonBodySetForceAndTorqueCallback( priv->body, 0 );
00064         //NewtonBodySetFreezeState( priv->body, 1 ); <== this will block also any body jointed to this one
00065 //      //--- Queste tre righe mettono un NullCollision all'oggetto fisico,
00066 //      //    e quindi tutte le collisioni vengono totalmente ignorarte da NGD
00067 //      //--- Un alternativa e' commentare queste righe, ed impostare la massa a 0
00068 //      //    in questo modo, l'oggetto risultera' statico per NGD, e generera' collisioni
00069 //      //    con gli altri oggetti. Cosi' facendo anche muovendo l'oggetto in modo
00070 //      //    cinematico potra' cmq collidere e spostare oggetti dinamici.
00071 //      //    Pero', cmq, gli passera' attraverso come se fossero trasparenti, quindi
00072 //      //    movimenti veloci risulteranno 'sbagliati' dal punto di vista fisico
00073 //      NewtonCollision* nullC = NewtonCreateNull( worldpriv->world );
00074 //      NewtonBodySetCollision( priv->body, nullC );
00075 //      NewtonReleaseCollision( worldpriv->world, nullC );
00076 //      //--- soluzione alternativa: NewtonBodySetMassMatrix( priv->body, 0, 1, 1, 1 );
00077         if (c) {
00078             // Here we set mass to 0. This way the object will be static for NGD and will
00079             // collide with other solids, influencing them without being influenced. 
00080             NewtonBodySetMassMatrix( priv->body, 0, 1, 1, 1 );
00081         } else {
00082             // The following lines set a NullCollision for the physical object, so that
00083             // all collisions are completely ignored by Newton Game Dynamics
00084             NewtonCollision* nullC = NewtonCreateNull( worldpriv->world );
00085             NewtonBodySetCollision( priv->body, nullC );
00086             NewtonReleaseCollision( worldpriv->world, nullC );
00087         }
00088     } else {
00089         // Sets the signal-wrappers callback and collision shape
00090         NewtonBodySetTransformCallback( priv->body, (PhyObjectPrivate::setTransformHandler) );
00091         NewtonBodySetForceAndTorqueCallback( priv->body, (PhyObjectPrivate::applyForceAndTorqueHandler) );
00092         NewtonBodySetFreezeState( priv->body, 0 );
00093         NewtonBodySetCollision( priv->body, priv->collision );
00094         NewtonBodySetMatrix( priv->body, &tm[0][0] );
00095         // Restoring mass and inertia
00096         if (isStatic) {
00097             NewtonBodySetMassMatrix( priv->body, 0.0, 1.0, 1.0, 1.0 );
00098         } else {
00099             NewtonBodySetMassMatrix( priv->body, objInertiaVec[0], objInertiaVec[1], objInertiaVec[2], objInertiaVec[3] );
00100         }
00101     }
00102 #endif
00103 }
00104 
00105 void PhyObject::setStatic(bool b)
00106 {
00107     if (isStatic == b) return;
00108     isStatic = b;
00109 #ifdef WORLDSIM_USE_NEWTON
00110     if (b) {
00111         NewtonBodySetMassMatrix( priv->body, 0.0, 1.0, 1.0, 1.0 );
00112     } else {
00113         NewtonBodySetMassMatrix( priv->body, objInertiaVec[0], objInertiaVec[1], objInertiaVec[2], objInertiaVec[3] );
00114     }
00115 #endif
00116 }
00117 
00118 void PhyObject::reset() {
00119 #ifdef WORLDSIM_USE_NEWTON
00120     wVector zero = wVector(0,0,0);
00121     forceAcc = zero;
00122     torqueAcc= zero;
00123     NewtonBodySetForce( priv->body, &forceAcc[0] );
00124     NewtonBodySetTorque( priv->body, &torqueAcc[0] );
00125     NewtonBodySetOmega( priv->body, &zero[0] );
00126     NewtonBodySetVelocity( priv->body, &zero[0] );
00127     //--- remove any contact involving this object
00128     NewtonWorld* nworld = NewtonBodyGetWorld( priv->body );
00129     NewtonWorldCriticalSectionLock( nworld );
00130     for( NewtonJoint* contactList = NewtonBodyGetFirstContactJoint( priv->body ); contactList;
00131          contactList = NewtonBodyGetNextContactJoint( priv->body, contactList ) ) {
00132         void* nextContact;
00133         for( void* contact = NewtonContactJointGetFirstContact(contactList); contact; contact = nextContact ) {
00134             //--- before removing contact, It get the nextContact in the list
00135             nextContact = NewtonContactJointGetNextContact( contactList, contact );
00136             NewtonContactJointRemoveContact( contactList, contact );
00137         }
00138     }
00139     NewtonWorldCriticalSectionUnlock( nworld );
00140 #endif
00141 }
00142 
00143 void PhyObject::changedMatrix() {
00144 #ifdef WORLDSIM_USE_NEWTON
00145     //qDebug() << "SYNC POSITION" << tm[3][0] << tm[3][1] << tm[3][2];
00146     NewtonBodySetMatrix( priv->body, &tm[0][0] );
00147 #endif
00148 }
00149 
00150 void PhyObject::addForce( const wVector& force ) {
00151     forceAcc += force;
00152 }
00153 
00154 void PhyObject::setForce( const wVector& force) {
00155     forceAcc = force;
00156 }
00157 
00158 wVector PhyObject::force() {
00159     wVector f;
00160 #ifdef WORLDSIM_USE_NEWTON
00161     NewtonBodyGetForce( priv->body, &f[0] );
00162 #endif
00163     return f;
00164 }
00165 
00166 void PhyObject::addTorque( const wVector& torque ) {
00167     torqueAcc += torque;
00168 }
00169 
00170 void PhyObject::setTorque( const wVector& torque ) {
00171     torqueAcc = torque;
00172 }
00173 
00174 wVector PhyObject::torque() {
00175     wVector t;
00176 #ifdef WORLDSIM_USE_NEWTON
00177     NewtonBodyGetTorque( priv->body, &t[0] );
00178 #endif
00179     return t;
00180 }
00181 
00182 void PhyObject::setMassInertiaVec( const wVector& mi ) {
00183     objInertiaVec = mi;
00184 #ifdef WORLDSIM_USE_NEWTON
00185     // Setting mass and getting the inverse inertia matrix
00186     NewtonBodySetMassMatrix( priv->body, mi[0], mi[1], mi[2], mi[3] );
00187     NewtonBodyGetInvMass( priv->body, &objInvInertiaVec[0], &objInvInertiaVec[1], &objInvInertiaVec[2], &objInvInertiaVec[3]);
00188 #endif
00189 }
00190 
00191 wVector PhyObject::massInertiaVec() const {
00192     return objInertiaVec;
00193 }
00194 
00195 wVector PhyObject::invMassInertiaVec() const {
00196     return objInvInertiaVec;
00197 }
00198 
00199 wVector PhyObject::invInertiaVec() const {
00200     wVector mi;
00201     mi[0] = objInvInertiaVec[1];
00202     mi[1] = objInvInertiaVec[2];
00203     mi[2] = objInvInertiaVec[3];
00204     mi[3] = 0.0;
00205     return mi;
00206 }
00207 
00208 void PhyObject::setMass( real newmass ) {
00209 #ifdef WORLDSIM_USE_NEWTON
00210     if ( newmass < 0.0001 ) {
00211         objInertiaVec = wVector(0.0, 1.0, 1.0, 1.0);
00212         objInvInertiaVec = wVector(0.0, 1.0, 1.0, 1.0);
00213         isStatic = true;
00214         NewtonBodySetMassMatrix( priv->body, 0, 1, 1, 1 );
00215     } else {
00216         real inertia[3];
00217         real centre[3] = { 0, 0, 0 };
00218         NewtonConvexCollisionCalculateInertialMatrix( priv->collision, inertia, centre );
00219 
00220         objInertiaVec = wVector(newmass, newmass*inertia[0], newmass*inertia[1], newmass*inertia[2]);
00221         NewtonBodySetMassMatrix( priv->body, objInertiaVec[0], objInertiaVec[1], objInertiaVec[2], objInertiaVec[3] );
00222         // Saving the inverse inertia matrix
00223         NewtonBodyGetInvMass( priv->body, &objInvInertiaVec[0], &objInvInertiaVec[1], &objInvInertiaVec[2], &objInvInertiaVec[3]);
00224         // If the object is static we reset its mass to 0
00225         if (isStatic) {
00226             NewtonBodySetMassMatrix( priv->body, 0, 1, 1, 1 );
00227         }
00228     }
00229 #endif
00230 }
00231 
00232 real PhyObject::mass() {
00233     return objInertiaVec[0];
00234 }
00235 
00236 void PhyObject::setOmega( const wVector& omega ) {
00237 #ifdef WORLDSIM_USE_NEWTON
00238     NewtonBodySetOmega( priv->body, &omega[0] );
00239 #endif
00240 }
00241 
00242 wVector PhyObject::omega() {
00243     wVector t;
00244 #ifdef WORLDSIM_USE_NEWTON
00245     NewtonBodyGetOmega( priv->body, &t[0] );
00246 #endif
00247     return t;
00248 }
00249 
00250 void PhyObject::setVelocity( const wVector& velocity ) {
00251 #ifdef WORLDSIM_USE_NEWTON
00252     NewtonBodySetVelocity( priv->body, &velocity[0] );
00253 #endif
00254 }
00255 
00256 wVector PhyObject::velocity() {
00257     wVector t;
00258 #ifdef WORLDSIM_USE_NEWTON
00259     NewtonBodyGetVelocity( priv->body, &t[0] );
00260 #endif
00261     return t;
00262 }
00263 
00264 void PhyObject::addImpulse( const wVector& pointDeltaVeloc, const wVector& pointPosit ) {
00265 #ifdef WORLDSIM_USE_NEWTON
00266     NewtonBodyAddImpulse( priv->body, &pointDeltaVeloc[0], &pointPosit[0] );
00267 #endif
00268 }
00269 
00270 void PhyObject::setMaterial( QString material ) {
00271     this->materialv = material;
00272 #ifdef WORLDSIM_USE_NEWTON
00273     if ( worldv->priv->matIDs.contains( material ) ) {
00274         NewtonBodySetMaterialGroupID( priv->body, worldv->priv->matIDs[material] );
00275     }
00276 #endif
00277 }
00278 
00279 QString PhyObject::material() const {
00280     return materialv;
00281 }
00282 
00283 void PhyObject::createPrivateObject() {
00284 #ifdef WORLDSIM_USE_NEWTON
00285     NewtonCollision* c = NewtonCreateNull( worldpriv->world );
00286     wMatrix initialTransformationMatrix = wMatrix::identity(); // The transformation matrix is set in other places
00287     priv->body = NewtonCreateBody( worldpriv->world, c, &initialTransformationMatrix[0][0] );
00288     priv->collision = NewtonBodyGetCollision( priv->body );
00289     //NewtonReleaseCollision( worldpriv->world, c );
00290     NewtonBodySetAutoSleep( priv->body, 0 );
00291     NewtonBodySetMassMatrix( priv->body, 1.0, 1.0, 1.0, 1.0 );
00292     NewtonBodySetUserData( priv->body, this );
00293     // Sets the signal-wrappers callback
00294     NewtonBodySetTransformCallback( priv->body, (PhyObjectPrivate::setTransformHandler) );
00295     NewtonBodySetForceAndTorqueCallback( priv->body, (PhyObjectPrivate::applyForceAndTorqueHandler) );
00296 #endif
00297 }
00298 
00299 } // end namespace farsa