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

physics/GJKCollisionDetector.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: GJKCollisionDetector.cpp 1031 2004-02-11 20:46:36Z jungd $
00019   $Revision: 1.6 $
00020   $Date: 2004-02-11 15:46:36 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <physics/GJKCollisionDetector>
00026 #include <gfx/Triangle3>
00027 #include <base/ref>
00028 #include <base/Quat4>
00029 
00030 using physics::GJKCollisionDetector;
00031 using physics::CollisionState;
00032 using physics::CollisionModelProvider;
00033 using base::Vector3;
00034 using base::Matrix3;
00035 using base::transpose;
00036 using base::inverse;
00037 using base::cross;
00038 using gfx::Triangle3;
00039 
00040 
00041 #include <osg/Node>
00042 #include <osg/Group>
00043 #include <osg/Geode>
00044 #include <osg/Transform>
00045 #include <osg/StateSet>
00046 #include <osg/Material>
00047 #include <osg/Array>
00048 #include <osg/PolygonMode>
00049 #include <osg/Geometry>
00050 
00051 using osg::Vec4;
00052 using osg::StateSet;
00053 
00054 
00055 
00056 
00057 // public
00058 
00059 
00060 GJKCollisionDetector::GJKCollisionDetector()
00061   : collisionDetectionEnabled(true), node(0)
00062 {
00063 }
00064 
00065 
00066 GJKCollisionDetector::~GJKCollisionDetector()
00067 {
00068 }
00069 
00070 
00071 const Real rel_error = 1e-6; // relative error in the computed distance
00072 const Real abs_error = 1e-10; // absolute error if the distance is almost zero
00073   
00074 
00075 
00076 GJKCollisionDetector::GJKCollisionState::GJKCollisionState(ref<const Solid> solid1, ref<const Solid> solid2,
00077                                                            CollisionModel::CollisionModelType modelType)
00078   : CollisionState(solid1, solid2)
00079 {
00080   ref<const GJKCollisionModel> cm1 = narrow_ref<const GJKCollisionModel>( solid1->getCollisionModel(modelType) );
00081   ref<const GJKCollisionModel> cm2 = narrow_ref<const GJKCollisionModel>( solid2->getCollisionModel(modelType) );
00082 
00083 }
00084 
00085 GJKCollisionDetector::GJKCollisionState::~GJKCollisionState()
00086 {
00087 }
00088 
00089 
00090 
00091 
00092 ref<CollisionState> GJKCollisionDetector::newCollisionState(ref<const Solid> solid1, ref<const Solid> solid2) const
00093 {
00094   GJKCollisionState *sp = NewNamedObj("GJKCollisionState") GJKCollisionState(solid1, solid2, getType());
00095   return ref<GJKCollisionState>(sp);
00096 }
00097 
00098 bool GJKCollisionDetector::collision(ref<const Solid> solid1, ref<const Solid> solid2, CollisionQueryType queryType)
00099 {
00100   if (!collisionDetectionEnabled) return false;
00101   if (queryType == PotentialCollision) return true;
00102 
00103   // This must be called before GJK intersect/closest_points functions
00104   // to ensure that a GJKCollisionState for the pair has been created
00105 
00106   ref<GJKCollisionState> cs(narrow_ref<GJKCollisionState>(getCollisionState(solid1,solid2))); 
00107 
00108   // Do a pair-wise collision check
00109 
00110   ref<const GJKCollisionModel> model1 
00111     = narrow_ref<const GJKCollisionModel>(solid1->getCollisionModel(getType()));
00112   ref<const GJKCollisionModel> model2 
00113     = narrow_ref<const GJKCollisionModel>(solid2->getCollisionModel(getType()));
00114   
00115   base::Transform t1(solid1->getPosition(), solid1->getOrientation());
00116   base::Transform t2(solid2->getPosition(), solid2->getOrientation());
00117   
00118   // update OSGVisual (if it exists)
00119   if (node!=0) {
00120     const Point3 s0(t1(cs->lastSupportPoint[0]));
00121     const Point3 s1(t2(cs->lastSupportPoint[1]));
00122     (*verts)[0].set(s0.x,s0.y,s0.z); 
00123     (*verts)[1].set(s1.x,s1.y,s1.z); 
00124     geom->setVertexArray(verts);
00125   }
00126 
00127 
00128   // get last support verts
00129   ref<const Polyhedron::Vertex> support0(cs->lastSupport[0]);
00130   ref<const Polyhedron::Vertex> support1(cs->lastSupport[1]);
00131 
00132   // perform collision check
00133   ref<GJKCollisionModel::GJKModelState> ms1(NewObj GJKCollisionModel::GJKModelState(support0));
00134   ref<GJKCollisionModel::GJKModelState> ms2(NewObj GJKCollisionModel::GJKModelState(support1));
00135 
00136   bool collided = intersect(model1, model2, t1, t2, ms1, ms2, cs);
00137 
00138   cs->lastSupport[0] = ms1->lastSupport;
00139   cs->lastSupport[1] = ms2->lastSupport;
00140   cs->lastSupportPoint[0] = ms1->lastSupportPoint;
00141   cs->lastSupportPoint[1] = ms2->lastSupportPoint;
00142 
00143 
00144   if (collided) {
00145 
00146     // construct contacts 
00147 
00148     /*    
00149     const DtScalar* p1 = collision_data->point1;
00150     const DtScalar* p2 = collision_data->point2;
00151     const DtScalar* n = collision_data->normal;
00152     Point3 cp1(p1[0],p1[1],p1[2]);
00153     Point3 cp2(p2[0],p2[1],p2[2]);
00154     Vector3 cn(n[0],n[1],n[2]);
00155     CollisionState::Contact contact(cp1, cp2,cn);
00156 
00157     cs->contacts.clear();
00158     cs->contacts.push_back(contact);
00159     */
00160     
00161     std::cout << "Collided.\n"; //  T1=\n" << T1.getBasis() << "\n:" << T1.getOrigin() << "\n";
00162   }
00163   else {
00164     std::cout << "No Collision\n"; // v=" << cs->v << std::endl;
00165   }
00166     
00167   return collided;
00168 }
00169 
00170 
00171 // GJK algorithm
00172 
00173 void GJKCollisionDetector::compute_det() 
00174 {
00175   static Real dp[4][4];
00176 
00177   for (Int i = 0, bit = 1; i < 4; ++i, bit <<=1) 
00178     if (bits & bit) dp[i][last] = dp[last][i] = dot(y[i], y[last]);
00179   dp[last][last] = dot(y[last], y[last]);
00180 
00181   det[last_bit][last] = 1;
00182   for (Int j = 0, sj = 1; j < 4; ++j, sj <<= 1) {
00183     if (bits & sj) {
00184       Int s2 = sj|last_bit;
00185       det[s2][j] = dp[last][last] - dp[last][j]; 
00186       det[s2][last] = dp[j][j] - dp[j][last];
00187       for (Int k = 0, sk = 1; k < j; ++k, sk <<= 1) {
00188         if (bits & sk) {
00189           Int s3 = sk|s2;
00190           det[s3][k] = det[s2][j] * (dp[j][j] - dp[j][k]) + 
00191                        det[s2][last] * (dp[last][j] - dp[last][k]);
00192           det[s3][j] = det[sk|last_bit][k] * (dp[k][k] - dp[k][j]) + 
00193                        det[sk|last_bit][last] * (dp[last][k] - dp[last][j]);
00194           det[s3][last] = det[sk|sj][k] * (dp[k][k] - dp[k][last]) + 
00195                           det[sk|sj][j] * (dp[j][k] - dp[j][last]);
00196         }
00197       }
00198     }
00199   }
00200   if (all_bits == 15) {
00201     det[15][0] = det[14][1] * (dp[1][1] - dp[1][0]) + 
00202                  det[14][2] * (dp[2][1] - dp[2][0]) + 
00203                  det[14][3] * (dp[3][1] - dp[3][0]);
00204     det[15][1] = det[13][0] * (dp[0][0] - dp[0][1]) + 
00205                  det[13][2] * (dp[2][0] - dp[2][1]) + 
00206                  det[13][3] * (dp[3][0] - dp[3][1]);
00207     det[15][2] = det[11][0] * (dp[0][0] - dp[0][2]) + 
00208                  det[11][1] * (dp[1][0] - dp[1][2]) +  
00209                  det[11][3] * (dp[3][0] - dp[3][2]);
00210     det[15][3] = det[7][0] * (dp[0][0] - dp[0][3]) + 
00211                  det[7][1] * (dp[1][0] - dp[1][3]) + 
00212                  det[7][2] * (dp[2][0] - dp[2][3]);
00213   }
00214 }
00215 
00216 
00217 inline bool GJKCollisionDetector::valid(Int s) 
00218 {  
00219   for (Int i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
00220     if (all_bits & bit) {
00221       if (s & bit) { if (det[s][i] <= 0) return false; }
00222       else if (det[s|bit][i] > 0) return false;
00223     }
00224   }
00225   return true;
00226 }
00227 
00228 inline void GJKCollisionDetector::compute_vector(Int bits, Vector3& v)
00229 {
00230   Real sum = 0;
00231   v.setZero();
00232   for (Int i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
00233     if (bits & bit) {
00234       sum += det[bits][i];
00235       v += y[i] * det[bits][i];
00236     }
00237   }
00238   v *= 1 / sum;
00239 }
00240 
00241 inline void GJKCollisionDetector::compute_points(int bits, Point3& p1, Point3& p2)
00242 {
00243   Real sum = 0;
00244   p1.setZero();
00245   p2.setZero();
00246   for (Int i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
00247     if (bits & bit) {
00248       sum += det[bits][i];
00249       p1 += p[i] * det[bits][i];
00250       p2 += q[i] * det[bits][i];
00251     }
00252   }
00253   Real s = 1 / sum;
00254   p1 *= s;
00255   p2 *= s;
00256 }
00257 
00258 inline bool GJKCollisionDetector::closest(Vector3& v) 
00259 {
00260   compute_det();
00261   for (Int s = bits; s; --s) {
00262     if ((s & bits) == s) {
00263       if (valid(s|last_bit)) {
00264         bits = s|last_bit;
00265         compute_vector(bits, v);
00266         return true;
00267       }
00268     }
00269   }
00270   if (valid(last_bit)) {
00271     bits = last_bit;
00272     v = y[last];
00273     return true;
00274   }
00275 
00276   return false;
00277 }
00278 
00279 
00280 bool GJKCollisionDetector::intersect(ref<const GJKCollisionModel> model1, ref<const GJKCollisionModel> model2,
00281                                      const base::Transform& t1, const base::Transform& t2, 
00282                                      ref<GJKCollisionModel::GJKModelState> modelState1,
00283                                      ref<GJKCollisionModel::GJKModelState> modelState2,
00284                                      ref<GJKCollisionState> collisionState)
00285 {
00286   Vector3 w;
00287   Vector3& v(collisionState->v);
00288 
00289   bits = 0;
00290   all_bits = 0;
00291 
00292 
00293   do {
00294     last = 0;
00295     last_bit = 1;
00296     while (bits & last_bit) { ++last; last_bit <<= 1; }
00297     w =   t1(model1->support(modelState1,t1.rotate(-v))) 
00298         - t2(model2->support(modelState2,t2.rotate( v))); 
00299     if (dot(v, w) > 0) return false;
00300 
00301     y[last] = w;
00302     all_bits = bits|last_bit;
00303     if (!closest(v)) {
00304       return false;
00305     }
00306   } 
00307   while (bits < 15 && !v.equalsZero() ); 
00308   return true;
00309 }
00310 
00311 
00312 
00313 /// create a visual for debugging purposes
00314 osg::Node* GJKCollisionDetector::createOSGVisual(Visual::Attributes visualAttributes) const
00315 {
00316   if (!(visualAttributes & ShowCollisionDetection)) return NewObj osg::Node();
00317 
00318   if ((node!=0) && (attributes==visualAttributes))
00319     return &(*node);
00320 
00321   // show a line between the last support point and the passed v.
00322   geom = new osg::Geometry();
00323 
00324   StateSet* state = new osg::StateSet();
00325   osg::Material* mat = new osg::Material();
00326   Vec4 col( 1, 1, 0, 1);
00327   mat->setAmbient( osg::Material::FRONT_AND_BACK, col );
00328   mat->setDiffuse( osg::Material::FRONT_AND_BACK, col );
00329   state->setAttribute( mat );
00330   //geom->setStateSet(state);
00331 
00332   verts = new osg::Vec3Array(2);
00333   (*verts)[0].set(0,0,0);
00334   (*verts)[1].set(0,0,0);
00335   geom->setVertexArray(verts);
00336 
00337   osg::Vec4Array* colors = new osg::Vec4Array(1);
00338   (*colors)[0].set(1.0f,0.0f,0.0f,1.0f);
00339   geom->setColorArray(colors);
00340   geom->setColorBinding(osg::Geometry::BIND_OVERALL);
00341 
00342   osg::DrawArrays* linearray = new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2);
00343   geom->addPrimitiveSet(linearray);
00344 
00345   osg::Geode* geode = new osg::Geode();
00346   geode = new osg::Geode();
00347   geode->setName("Debug");
00348   geode->addDrawable(&(*geom));
00349 
00350   node = geode;
00351   attributes = visualAttributes;
00352 
00353   return &(*node);
00354 }
00355 

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