Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp @ 2184

Last change on this file since 2184 was 2119, checked in by rgrieder, 16 years ago

Merged physics branch into physics_new branch.

  • Property svn:eol-style set to native
File size: 6.2 KB
Line 
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
16#include "LinearMath/btScalar.h"
17#include "SphereTriangleDetector.h"
18#include "BulletCollision/CollisionShapes/btTriangleShape.h"
19#include "BulletCollision/CollisionShapes/btSphereShape.h"
20
21
22SphereTriangleDetector::SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle)
23:m_sphere(sphere),
24m_triangle(triangle)
25{
26
27}
28
29void    SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
30{
31
32        (void)debugDraw;
33        const btTransform& transformA = input.m_transformA;
34        const btTransform& transformB = input.m_transformB;
35
36        btVector3 point,normal;
37        btScalar timeOfImpact = btScalar(1.);
38        btScalar depth = btScalar(0.);
39//      output.m_distance = btScalar(1e30);
40        //move sphere into triangle space
41        btTransform     sphereInTr = transformB.inverseTimes(transformA);
42
43        if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact))
44        {
45                if (swapResults)
46                {
47                        btVector3 normalOnB = transformB.getBasis()*normal;
48                        btVector3 normalOnA = -normalOnB;
49                        btVector3 pointOnA = transformB*point+normalOnB*depth;
50                        output.addContactPoint(normalOnA,pointOnA,depth);
51                } else
52                {
53                        output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth);
54                }
55        }
56
57}
58
59#define MAX_OVERLAP btScalar(0.)
60
61
62
63// See also geometrictools.com
64// Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv
65btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest);
66
67btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) {
68        btVector3 diff = p - from;
69        btVector3 v = to - from;
70        btScalar t = v.dot(diff);
71       
72        if (t > 0) {
73                btScalar dotVV = v.dot(v);
74                if (t < dotVV) {
75                        t /= dotVV;
76                        diff -= t*v;
77                } else {
78                        t = 1;
79                        diff -= v;
80                }
81        } else
82                t = 0;
83
84        nearest = from + t*v;
85        return diff.dot(diff); 
86}
87
88bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal)  {
89        btVector3 lp(p);
90        btVector3 lnormal(normal);
91       
92        return pointInTriangle(vertices, lnormal, &lp);
93}
94
95///combined discrete/continuous sphere-triangle
96bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact)
97{
98
99        const btVector3* vertices = &m_triangle->getVertexPtr(0);
100        const btVector3& c = sphereCenter;
101        btScalar r = m_sphere->getRadius();
102
103        btVector3 delta (0,0,0);
104
105        btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]);
106        normal.normalize();
107        btVector3 p1ToCentre = c - vertices[0];
108        btScalar distanceFromPlane = p1ToCentre.dot(normal);
109
110        if (distanceFromPlane < btScalar(0.))
111        {
112                //triangle facing the other way
113       
114                distanceFromPlane *= btScalar(-1.);
115                normal *= btScalar(-1.);
116        }
117
118        ///todo: move this gContactBreakingThreshold into a proper structure
119        extern btScalar gContactBreakingThreshold;
120
121        btScalar contactMargin = gContactBreakingThreshold;
122        bool isInsideContactPlane = distanceFromPlane < r + contactMargin;
123        bool isInsideShellPlane = distanceFromPlane < r;
124       
125        btScalar deltaDotNormal = delta.dot(normal);
126        if (!isInsideShellPlane && deltaDotNormal >= btScalar(0.0))
127                return false;
128
129        // Check for contact / intersection
130        bool hasContact = false;
131        btVector3 contactPoint;
132        if (isInsideContactPlane) {
133                if (facecontains(c,vertices,normal)) {
134                        // Inside the contact wedge - touches a point on the shell plane
135                        hasContact = true;
136                        contactPoint = c - normal*distanceFromPlane;
137                } else {
138                        // Could be inside one of the contact capsules
139                        btScalar contactCapsuleRadiusSqr = (r + contactMargin) * (r + contactMargin);
140                        btVector3 nearestOnEdge;
141                        for (int i = 0; i < m_triangle->getNumEdges(); i++) {
142                               
143                                btPoint3 pa;
144                                btPoint3 pb;
145                               
146                                m_triangle->getEdge(i,pa,pb);
147
148                                btScalar distanceSqr = SegmentSqrDistance(pa,pb,c, nearestOnEdge);
149                                if (distanceSqr < contactCapsuleRadiusSqr) {
150                                        // Yep, we're inside a capsule
151                                        hasContact = true;
152                                        contactPoint = nearestOnEdge;
153                                }
154                               
155                        }
156                }
157        }
158
159        if (hasContact) {
160                btVector3 contactToCentre = c - contactPoint;
161                btScalar distanceSqr = contactToCentre.length2();
162                if (distanceSqr < (r - MAX_OVERLAP)*(r - MAX_OVERLAP)) {
163                        btScalar distance = btSqrt(distanceSqr);
164                        resultNormal = contactToCentre;
165                        resultNormal.normalize();
166                        point = contactPoint;
167                        depth = -(r-distance);
168                        return true;
169                }
170
171                if (delta.dot(contactToCentre) >= btScalar(0.0)) 
172                        return false;
173               
174                // Moving towards the contact point -> collision
175                point = contactPoint;
176                timeOfImpact = btScalar(0.0);
177                return true;
178        }
179       
180        return false;
181}
182
183
184bool SphereTriangleDetector::pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p )
185{
186        const btVector3* p1 = &vertices[0];
187        const btVector3* p2 = &vertices[1];
188        const btVector3* p3 = &vertices[2];
189
190        btVector3 edge1( *p2 - *p1 );
191        btVector3 edge2( *p3 - *p2 );
192        btVector3 edge3( *p1 - *p3 );
193
194        btVector3 p1_to_p( *p - *p1 );
195        btVector3 p2_to_p( *p - *p2 );
196        btVector3 p3_to_p( *p - *p3 );
197
198        btVector3 edge1_normal( edge1.cross(normal));
199        btVector3 edge2_normal( edge2.cross(normal));
200        btVector3 edge3_normal( edge3.cross(normal));
201       
202        btScalar r1, r2, r3;
203        r1 = edge1_normal.dot( p1_to_p );
204        r2 = edge2_normal.dot( p2_to_p );
205        r3 = edge3_normal.dot( p3_to_p );
206        if ( ( r1 > 0 && r2 > 0 && r3 > 0 ) ||
207             ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) )
208                return true;
209        return false;
210
211}
Note: See TracBrowser for help on using the repository browser.