SphereTriangleDetector.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 #include "LinearMath/btScalar.h"
00017 #include "SphereTriangleDetector.h"
00018 #include "BulletCollision/CollisionShapes/btTriangleShape.h"
00019 #include "BulletCollision/CollisionShapes/btSphereShape.h"
00020 
00021 
00022 SphereTriangleDetector::SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle,btScalar contactBreakingThreshold)
00023 :m_sphere(sphere),
00024 m_triangle(triangle),
00025 m_contactBreakingThreshold(contactBreakingThreshold)
00026 {
00027 
00028 }
00029 
00030 void    SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
00031 {
00032 
00033         (void)debugDraw;
00034         const btTransform& transformA = input.m_transformA;
00035         const btTransform& transformB = input.m_transformB;
00036 
00037         btVector3 point,normal;
00038         btScalar timeOfImpact = btScalar(1.);
00039         btScalar depth = btScalar(0.);
00040 //      output.m_distance = btScalar(BT_LARGE_FLOAT);
00041         //move sphere into triangle space
00042         btTransform     sphereInTr = transformB.inverseTimes(transformA);
00043 
00044         if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact,m_contactBreakingThreshold))
00045         {
00046                 if (swapResults)
00047                 {
00048                         btVector3 normalOnB = transformB.getBasis()*normal;
00049                         btVector3 normalOnA = -normalOnB;
00050                         btVector3 pointOnA = transformB*point+normalOnB*depth;
00051                         output.addContactPoint(normalOnA,pointOnA,depth);
00052                 } else
00053                 {
00054                         output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth);
00055                 }
00056         }
00057 
00058 }
00059 
00060 #define MAX_OVERLAP btScalar(0.)
00061 
00062 
00063 
00064 // See also geometrictools.com
00065 // Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv
00066 btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest);
00067 
00068 btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) {
00069         btVector3 diff = p - from;
00070         btVector3 v = to - from;
00071         btScalar t = v.dot(diff);
00072         
00073         if (t > 0) {
00074                 btScalar dotVV = v.dot(v);
00075                 if (t < dotVV) {
00076                         t /= dotVV;
00077                         diff -= t*v;
00078                 } else {
00079                         t = 1;
00080                         diff -= v;
00081                 }
00082         } else
00083                 t = 0;
00084 
00085         nearest = from + t*v;
00086         return diff.dot(diff);  
00087 }
00088 
00089 bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal)  {
00090         btVector3 lp(p);
00091         btVector3 lnormal(normal);
00092         
00093         return pointInTriangle(vertices, lnormal, &lp);
00094 }
00095 
00097 bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact, btScalar contactBreakingThreshold)
00098 {
00099 
00100         const btVector3* vertices = &m_triangle->getVertexPtr(0);
00101         const btVector3& c = sphereCenter;
00102         btScalar r = m_sphere->getRadius();
00103 
00104         btVector3 delta (0,0,0);
00105 
00106         btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]);
00107         normal.normalize();
00108         btVector3 p1ToCentre = c - vertices[0];
00109         btScalar distanceFromPlane = p1ToCentre.dot(normal);
00110 
00111         if (distanceFromPlane < btScalar(0.))
00112         {
00113                 //triangle facing the other way
00114         
00115                 distanceFromPlane *= btScalar(-1.);
00116                 normal *= btScalar(-1.);
00117         }
00118 
00119         btScalar contactMargin = contactBreakingThreshold;
00120         bool isInsideContactPlane = distanceFromPlane < r + contactMargin;
00121         bool isInsideShellPlane = distanceFromPlane < r;
00122         
00123         btScalar deltaDotNormal = delta.dot(normal);
00124         if (!isInsideShellPlane && deltaDotNormal >= btScalar(0.0))
00125                 return false;
00126 
00127         // Check for contact / intersection
00128         bool hasContact = false;
00129         btVector3 contactPoint;
00130         if (isInsideContactPlane) {
00131                 if (facecontains(c,vertices,normal)) {
00132                         // Inside the contact wedge - touches a point on the shell plane
00133                         hasContact = true;
00134                         contactPoint = c - normal*distanceFromPlane;
00135                 } else {
00136                         // Could be inside one of the contact capsules
00137                         btScalar contactCapsuleRadiusSqr = (r + contactMargin) * (r + contactMargin);
00138                         btVector3 nearestOnEdge;
00139                         for (int i = 0; i < m_triangle->getNumEdges(); i++) {
00140                                 
00141                                 btVector3 pa;
00142                                 btVector3 pb;
00143                                 
00144                                 m_triangle->getEdge(i,pa,pb);
00145 
00146                                 btScalar distanceSqr = SegmentSqrDistance(pa,pb,c, nearestOnEdge);
00147                                 if (distanceSqr < contactCapsuleRadiusSqr) {
00148                                         // Yep, we're inside a capsule
00149                                         hasContact = true;
00150                                         contactPoint = nearestOnEdge;
00151                                 }
00152                                 
00153                         }
00154                 }
00155         }
00156 
00157         if (hasContact) {
00158                 btVector3 contactToCentre = c - contactPoint;
00159                 btScalar distanceSqr = contactToCentre.length2();
00160                 if (distanceSqr < (r - MAX_OVERLAP)*(r - MAX_OVERLAP)) {
00161                         btScalar distance = btSqrt(distanceSqr);
00162                         resultNormal = contactToCentre;
00163                         resultNormal.normalize();
00164                         point = contactPoint;
00165                         depth = -(r-distance);
00166                         return true;
00167                 }
00168 
00169                 if (delta.dot(contactToCentre) >= btScalar(0.0)) 
00170                         return false;
00171                 
00172                 // Moving towards the contact point -> collision
00173                 point = contactPoint;
00174                 timeOfImpact = btScalar(0.0);
00175                 return true;
00176         }
00177         
00178         return false;
00179 }
00180 
00181 
00182 bool SphereTriangleDetector::pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p )
00183 {
00184         const btVector3* p1 = &vertices[0];
00185         const btVector3* p2 = &vertices[1];
00186         const btVector3* p3 = &vertices[2];
00187 
00188         btVector3 edge1( *p2 - *p1 );
00189         btVector3 edge2( *p3 - *p2 );
00190         btVector3 edge3( *p1 - *p3 );
00191 
00192         btVector3 p1_to_p( *p - *p1 );
00193         btVector3 p2_to_p( *p - *p2 );
00194         btVector3 p3_to_p( *p - *p3 );
00195 
00196         btVector3 edge1_normal( edge1.cross(normal));
00197         btVector3 edge2_normal( edge2.cross(normal));
00198         btVector3 edge3_normal( edge3.cross(normal));
00199         
00200         btScalar r1, r2, r3;
00201         r1 = edge1_normal.dot( p1_to_p );
00202         r2 = edge2_normal.dot( p2_to_p );
00203         r3 = edge3_normal.dot( p3_to_p );
00204         if ( ( r1 > 0 && r2 > 0 && r3 > 0 ) ||
00205              ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) )
00206                 return true;
00207         return false;
00208 
00209 }

Generated on Mon Feb 15 22:17:08 2010 for Bullet Collision Detection & Physics Library by  doxygen 1.6.1