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

physics/OBBCollisionDetector.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: OBBCollisionDetector.cpp 1031 2004-02-11 20:46:36Z jungd $
00019   $Revision: 1.3 $
00020   $Date: 2004-02-11 15:46:36 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <physics/OBBCollisionDetector>
00026 #include <base/Quat4>
00027 
00028 using physics::OBBCollisionDetector;
00029 using physics::CollisionState;
00030 using physics::CollisionModelProvider;
00031 using base::Vector3;
00032 using base::Matrix3;
00033 using base::transpose;
00034 using base::inverse;
00035 using base::cross;
00036 using gfx::Triangle3;
00037 
00038 
00039 // public
00040 
00041 bool OBBCollisionDetector::collision(ref<const Solid> solid1, ref<const Solid> solid2, CollisionQueryType queryType)
00042 {
00043   if (!collisionDetectionEnabled) return false;
00044   if (queryType == PotentialCollision) return true;
00045 
00046   ref<const OBBCollisionModel> model1 
00047     = narrow_ref<const OBBCollisionModel>(solid1->getCollisionModel(getType()));
00048   ref<const OBBCollisionModel> model2 
00049     = narrow_ref<const OBBCollisionModel>(solid2->getCollisionModel(getType()));
00050 
00051   Matrix3 R1 = Matrix4(solid1->getOrientation()); // a better way to convert? !!
00052   Matrix3 R2 = Matrix4(solid2->getOrientation());
00053   const Vector3& T1(solid1->getPosition());
00054   const Vector3& T2(solid2->getPosition());
00055 
00056   // Collision test
00057   Collide(R1, T1, model1, R2, T2, model2, queryType);
00058   //std::cout << "State - box:" << numBoxTests
00059   //        << " tri: " << numTriTests
00060   //        << " contacts:" << contacts.size() 
00061   //        << " contact:" << contacts[0].first << "\n";
00062 
00063   double R1a[3][3];
00064   R1a[0][0] = R1(1,1); R1a[0][1] = R1(1,2); R1a[0][2] = R1(1,3);
00065   R1a[1][0] = R1(2,1); R1a[1][1] = R1(2,2); R1a[1][2] = R1(2,3);
00066   R1a[2][0] = R1(3,1); R1a[2][1] = R1(3,2); R1a[2][2] = R1(3,3);
00067   double R2a[3][3];
00068   R2a[0][0] = R2(1,1); R2a[0][1] = R2(1,2); R2a[0][2] = R2(1,3);
00069   R2a[1][0] = R2(2,1); R2a[1][1] = R2(2,2); R2a[1][2] = R2(2,3);
00070   R2a[2][0] = R2(3,1); R2a[2][1] = R2(3,2); R2a[2][2] = R2(3,3);
00071 
00072   double T1a[3]; T1a[0] = T1[1]; T1a[1] = T1[2]; T1a[2] = T1[3];
00073   double T2a[3]; T2a[0] = T2[1]; T2a[1] = T2[2]; T2a[2] = T2[3];
00074   
00075   // find the CollisionState
00076   ref<CollisionState> collisionState = getCollisionState(solid1,solid2);
00077   ref<OBBCollisionState> state = narrow_ref<OBBCollisionState>(collisionState);
00078   state->contacts.clear();
00079   
00080   // Compute collision points (if required)
00081   if ( ((queryType == FirstContactPoint) 
00082         || (queryType == AllContactPoints))
00083        && contacts.size() > 0) {
00084     
00085     Int i=0;
00086     do {
00087       Triangle3 t1 = contacts[i].first;
00088       Triangle3 t2 = contacts[i].second;
00089       
00090       // !!! this is a hack for the contact normal - compute it properly!!
00091       Vector3 normal1(t1.normal());
00092 
00093       // Transform to world coords
00094       t1.transform(R1); t1 += T1;
00095       t2.transform(R2); t2 += T2;
00096       
00097       Point3 contactPoint; //!!! fix = t1.intersect(t2);
00098       
00099       if (contactPoint == Point3()) {
00100         //Debugln("Failed to compute contact point!");
00101         contactPoint = (t2[1]+t2[2]+t2[3])/3.0;
00102       }
00103       
00104       Point3 contact1(contactPoint-T1);//!!! untested
00105       contact1 = inverse(R1)*contact1;
00106       Point3 contact2(contactPoint-T2);
00107       contact2 = inverse(R2)*contact2;
00108 
00109       //      Point3 contact1(gfx::inverse(transform1.getTransform())*contactPoint);
00110       //      Point3 contact2(gfx::inverse(transform2.getTransform())*contactPoint);
00111       
00112       //                        Debugln("Contacts:" << i << ": " << contact1 << " and " << contact2 
00113       //                                                        << " global:" << contactPoint);
00114 
00115       state->contacts.push_back(CollisionState::Contact(contact1,contact2,normal1));
00116       
00117       i++;
00118     } while ((i < contacts.size()) && (queryType == AllContactPoints));
00119     
00120   }
00121     
00122   return (contacts.size() > 0);
00123 }
00124 
00125 
00126 
00127 
00128 
00129 
00130 
00131 // protected
00132 
00133 void OBBCollisionDetector::Collide(const base::Matrix3& R1, const gfx::Vector3& T1, 
00134                                    ref<const OBBCollisionModel> model1,
00135                                    const base::Matrix3& R2, const gfx::Vector3& T2, 
00136                                    ref<const OBBCollisionModel> model2,
00137                                    CollisionQueryType queryType)
00138 {
00139   Collide(R1,T1,1.0,model1,R2,T2,1.0,model2,queryType);
00140 }
00141 
00142 
00143 void OBBCollisionDetector::Collide(const base::Matrix3& R1, const gfx::Vector3& T1, Real s1, 
00144                                    ref<const OBBCollisionModel> model1,
00145                                    const base::Matrix3& R2, const gfx::Vector3& T2, Real s2, 
00146                                    ref<const OBBCollisionModel> model2,
00147                                    CollisionQueryType queryType)
00148 {
00149   // reset the report fields
00150   numBoxTests = 0;
00151   numTriTests = 0;
00152   contacts.clear();
00153 
00154   if (model1->tris.empty() || model2->tris.empty()) return; // no triangles in one of the models
00155 
00156   const OBBCollisionModel::OBB& b1(model1->b[0]);
00157   const OBBCollisionModel::OBB& b2(model2->b[0]);
00158   
00159   firstContact = (queryType==DetectCollision) || (queryType==FirstContactPoint);
00160   
00161   Matrix3 tR1, tR2, R;
00162   Vector3 tT1, tT2, T, U;
00163   Real s;
00164         
00165   // [R1,T1,s1] and [R2,T2,s2] are how the two triangle sets
00166   // (i.e. models) are positioned in world space.  [tR1,tT1,s1] and
00167   // [tR2,tT2,s2] are how the top level boxes are positioned in world
00168   // space
00169   
00170   tR1 = R1*b1.pR;
00171   tT1 = (s1*R1)*b1.pT+T1;
00172   tR2 = R2*b2.pR;
00173   tT2 = (s2*R2)*b2.pT+T2;
00174   
00175   // (R,T,s) is the placement of b2's top level box within
00176   // the coordinate system of b1's top level box.
00177   
00178   R = transpose(tR1)*tR2;       
00179   U = tT2-tT1;
00180   T = (transpose(tR1)*U)/s1;
00181   
00182   s = s2/s1;
00183   
00184   // To transform tri's from model1's CS to model2's CS use this:
00185   //    x2 = ms . mR . x1 + mT
00186   mR = transpose(R2)*R1;
00187   U = T1-T2;
00188   mT = (transpose(R2)*U)/s2;
00189   ms = s1/s2;
00190   
00191   // make the call
00192   collideRecursive(b1, b2, R, T, s);
00193 
00194 }
00195 
00196 
00197 void OBBCollisionDetector::collideRecursive(const OBBCollisionModel::OBB& b1, 
00198                                             const OBBCollisionModel::OBB& b2,
00199                                             const base::Matrix3& R, const base::Vector3& T, double s)
00200 {
00201   if ((firstContact) && (contacts.size() > 0)) return;
00202   
00203   // test top level
00204   numBoxTests++;
00205   
00206   Vector3 d(s*b2.d);
00207   Int f1 = OBBDisjoint(R, T, b1.d, d);
00208   
00209   if (f1 != 0) 
00210     return;  // stop processing this test, go to top of loop
00211   
00212   // contact between boxes
00213   if (b1.leaf() && b2.leaf()) {
00214     // it is a leaf pair - compare the polygons therein
00215     // tri_contact uses the model-to-model transforms stored in
00216     // mR, mT, ms.
00217     
00218     triContact(b1, b2);
00219     return;
00220   }
00221   
00222   Vector3 U;
00223   Matrix3 cR;
00224   Vector3 cT;
00225   Real cs;
00226   
00227   // Currently, the transform from model 2 to model 1 space is
00228   // given by [B T s], where y = [B T s].x = s.B.x + T.
00229   
00230   if (b2.leaf() || (!b1.leaf() && (b1.size() > b2.size()))) {
00231     // here we descend to children of b1.  The transform from
00232     // a child of b1 to b1 is stored in [b1.N.pR,b1.N.pT],
00233     // but we will denote it [B1 T1 1] for short.  Notice that
00234     // children boxes always have same scaling as parent, so s=1
00235     // for such nested transforms.
00236     
00237     // Here, we compute [B1 T1 1]'[B T s] = [B1'B B1'(T-T1) s]
00238     // for each child, and store the transform into the collision
00239     // test queue.
00240     
00241     cR = transpose(b1.N->pR)*R;
00242     U=T-b1.N->pT;
00243     cT = transpose(b1.N->pR)*U;
00244     cs = s;
00245     
00246     collideRecursive(*b1.N, b2, cR, cT, cs);
00247     
00248     cR = transpose(b1.P->pR)*R;
00249     U=T-b1.P->pT;
00250     cT=transpose(b1.P->pR)*U;
00251     cs = s;
00252     
00253     collideRecursive(*b1.P, b2, cR, cT, cs);
00254     
00255     return;
00256   }
00257   else {
00258     // here we descend to the children of b2.  See comments for
00259     // other 'if' clause for explanation.
00260     
00261     cR = R*b2.N->pR;
00262     cT = (s*R)*b2.N->pT+T;
00263     cs = s;
00264     
00265     collideRecursive(b1, *b2.N, cR, cT, cs);
00266     
00267     cR = R*b2.P->pR;
00268     cT = (s*R)*b2.P->pT+T;
00269     cs = s;
00270     
00271     collideRecursive(b1, *b2.P, cR, cT, cs);
00272     
00273     return; 
00274   }
00275 }
00276 
00277 
00278 void OBBCollisionDetector::triContact(const OBBCollisionModel::OBB& b1,
00279                                       const OBBCollisionModel::OBB& b2)
00280 {
00281   // assume just one triangle in each box.
00282   
00283   // the vertices of the tri in b2 is in model1 C.S.  The vertices of
00284   // the other triangle is in model2 CS.  Use mR, mT, and
00285   // ms to transform into model2 CS.
00286   p1 = b1.tr.p1();
00287   p2 = b1.tr.p2();
00288   p3 = b1.tr.p3();
00289   
00290   Matrix3 msR(ms*mR);
00291   i1 = msR*p1+mT;
00292   i2 = msR*p2+mT;
00293   i3 = msR*p3+mT;
00294   
00295   numTriTests++;
00296   
00297   if (triContact(i1, i2, i3, b2.tr.p1(), b2.tr.p2(), b2.tr.p3()))
00298     contacts.push_back(std::pair<Triangle3,Triangle3>(b1.tr, b2.tr));
00299 }
00300 
00301 
00302 bool OBBCollisionDetector::triContact(const base::Vector3& P1, const base::Vector3& P2, const base::Vector3& P3,
00303                                       const base::Point3& Q1, const base::Point3& Q2, const base::Point3& Q3)
00304 {
00305   /*
00306     One triangle is (p1,p2,p3).  Other is (q1,q2,q3).
00307     Edges are (e1,e2,e3) and (f1,f2,f3).
00308     Normals are n1 and m1
00309     Outwards are (g1,g2,g3) and (h1,h2,h3).
00310     
00311     We assume that the triangle vertices are in the same coordinate system.
00312     
00313     First thing we do is establish a new c.s. so that p1 is at (0,0,0).
00314     
00315   */
00316   z.setZero();
00317   
00318   p1 = P1-P1;
00319   p2 = P2-P1;
00320   p3 = P3-P1;
00321   
00322   q1 = Q1-P1;
00323   q2 = Q2-P1;
00324   q3 = Q3-P1;
00325   
00326   e1 = p2-p1;
00327   e2 = p3-p2;
00328   e3 = p1-p3;
00329   
00330   f1 = q2-q1;
00331   f2 = q3-q2;
00332   f3 = q1-q3;
00333   
00334   n1.cross(e1, e2);
00335   m1.cross(f1, f2);
00336   
00337   g1.cross(e1, n1);
00338   g2.cross(e2, n1);
00339   g3.cross(e3, n1);
00340   h1.cross(f1, m1);
00341   h2.cross(f2, m1);
00342   h3.cross(f3, m1);
00343   
00344   ef11.cross(e1, f1);
00345   ef12.cross(e1, f2);
00346   ef13.cross(e1, f3);
00347   ef21.cross(e2, f1);
00348   ef22.cross(e2, f2);
00349   ef23.cross(e2, f3);
00350   ef31.cross(e3, f1);
00351   ef32.cross(e3, f2);
00352   ef33.cross(e3, f3);
00353   
00354   // now begin the series of tests
00355   
00356   if (!project6(n1, p1, p2, p3, q1, q2, q3)) return false;
00357   if (!project6(m1, p1, p2, p3, q1, q2, q3)) return false;
00358   
00359   if (!project6(ef11, p1, p2, p3, q1, q2, q3)) return false;
00360   if (!project6(ef12, p1, p2, p3, q1, q2, q3)) return false;
00361   if (!project6(ef13, p1, p2, p3, q1, q2, q3)) return false;
00362   if (!project6(ef21, p1, p2, p3, q1, q2, q3)) return false;
00363   if (!project6(ef22, p1, p2, p3, q1, q2, q3)) return false;
00364   if (!project6(ef23, p1, p2, p3, q1, q2, q3)) return false;
00365   if (!project6(ef31, p1, p2, p3, q1, q2, q3)) return false;
00366   if (!project6(ef32, p1, p2, p3, q1, q2, q3)) return false;
00367   if (!project6(ef33, p1, p2, p3, q1, q2, q3)) return false;
00368   
00369   if (!project6(g1, p1, p2, p3, q1, q2, q3)) return false;
00370   if (!project6(g2, p1, p2, p3, q1, q2, q3)) return false;
00371   if (!project6(g3, p1, p2, p3, q1, q2, q3)) return false;
00372   if (!project6(h1, p1, p2, p3, q1, q2, q3)) return false;
00373   if (!project6(h2, p1, p2, p3, q1, q2, q3)) return false;
00374   if (!project6(h3, p1, p2, p3, q1, q2, q3)) return false;
00375   
00376   return true;
00377 }
00378 
00379 
00380 bool OBBCollisionDetector::project6(const Vector3& ax, 
00381                                     const Vector3& p1, const Vector3& p2, const Vector3& p3,
00382                                     const Vector3& q1, const Vector3& q2, const Vector3& q3) const
00383 {
00384   Real P1 = ax.dot(p1);
00385   Real P2 = ax.dot(p2);
00386   Real P3 = ax.dot(p3);
00387   Real Q1 = ax.dot(q1);
00388   Real Q2 = ax.dot(q2);
00389   Real Q3 = ax.dot(q3);
00390   
00391   Real mx1 = Math::maximum(P1, P2, P3);
00392   Real mn1 = Math::minimum(P1, P2, P3);
00393   Real mx2 = Math::maximum(Q1, Q2, Q3);
00394   Real mn2 = Math::minimum(Q1, Q2, Q3);
00395   
00396   if (mn1 > mx2) return false;
00397   if (mn2 > mx1) return false;
00398   return true;
00399 }
00400 
00401 
00402 Int OBBCollisionDetector::OBBDisjoint(const base::Matrix3& B, const gfx::Vector3& T,
00403                                       const base::Vector3& a, const gfx::Vector3& b)
00404 {
00405   Real t, s;
00406   
00407   // Bf = fabs(B)
00408   const Real reps = CollisionDetector::collisionEpsilon;
00409   Bf.e(1,1) = base::abs(B.e(1,1));  Bf.e(1,1) += reps;
00410   Bf.e(1,2) = base::abs(B.e(1,2));  Bf.e(1,2) += reps;
00411   Bf.e(1,3) = base::abs(B.e(1,3));  Bf.e(1,3) += reps;
00412   Bf.e(2,1) = base::abs(B.e(2,1));  Bf.e(2,1) += reps;
00413   Bf.e(2,2) = base::abs(B.e(2,2));  Bf.e(2,2) += reps;
00414   Bf.e(2,3) = base::abs(B.e(2,3));  Bf.e(2,3) += reps;
00415   Bf.e(3,1) = base::abs(B.e(3,1));  Bf.e(3,1) += reps;
00416   Bf.e(3,2) = base::abs(B.e(3,2));  Bf.e(3,2) += reps;
00417   Bf.e(3,3) = base::abs(B.e(3,3));  Bf.e(3,3) += reps;
00418   
00419   // if any of these tests are one-sided, then the polyhedra are disjoint
00420   
00421   // A1 x A2 = A0
00422   t = base::abs(T.x);
00423   
00424   if (!(t <= (a.x + b.x * Bf.e(1,1) + b.y * Bf.e(1,2) + b.z * Bf.e(1,3)))) return 1;
00425   
00426   // B1 x B2 = B0
00427   s = T.x*B.e(1,1) + T.y*B.e(2,1) + T.z*B.e(3,1);
00428   t = base::abs(s);
00429   
00430   if (!(t <= (b.x + a.x * Bf.e(1,1) + a.y * Bf.e(2,1) + a.z * Bf.e(3,1)))) return 2;
00431   
00432   // A2 x A0 = A1
00433   t = base::abs(T.y);
00434   
00435   if (!(t <= (a.y + b.x * Bf.e(2,1) + b.y * Bf.e(2,2) + b.z * Bf.e(2,3)))) return 3;
00436   
00437   // A0 x A1 = A2
00438   t = base::abs(T.z);
00439   
00440   if (!(t <= (a.z + b.x * Bf.e(3,1) + b.y * Bf.e(3,2) + b.z * Bf.e(3,3)))) return 4;
00441   
00442   // B2 x B0 = B1
00443   s = T.x*B.e(1,2) + T.y*B.e(2,2) + T.z*B.e(3,2);
00444   t = base::abs(s);
00445   
00446   if (!(t <=(b.y + a.x * Bf.e(1,2) + a.y * Bf.e(2,2) + a.z * Bf.e(3,2)))) return 5;
00447   
00448   // B0 x B1 = B2
00449   s = T.x*B.e(1,3) + T.y*B.e(2,3) + T.z*B.e(3,3);
00450   t = base::abs(s);
00451   
00452   if (!(t <= (b.z + a.x * Bf.e(1,3) + a.y * Bf.e(2,3) + a.z * Bf.e(3,3)))) return 6;
00453   
00454   // A0 x B0
00455   s = T.z * B.e(2,1) - T.y * B.e(3,1);
00456   t = base::abs(s);
00457   
00458   if (!(t <= (a.y * Bf.e(3,1) + a.z * Bf.e(2,1) + b.y * Bf.e(1,3) + b.z * Bf.e(1,2)))) return 7;
00459   
00460   // A0 x B1
00461   s = T.z * B.e(2,2) - T.y * B.e(3,2);
00462   t = base::abs(s);
00463   
00464   if (!(t <= (a.y * Bf.e(3,2) + a.z * Bf.e(2,2) + b.x * Bf.e(1,3) + b.z * Bf.e(1,1)))) return 8;
00465   
00466   // A0 x B2
00467   s = T.z * B.e(2,3) - T.y * B.e(3,3);
00468   t = base::abs(s);
00469   
00470   if (!(t <= (a.y * Bf.e(3,3) + a.z * Bf.e(2,3) + b.x * Bf.e(1,2) + b.y * Bf.e(1,1)))) return 9;
00471   
00472   // A1 x B0
00473   s = T.x * B.e(3,1) - T.z * B.e(1,1);
00474   t = base::abs(s);
00475   
00476   if (!(t <= (a.x * Bf.e(3,1) + a.z * Bf.e(1,1) + b.y * Bf.e(2,3) + b.z * Bf.e(2,2)))) return 10;
00477   
00478   // A1 x B1
00479   s = T.x * B.e(3,2) - T.z * B.e(1,2);
00480   t = base::abs(s);
00481   
00482   if (!(t <=(a.x * Bf.e(3,2) + a.z * Bf.e(1,2) + b.x * Bf.e(2,3) + b.z * Bf.e(2,1)))) return 11;
00483   
00484   // A1 x B2
00485   s = T.x * B.e(3,3) - T.z * B.e(1,3);
00486   t = base::abs(s);
00487   
00488   if (!(t <= (a.x * Bf.e(3,3) + a.z * Bf.e(1,3) + b.x * Bf.e(2,2) + b.y * Bf.e(2,1)))) return 12;
00489   
00490   // A2 x B0
00491   s = T.y * B.e(1,1) - T.x * B.e(2,1);
00492   t = base::abs(s);
00493   
00494   if (!(t <= (a.x * Bf.e(2,1) + a.y * Bf.e(1,1) + b.y * Bf.e(3,3) + b.z * Bf.e(3,2)))) return 13;
00495   
00496   // A2 x B1
00497   s = T.y * B.e(1,2) - T.x * B.e(2,2);
00498   t = base::abs(s);
00499   
00500   if (!(t <=(a.x * Bf.e(2,2) + a.y * Bf.e(1,2) + b.x * Bf.e(3,3) + b.z * Bf.e(3,1)))) return 14;
00501   
00502   // A2 x B2
00503   s = T.y * B.e(1,3) - T.x * B.e(2,3);
00504   t = base::abs(s);
00505   
00506   if (!(t <=(a.x * Bf.e(2,3) + a.y * Bf.e(1,3) + b.x * Bf.e(3,2) + b.y * Bf.e(3,1)))) return 15;
00507   
00508   return 0; 
00509   
00510 }

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