Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

cylinder_physics.cc

Go to the documentation of this file.
00001 /*
00002   svas_server -- virtual World Server of Svas
00003   Copyright (c) 2001, 2002 David Moreno Montero
00004  
00005  
00006   This program is free software; you can redistribute it and/or modify
00007   it under the terms of the GNU General Public License as published by
00008   the Free Software Foundation; either version 2 of the License, or
00009   (at your option) any later version.
00010  
00011   This program is distributed in the hope that it will be useful, but
00012   WITHOUT ANY WARRANTY; without even the implied warranty of
00013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014   General Public License for more details.
00015  
00016   You should have received a copy of the GNU General Public License
00017   along with this program; if not, write to the Free Software
00018   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00019   02111-1307, USA.  
00020 
00021 */
00022 
00023 #include <thread.h>
00024 #include <math.h>
00025 #include "cylinder.h"
00026 #include "log.h"
00027 #include "world.h"
00028 #include "agent.h"
00029 #include "collision.h"
00030 
00031 /**
00032  * Updates the moment of inertia of the cylinder
00033  */
00034 void Cylinder::updateMomentOfInertia(){
00035   double xxyy=((1.0/12.0)*mass*height*height) + ((1.0/4.0)*mass*width*width);
00036   double zz=(1.0/2.0)*mass*width*width;
00037 
00038   inertia=Matrix3x3(xxyy,0,0,
00039             0,xxyy,0,
00040             0,0,zz);
00041   inertiaInverse=inertia.Inverse();
00042 }
00043 
00044 
00045 
00046 /**
00047  * As a new cycle begins, we need to reset the forces, moments... It
00048  * also adds the forces due to gravity, linear drag and angular drag.
00049  **/
00050 void Cylinder::newCycle(){
00051   unsigned int i;
00052   updateMomentOfInertia();
00053 
00054   if (fabs(velocity.X())<COLLISION_VELOCITY_EPSILUM)    velocity=Vector3d(0,velocity.Y(),velocity.Z());
00055   if (fabs(velocity.Y())<COLLISION_VELOCITY_EPSILUM)    velocity=Vector3d(velocity.X(),0,velocity.Z());
00056   if (fabs(velocity.Z())<COLLISION_VELOCITY_EPSILUM)    velocity=Vector3d(velocity.X(),velocity.Y(),0);
00057 
00058   if (fabs(angularVelocity.X())<COLLISION_ANGULARVELOCITY_EPSILUM)    angularVelocity=Vector3d(0,angularVelocity.Y(),angularVelocity.Z());
00059   if (fabs(angularVelocity.Y())<COLLISION_ANGULARVELOCITY_EPSILUM)    angularVelocity=Vector3d(angularVelocity.X(),0,angularVelocity.Z());
00060   if (fabs(angularVelocity.Z())<COLLISION_ANGULARVELOCITY_EPSILUM)    angularVelocity=Vector3d(angularVelocity.X(),angularVelocity.Y(),0);
00061 
00062   /// I update sons glueposition...
00063   for(i=son.size();i--;){
00064     son[i]->gluePosition=(orientationWorld*son[i]->gluePositionBody.X()*height) + 
00065       (son[i]->orientationWorld*radius);
00066   }
00067 
00068   force=Vector3d(0,0,0);
00069   oldForce=force;
00070   moment=Vector3d(0,0,0);
00071   oldMoment=moment;
00072 
00073   /// Gravity
00074   force+=Vector3d(0,0,1)*mass*World::getGravity();
00075 
00076   /// Linear Drag
00077   /// The last part (width*height) is a very bad approximation of area
00078   /// exposed to the drag force
00079   double speed=velocity.module();
00080   if (speed!=0.0)
00081     force+=((-velocity).normalized())*(speed*speed*World::getLinearDragCoefficient()*width*height);
00082 
00083   /// Angular Drag
00084   double aspeed=angularVelocity.module();
00085   if (aspeed!=0.0)
00086     moment+=((-angularVelocity).normalized())*(aspeed*aspeed*World::getAngularDragCoefficient()*width*height);
00087 
00088   /// Spring and damper forces
00089   double f;
00090   double l;
00091   Vector3d L,V;
00092   Vector3d O;
00093   
00094   for (i=son.size();i--;){
00095     L=son[i]->gluePosition-son[i]->position; //son[i]->gluePosition-(son[i]->position+velocity+(son[i]->force/son[i]->mass));
00096     l=L.module();
00097     if (l==0)
00098       continue;
00099     if (l>length){
00100       drop(son[i]->getId(),NULL,0);
00101       continue;
00102     }
00103     V=-(velocity-son[i]->velocity);
00104     f=(World::getSpringCoefficient()*l+
00105        World::getDamperCoefficient()*(V*L)/l); // The force scalar
00106 
00107     O=Vector3d(sin(son[i]->gluePositionBody.Y()),
00108            cos(son[i]->gluePositionBody.Y()),0);
00109 
00110     //log <<O.toString()<<endl;
00111 
00112     /// Action   - My force against my son
00113     //    applyForceOnBody(O*f,(O*radius)+Vector3d(0,0,(son[i]->gluePositionBody.X()-0.5)*son[i]->length/2));
00114     moment+=(O*f)^((O*radius)+Vector3d(0,0,(son[i]->gluePositionBody.X()-0.5)*son[i]->length));
00115 
00116     /// Reaction!
00117     //    son[i]->applyForceOnBody(Vector3d(0,0,-f),Vector3d(0,0,-length/2));
00118     son[i]->moment+=Vector3d(0,0,-f)^(Vector3d(0,0,-length/2));
00119 
00120     son[i]->setToGluePosition();
00121   }
00122   
00123   /// Check contact force with the ground
00124   Collision *col=checkGroundCollision();
00125   if (NULL!=col){
00126     if (col->getType()==contact)
00127       col->resolve();
00128     delete col;
00129   }
00130 
00131 
00132   /*
00133   for (i=son.size();i--;){
00134     son[i]->setToGluePosition();
00135   }
00136   */
00137 }
00138 
00139 /**
00140  * Moves the cylinder to the glue position, if any
00141  */
00142 void Cylinder::setToGluePosition(void){
00143   if (NULL!=father)
00144     position=gluePosition;
00145 }
00146 
00147 /**
00148  * Moves the position of the cylinder, but with care with parent; in
00149  * case the cylinder have a parent, it moves the parent too. Have care
00150  * about gluePosition too.
00151  */
00152 void Cylinder::movePosition(const Vector3d &ammount){
00153   /*
00154   if (father!=NULL)
00155     father->movePosition(ammount);
00156   else
00157   */
00158   position+=ammount;
00159 }
00160 
00161 /**
00162  * Apply a force over the cylinder, causing linear and angular acceleration
00163  *
00164  * the point where the force is applied is perpendicular to the
00165  * axis. (through the line that connects the axis and the point where)
00166  */
00167 void Cylinder::applyForce(const Vector3d &_force, const Point3d &where){
00168   log <<"Do not use this force!"<<endl;
00169   force+=_force;
00170   //  moment+= _force^((~orientation).rotate(where-getCentreOfGravity()).getAxis());
00171 }
00172 
00173 /**
00174  * Apply a force over the cylinder, causing linear and angular acceleration
00175  *
00176  * The force and point are both in body coordinates
00177  */
00178 void Cylinder::applyForceOnBody(const Vector3d &_force, const Point3d &where){
00179   force+=orientationBase.toWorld(_force);
00180   moment+= _force^where;
00181 }
00182 
00183 
00184 /**
00185  * Move the cylinders, and check collissions. Returns true if it's
00186  * bellow the floor
00187  */
00188 void Cylinder::applyVelocity(double dtime){
00189   /// first we save status
00190   oldPosition=position;
00191   oldOrientationBase=orientationBase;
00192   oldVelocity=velocity;
00193   oldAngularVelocity=angularVelocity;
00194   oldForce=force;
00195   oldMoment=moment;
00196 
00197   ////// And now apply velocity
00198   // Linear Velocity
00199   Vector3d A=force/mass;
00200   velocity+=A*dtime;
00201   position+=velocity*dtime;
00202 
00203   // Angular velocity
00204   A=inertiaInverse*(moment - (angularVelocity^(inertia*angularVelocity)));
00205 
00206   angularVelocity+=A*dtime;
00207   orientationBase+=(orientationBase*angularVelocity) * (0.5 *dtime);
00208   orientationBase.normalize();
00209 
00210   position+=orientationWorld*(length/2); // I set position to the center
00211 
00212   orientationWorld=orientationBase.toWorld(Vector3d(0,0,1));
00213   orientationWorld.normalize();
00214 
00215   position-=orientationWorld*(length/2); // and back to the position
00216 
00217 
00218   /*    
00219   unsigned int i;
00220   for (i=son.size();i--;)
00221     son[i]->orientationBase=(orientationBase*son[i]->orientationBase).normalized();
00222   */
00223 }
00224 
00225 /**
00226  * Undoes latest velocity, setting the oldXXX values that were saved
00227  */
00228 void Cylinder::undoVelocity(void){
00229   position=oldPosition;
00230 
00231   orientationBase=oldOrientationBase;
00232   orientationWorld=orientationBase.toWorld(Vector3d(0,0,1));
00233   orientationWorld.normalize();
00234 
00235   velocity=oldVelocity;
00236   angularVelocity=oldAngularVelocity;
00237   force=oldForce;
00238   moment=oldMoment;
00239 }
00240 
00241 
00242 /**
00243  * Checks all collisions; against other cylinders, ground...
00244  */
00245 vector<Collision *> Cylinder::checkCollisions(){
00246   Collision *coll;
00247   vector<Collision *> ret;
00248   
00249   /// against ground
00250   coll=checkGroundCollision();
00251   if (NULL!=coll)
00252     ret.push_back(coll);
00253 
00254   /// against other cylinders
00255   unsigned int i;
00256   Cylinder *c;
00257   for (i=world->getNumCylinders();i--;){
00258     c=world->getCylinder(i);
00259     if (c!=this)
00260       if ((coll=checkCylinderCollision(c))!=NULL)
00261     ret.push_back(coll);
00262   }
00263 
00264   return ret;
00265 }
00266 
00267 /**
00268  * Check the collision against the ground
00269  *
00270  * The way it works is: 
00271  *
00272  * The cylinder is defined by two planes at position (p1) and at
00273  * position+orientation*height (p2) (the two extremes) and the
00274  * radius (width).
00275  *
00276  * 1.We check that p1 and p2 are above the plane, else they are in
00277  * contact, or more probably penetrating
00278  *
00279  * 2.then we check the lines that are the cut's of both planes to the
00280  * ground (l1 and l2), and the distance from the lines l1 and l2 to p1
00281  * and p2, respectively, if it's less than the radius, then the
00282  * cylinder cuts the plane. We check also for contact.
00283  */
00284 Collision *Cylinder::checkGroundCollision(){
00285   Point3d p1,p2, p0, pb1, pb2,pb0;
00286   Vector3d o=orientationWorld;
00287 
00288 
00289   p1=getPosition();
00290   p2=p1+(o*height);
00291   p0=p1+(o*(height/2));
00292   
00293   pb1=Vector3d(0,0,-length/2);
00294   pb2=Vector3d(0,0,+length/2);
00295   pb0=Vector3d(0,0,0);
00296 
00297 
00298   /// If any of the points is bellow, they are, for sure, penetrating
00299   if ((p1.Z()<-COLLISION_SPACE_EPSILUM)&&(p2.Z()<-COLLISION_SPACE_EPSILUM)){
00300     if (p1.Z()<p2.Z()){
00301       if ((velocity.Z()+orientationBase.toWorld(angularVelocity^pb1).Z())<COLLISION_VELOCITY_EPSILUM)
00302     return new Collision(this, pb1, penetrating);
00303     }
00304     else{
00305       if ((velocity.Z()+orientationBase.toWorld(angularVelocity^pb2).Z())<COLLISION_VELOCITY_EPSILUM)
00306     return new Collision(this, pb2, penetrating);
00307     }
00308   }
00309   if (p0.Z()<-COLLISION_SPACE_EPSILUM) // or only one
00310     if (velocity.Z()<COLLISION_VELOCITY_EPSILUM)
00311       return new Collision(this, pb0, penetrating);
00312   if (p1.Z()<-COLLISION_SPACE_EPSILUM) 
00313     if ((velocity.Z()+orientationBase.toWorld(angularVelocity^pb1).Z())<COLLISION_VELOCITY_EPSILUM)
00314       return new Collision(this, pb1, penetrating);
00315   if (p2.Z()<-COLLISION_SPACE_EPSILUM)
00316     if ((velocity.Z()+orientationBase.toWorld(angularVelocity^pb2).Z())<COLLISION_VELOCITY_EPSILUM)
00317       return new Collision(this, pb2, penetrating);
00318 
00319 
00320   /// If it's between -COL and +COL, they are in contact
00321   if (force.Z()<0){ /// Only if I'm accelerating vs the ground, and
00322             /// the point that goes against it
00323     if ((p1.Z()<COLLISION_SPACE_EPSILUM)&&(p2.Z()<COLLISION_SPACE_EPSILUM)){
00324       if (p1.Z()<p2.Z())
00325     return new Collision(this, pb1, contact);
00326       else
00327     return new Collision(this, pb2, contact);
00328     }
00329     if (p0.Z()<COLLISION_SPACE_EPSILUM) // or only one
00330       return new Collision(this, pb0, contact);
00331     if (p1.Z()<COLLISION_SPACE_EPSILUM)
00332       return new Collision(this, pb1, contact);
00333     if (p2.Z()<COLLISION_SPACE_EPSILUM)
00334       return new Collision(this, pb2, contact);
00335   }
00336 
00337   /// Greater than +COL... no collision
00338   return NULL;
00339 }
00340 
00341 /**
00342  * Check a collision against another cylinder. 
00343 
00344  * The way to calculate this is to first check the distance between
00345  * the two centers of gravity; if it's grater then the sum of both
00346  * lengths then sure they do not collide; then I check the distance
00347  * from both lines (each from one cylinder point, and with the
00348  * orientation).
00349  */
00350 Collision *Cylinder::checkCylinderCollision(Cylinder *other){
00351   return NULL;
00352   /*
00353   double dcc=(other->getCentreOfGravity()-getCentreOfGravity()).module(); /// Distance Center to Center
00354   double srr=(other->length+length);  /// Sum of Radius Radius
00355   if ( dcc > srr+2*COLLISION_SPACE_EPSILUM)
00356     return NULL;
00357 
00358   if ((orientationWorld^other->orientationWorld).module()==0){ // Parallel lines... just check distance...
00359     double d=(orientationWorld^(position-other->position)).module();
00360     d=(d-srr)/2;
00361     if (d<-COLLISION_SPACE_EPSILUM)
00362       return new Collision(this, other, other->getCentreOfGravity()+getCentreOfGravity()/2, penetrating);
00363     else if (d<COLLISION_SPACE_EPSILUM)
00364       return new Collision(this, other, other->getCentreOfGravity()+getCentreOfGravity()/2, contact);
00365     else 
00366       return NULL;
00367   }
00368   // Not parallel...
00369   /// Check distance between two lines!
00370 
00371 
00372   
00373   //new Collision(this, other, other->getCentreOfGravity()+getCentreOfGravity()/2, contact);
00374   
00375 
00376   return NULL;*/
00377 }

Generated on Mon Jun 17 19:53:44 2002 for Svas Server by doxygen1.2.16