Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

physics/CollisionDetector.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: CollisionDetector.cpp 1031 2004-02-11 20:46:36Z jungd $
00019   $Revision: 1.8 $
00020   $Date: 2004-02-11 15:46:36 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <physics/CollisionDetector>
00026 
00027 #include <base/Dimension3>
00028 #include <base/Transform>
00029 #include <gfx/Segment3>
00030 #include <physics/Box>
00031 #include <physics/Sphere>
00032 
00033 using physics::CollisionDetector;
00034 
00035 using base::Dimension3;
00036 using base::Transform;
00037 
00038 using gfx::Segment3;
00039 
00040 using physics::Collidable;
00041 using physics::CollidableBody;
00042 using physics::CollidableGroup;
00043 using physics::CollisionState;
00044 
00045 using physics::Shape;
00046 using physics::Box;
00047 using physics::Sphere;
00048 
00049 
00050 
00051 namespace physics {
00052 
00053 // needed by std::map CollisionStateMap
00054 bool operator<(ref<const CollidableBody> s1, const CollidableBody* s2)
00055 { return &(*s1) < s2; }
00056 
00057 }
00058 
00059 
00060 const Real CollisionDetector::collisionEpsilon = 1e-6;
00061 
00062 
00063 CollisionDetector::CollisionDetector()
00064  : queryType(AllContactPoints)
00065 {
00066 }
00067 
00068 
00069 CollisionDetector::~CollisionDetector()
00070 {
00071 }
00072 
00073 
00074 Segment3 CollisionDetector::shortestSegmentBetween(ref<const Collidable> collidable1, ref<const Collidable> collidable2)
00075 {
00076   //!!! this isn't properly implemented at present.  Can use GJK algorithm sometime.
00077   // Box stuff only uses box verts!
00078   
00079   if (instanceof(*collidable1, const CollidableGroup) || instanceof(*collidable2, const CollidableGroup))
00080     throw std::runtime_error(Exception("distance between CollidableGoups not yet implemented - sorry."));
00081   
00082   if (instanceof(*collidable1, const CollidableBody) && instanceof(*collidable1, const CollidableBody)) {
00083     
00084     ref<const CollidableBody> body1(narrow_ref<const CollidableBody>(collidable1));
00085     ref<const CollidableBody> body2(narrow_ref<const CollidableBody>(collidable2));
00086     
00087     ref<const Shape> shape1(body1->getShape());
00088     ref<const Shape> shape2(body2->getShape());
00089     
00090     //!!! a map of methods would have been better - probably won't need either when GJK is implemented
00091     
00092     if (instanceof(*shape1, const Box)) {
00093       
00094       ref<const Box> box1(narrow_ref<const Box>(shape1));
00095       
00096       if (instanceof(*shape2, const Box)) {
00097 
00098         ref<const Box> box2(narrow_ref<const Box>(shape2));
00099         
00100         return box1->shortestSegmentBetween(      body1->getConfiguration(),
00101                                             box2, body2->getConfiguration());
00102       }
00103       else if (instanceof(*shape2, const Sphere)) {
00104 
00105         ref<const Sphere> sphere2(narrow_ref<const Sphere>(shape2));
00106         
00107         // segment between box and sphere center                                           
00108         Segment3 seg( box1->shortestSegmentBetween( body1->getConfiguration(), 
00109                                                     body2->getPosition() ) );
00110         Real r(sphere2->radius());
00111         // shorten it by r on the e end
00112         Vector3 dir(seg.e-seg.s);
00113         seg.e = seg.s + dir*(1-(r/dir.length()));
00114         
00115         return seg;         
00116         
00117       }
00118       else
00119         throw std::runtime_error(Exception("unsupported Shape combination"));
00120       
00121     } 
00122     else if (instanceof(*shape1, const Sphere)) {
00123       
00124       ref<const Sphere> sphere1(narrow_ref<const Sphere>(shape1));
00125       
00126       if (instanceof(*shape2, const Box)) {
00127         
00128         Segment3 minSeg = shortestSegmentBetween(collidable2, collidable1);
00129         base::swap(minSeg.s, minSeg.e);
00130         return minSeg;
00131         
00132       }
00133       else if (instanceof(*shape2, const Sphere)) {
00134         ref<const Sphere> sphere2(narrow_ref<const Sphere>(shape2));
00135         
00136         Vector3 vdir( body2->getPosition() - body1->getPosition() ); vdir.normalize();
00137         Point3 spherep1( body1->getPosition() + vdir*sphere1->radius() );
00138         Point3 spherep2( body2->getPosition() - vdir*sphere2->radius() );
00139         return Segment3( spherep1, spherep2 );
00140       }
00141       else
00142         throw std::runtime_error(Exception("unsupported Shape combination"));
00143       
00144     }
00145     else
00146       throw std::runtime_error(Exception("unsupported Shape"));
00147     
00148     
00149   }
00150   else {
00151     throw std::runtime_error(Exception("unsupported Collidable subtype"));
00152   }
00153   
00154 }
00155 
00156 ref<CollisionState> CollisionDetector::getCollisionState(ref<const CollidableBody> collidableBody1, ref<const CollidableBody> collidableBody2) const
00157 {  
00158   if (&(*collidableBody1) > &(*collidableBody2))
00159     base::swap(collidableBody1,collidableBody2);
00160 
00161   CollidableBodyPair contactPair = std::make_pair(collidableBody1, collidableBody2);
00162 
00163   // is there a state entry in the map for this pair?
00164   CollisionStateMap::iterator entry = collisionStates.find(contactPair);
00165   if (entry != collisionStates.end()) {
00166     // yes, use it
00167     return entry->second;
00168   }
00169   else {
00170     // no, create a new one
00171     ref<CollisionState> collisionState = newCollisionState(collidableBody1,collidableBody2);
00172     collisionStates[contactPair] = collisionState; 
00173     return collisionState;
00174   }
00175 }
00176 
00177 

Generated on Thu Jul 29 15:56:22 2004 for OpenSim by doxygen 1.3.6