2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
17 #include "btPersistentManifold.h"
18 #include "LinearMath/btTransform.h"
21 btScalar gContactBreakingThreshold = btScalar(0.02);
22 ContactDestroyedCallback gContactDestroyedCallback = 0;
23 ContactProcessedCallback gContactProcessedCallback = 0;
24 ///gContactCalcArea3Points will approximate the convex hull area using 3 points
25 ///when setting it to false, it will use 4 points to compute the area: it is more accurate but slower
26 bool gContactCalcArea3Points = true;
29 btPersistentManifold::btPersistentManifold()
30 :btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE),
41 #ifdef DEBUG_PERSISTENCY
43 void btPersistentManifold::DebugPersistency()
46 printf("DebugPersistency : numPoints %d\n",m_cachedPoints);
47 for (i=0;i<m_cachedPoints;i++)
49 printf("m_pointCache[%d].m_userPersistentData = %x\n",i,m_pointCache[i].m_userPersistentData);
52 #endif //DEBUG_PERSISTENCY
54 void btPersistentManifold::clearUserCache(btManifoldPoint& pt)
57 void* oldPtr = pt.m_userPersistentData;
60 #ifdef DEBUG_PERSISTENCY
63 for (i=0;i<m_cachedPoints;i++)
65 if (m_pointCache[i].m_userPersistentData == oldPtr)
69 printf("error in clearUserCache\n");
72 btAssert(occurance<=0);
73 #endif //DEBUG_PERSISTENCY
75 if (pt.m_userPersistentData && gContactDestroyedCallback)
77 (*gContactDestroyedCallback)(pt.m_userPersistentData);
78 pt.m_userPersistentData = 0;
81 #ifdef DEBUG_PERSISTENCY
89 static inline btScalar calcArea4Points(const btVector3 &p0,const btVector3 &p1,const btVector3 &p2,const btVector3 &p3)
91 // It calculates possible 3 area constructed from random 4 points and returns the biggest one.
101 //todo: Following 3 cross production can be easily optimized by SIMD.
102 btVector3 tmp0 = a[0].cross(b[0]);
103 btVector3 tmp1 = a[1].cross(b[1]);
104 btVector3 tmp2 = a[2].cross(b[2]);
106 return btMax(btMax(tmp0.length2(),tmp1.length2()),tmp2.length2());
109 int btPersistentManifold::sortCachedPoints(const btManifoldPoint& pt)
111 //calculate 4 possible cases areas, and take biggest area
112 //also need to keep 'deepest'
114 int maxPenetrationIndex = -1;
115 #define KEEP_DEEPEST_POINT 1
116 #ifdef KEEP_DEEPEST_POINT
117 btScalar maxPenetration = pt.getDistance();
118 for (int i=0;i<4;i++)
120 if (m_pointCache[i].getDistance() < maxPenetration)
122 maxPenetrationIndex = i;
123 maxPenetration = m_pointCache[i].getDistance();
126 #endif //KEEP_DEEPEST_POINT
128 btScalar res0(btScalar(0.)),res1(btScalar(0.)),res2(btScalar(0.)),res3(btScalar(0.));
130 if (gContactCalcArea3Points)
132 if (maxPenetrationIndex != 0)
134 btVector3 a0 = pt.m_localPointA-m_pointCache[1].m_localPointA;
135 btVector3 b0 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA;
136 btVector3 cross = a0.cross(b0);
137 res0 = cross.length2();
139 if (maxPenetrationIndex != 1)
141 btVector3 a1 = pt.m_localPointA-m_pointCache[0].m_localPointA;
142 btVector3 b1 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA;
143 btVector3 cross = a1.cross(b1);
144 res1 = cross.length2();
147 if (maxPenetrationIndex != 2)
149 btVector3 a2 = pt.m_localPointA-m_pointCache[0].m_localPointA;
150 btVector3 b2 = m_pointCache[3].m_localPointA-m_pointCache[1].m_localPointA;
151 btVector3 cross = a2.cross(b2);
152 res2 = cross.length2();
155 if (maxPenetrationIndex != 3)
157 btVector3 a3 = pt.m_localPointA-m_pointCache[0].m_localPointA;
158 btVector3 b3 = m_pointCache[2].m_localPointA-m_pointCache[1].m_localPointA;
159 btVector3 cross = a3.cross(b3);
160 res3 = cross.length2();
165 if(maxPenetrationIndex != 0) {
166 res0 = calcArea4Points(pt.m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA);
169 if(maxPenetrationIndex != 1) {
170 res1 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA);
173 if(maxPenetrationIndex != 2) {
174 res2 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[3].m_localPointA);
177 if(maxPenetrationIndex != 3) {
178 res3 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA);
181 btVector4 maxvec(res0,res1,res2,res3);
182 int biggestarea = maxvec.closestAxis4();
188 int btPersistentManifold::getCacheEntry(const btManifoldPoint& newPoint) const
190 btScalar shortestDist = getContactBreakingThreshold() * getContactBreakingThreshold();
191 int size = getNumContacts();
192 int nearestPoint = -1;
193 for( int i = 0; i < size; i++ )
195 const btManifoldPoint &mp = m_pointCache[i];
197 btVector3 diffA = mp.m_localPointA- newPoint.m_localPointA;
198 const btScalar distToManiPoint = diffA.dot(diffA);
199 if( distToManiPoint < shortestDist )
201 shortestDist = distToManiPoint;
208 int btPersistentManifold::addManifoldPoint(const btManifoldPoint& newPoint, bool isPredictive)
212 btAssert(validContactDistance(newPoint));
215 int insertIndex = getNumContacts();
216 if (insertIndex == MANIFOLD_CACHE_SIZE)
218 #if MANIFOLD_CACHE_SIZE >= 4
219 //sort cache so best points come first, based on area
220 insertIndex = sortCachedPoints(newPoint);
224 clearUserCache(m_pointCache[insertIndex]);
235 btAssert(m_pointCache[insertIndex].m_userPersistentData==0);
236 m_pointCache[insertIndex] = newPoint;
240 btScalar btPersistentManifold::getContactBreakingThreshold() const
242 return m_contactBreakingThreshold;
247 void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btTransform& trB)
250 #ifdef DEBUG_PERSISTENCY
251 printf("refreshContactPoints posA = (%f,%f,%f) posB = (%f,%f,%f)\n",
252 trA.getOrigin().getX(),
253 trA.getOrigin().getY(),
254 trA.getOrigin().getZ(),
255 trB.getOrigin().getX(),
256 trB.getOrigin().getY(),
257 trB.getOrigin().getZ());
258 #endif //DEBUG_PERSISTENCY
259 /// first refresh worldspace positions and distance
260 for (i=getNumContacts()-1;i>=0;i--)
262 btManifoldPoint &manifoldPoint = m_pointCache[i];
263 manifoldPoint.m_positionWorldOnA = trA( manifoldPoint.m_localPointA );
264 manifoldPoint.m_positionWorldOnB = trB( manifoldPoint.m_localPointB );
265 manifoldPoint.m_distance1 = (manifoldPoint.m_positionWorldOnA - manifoldPoint.m_positionWorldOnB).dot(manifoldPoint.m_normalWorldOnB);
266 manifoldPoint.m_lifeTime++;
271 btVector3 projectedDifference,projectedPoint;
272 for (i=getNumContacts()-1;i>=0;i--)
275 btManifoldPoint &manifoldPoint = m_pointCache[i];
276 //contact becomes invalid when signed distance exceeds margin (projected on contactnormal direction)
277 if (!validContactDistance(manifoldPoint))
279 removeContactPoint(i);
282 //contact also becomes invalid when relative movement orthogonal to normal exceeds margin
283 projectedPoint = manifoldPoint.m_positionWorldOnA - manifoldPoint.m_normalWorldOnB * manifoldPoint.m_distance1;
284 projectedDifference = manifoldPoint.m_positionWorldOnB - projectedPoint;
285 distance2d = projectedDifference.dot(projectedDifference);
286 if (distance2d > getContactBreakingThreshold()*getContactBreakingThreshold() )
288 removeContactPoint(i);
291 //contact point processed callback
292 if (gContactProcessedCallback)
293 (*gContactProcessedCallback)(manifoldPoint,(void*)m_body0,(void*)m_body1);
297 #ifdef DEBUG_PERSISTENCY