Bullet Collision Detection & Physics Library
btSimulationIslandManager.cpp
Go to the documentation of this file.
1 
2 /*
3 Bullet Continuous Collision Detection and Physics Library
4 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
5 
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it freely,
10 subject to the following restrictions:
11 
12 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.
13 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
14 3. This notice may not be removed or altered from any source distribution.
15 */
16 
17 
18 #include "LinearMath/btScalar.h"
24 
25 //#include <stdio.h>
26 #include "LinearMath/btQuickprof.h"
27 
29 m_splitIslands(true)
30 {
31 }
32 
34 {
35 }
36 
37 
39 {
40  m_unionFind.reset(n);
41 }
42 
43 
45 {
46 
47  {
48  btOverlappingPairCache* pairCachePtr = colWorld->getPairCache();
49  const int numOverlappingPairs = pairCachePtr->getNumOverlappingPairs();
50  if (numOverlappingPairs)
51  {
52  btBroadphasePair* pairPtr = pairCachePtr->getOverlappingPairArrayPtr();
53 
54  for (int i=0;i<numOverlappingPairs;i++)
55  {
56  const btBroadphasePair& collisionPair = pairPtr[i];
57  btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
58  btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
59 
60  if (((colObj0) && ((colObj0)->mergesSimulationIslands())) &&
61  ((colObj1) && ((colObj1)->mergesSimulationIslands())))
62  {
63 
64  m_unionFind.unite((colObj0)->getIslandTag(),
65  (colObj1)->getIslandTag());
66  }
67  }
68  }
69  }
70 }
71 
72 #ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
74 {
75 
76  // put the index into m_controllers into m_tag
77  int index = 0;
78  {
79 
80  int i;
81  for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
82  {
83  btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
84  //Adding filtering here
85  if (!collisionObject->isStaticOrKinematicObject())
86  {
87  collisionObject->setIslandTag(index++);
88  }
89  collisionObject->setCompanionId(-1);
90  collisionObject->setHitFraction(btScalar(1.));
91  }
92  }
93  // do the union find
94 
95  initUnionFind( index );
96 
97  findUnions(dispatcher,colWorld);
98 }
99 
101 {
102  // put the islandId ('find' value) into m_tag
103  {
104  int index = 0;
105  int i;
106  for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
107  {
108  btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
109  if (!collisionObject->isStaticOrKinematicObject())
110  {
111  collisionObject->setIslandTag( m_unionFind.find(index) );
112  //Set the correct object offset in Collision Object Array
113  m_unionFind.getElement(index).m_sz = i;
114  collisionObject->setCompanionId(-1);
115  index++;
116  } else
117  {
118  collisionObject->setIslandTag(-1);
119  collisionObject->setCompanionId(-2);
120  }
121  }
122  }
123 }
124 
125 
126 #else //STATIC_SIMULATION_ISLAND_OPTIMIZATION
128 {
129 
130  initUnionFind( int (colWorld->getCollisionObjectArray().size()));
131 
132  // put the index into m_controllers into m_tag
133  {
134 
135  int index = 0;
136  int i;
137  for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
138  {
139  btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
140  collisionObject->setIslandTag(index);
141  collisionObject->setCompanionId(-1);
142  collisionObject->setHitFraction(btScalar(1.));
143  index++;
144 
145  }
146  }
147  // do the union find
148 
149  findUnions(dispatcher,colWorld);
150 }
151 
153 {
154  // put the islandId ('find' value) into m_tag
155  {
156 
157 
158  int index = 0;
159  int i;
160  for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
161  {
162  btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
163  if (!collisionObject->isStaticOrKinematicObject())
164  {
165  collisionObject->setIslandTag( m_unionFind.find(index) );
166  collisionObject->setCompanionId(-1);
167  } else
168  {
169  collisionObject->setIslandTag(-1);
170  collisionObject->setCompanionId(-2);
171  }
172  index++;
173  }
174  }
175 }
176 
177 #endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
178 
179 inline int getIslandId(const btPersistentManifold* lhs)
180 {
181  int islandId;
182  const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0());
183  const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1());
184  islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag();
185  return islandId;
186 
187 }
188 
189 
190 
193 {
194  public:
195 
196  SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs ) const
197  {
198  return getIslandId(lhs) < getIslandId(rhs);
199  }
200 };
201 
203 {
204 public:
205 
206  SIMD_FORCE_INLINE bool operator() (const btPersistentManifold* lhs, const btPersistentManifold* rhs) const
207  {
208  return (
209  (getIslandId(lhs) < getIslandId(rhs))
211  ||((getIslandId(lhs) == getIslandId(rhs)) && (lhs->getBody0()->getBroadphaseHandle()->m_uniqueId == rhs->getBody0()->getBroadphaseHandle()->m_uniqueId) &&
213  );
214 
215  }
216 };
217 
218 
220 {
221 
222  BT_PROFILE("islandUnionFindAndQuickSort");
223 
224  btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
225 
227 
228  //we are going to sort the unionfind array, and store the element id in the size
229  //afterwards, we clean unionfind, to make sure no-one uses it anymore
230 
232  int numElem = getUnionFind().getNumElements();
233 
234  int endIslandIndex=1;
235  int startIslandIndex;
236 
237 
238  //update the sleeping state for bodies, if all are sleeping
239  for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
240  {
241  int islandId = getUnionFind().getElement(startIslandIndex).m_id;
242  for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
243  {
244  }
245 
246  //int numSleeping = 0;
247 
248  bool allSleeping = true;
249 
250  int idx;
251  for (idx=startIslandIndex;idx<endIslandIndex;idx++)
252  {
253  int i = getUnionFind().getElement(idx).m_sz;
254 
255  btCollisionObject* colObj0 = collisionObjects[i];
256  if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
257  {
258 // printf("error in island management\n");
259  }
260 
261  btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
262  if (colObj0->getIslandTag() == islandId)
263  {
264  if (colObj0->getActivationState()== ACTIVE_TAG ||
266  {
267  allSleeping = false;
268  break;
269  }
270  }
271  }
272 
273 
274  if (allSleeping)
275  {
276  int idx;
277  for (idx=startIslandIndex;idx<endIslandIndex;idx++)
278  {
279  int i = getUnionFind().getElement(idx).m_sz;
280  btCollisionObject* colObj0 = collisionObjects[i];
281  if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
282  {
283 // printf("error in island management\n");
284  }
285 
286  btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
287 
288  if (colObj0->getIslandTag() == islandId)
289  {
291  }
292  }
293  } else
294  {
295 
296  int idx;
297  for (idx=startIslandIndex;idx<endIslandIndex;idx++)
298  {
299  int i = getUnionFind().getElement(idx).m_sz;
300 
301  btCollisionObject* colObj0 = collisionObjects[i];
302  if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
303  {
304 // printf("error in island management\n");
305  }
306 
307  btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
308 
309  if (colObj0->getIslandTag() == islandId)
310  {
311  if ( colObj0->getActivationState() == ISLAND_SLEEPING)
312  {
314  colObj0->setDeactivationTime(0.f);
315  }
316  }
317  }
318  }
319  }
320 
321 
322  int i;
323  int maxNumManifolds = dispatcher->getNumManifolds();
324 
325 //#define SPLIT_ISLANDS 1
326 //#ifdef SPLIT_ISLANDS
327 
328 
329 //#endif //SPLIT_ISLANDS
330 
331 
332  for (i=0;i<maxNumManifolds ;i++)
333  {
334  btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
335  if (collisionWorld->getDispatchInfo().m_deterministicOverlappingPairs)
336  {
337  if (manifold->getNumContacts() == 0)
338  continue;
339  }
340 
341  const btCollisionObject* colObj0 = static_cast<const btCollisionObject*>(manifold->getBody0());
342  const btCollisionObject* colObj1 = static_cast<const btCollisionObject*>(manifold->getBody1());
343 
345  if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) ||
346  ((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING))
347  {
348 
349  //kinematic objects don't merge islands, but wake up all connected objects
350  if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING)
351  {
352  if (colObj0->hasContactResponse())
353  colObj1->activate();
354  }
355  if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING)
356  {
357  if (colObj1->hasContactResponse())
358  colObj0->activate();
359  }
360  if(m_splitIslands)
361  {
362  //filtering for response
363  if (dispatcher->needsResponse(colObj0,colObj1))
364  m_islandmanifold.push_back(manifold);
365  }
366  }
367  }
368 }
369 
370 
371 
374 {
375  btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
376 
377  buildIslands(dispatcher,collisionWorld);
378 
379  int endIslandIndex=1;
380  int startIslandIndex;
381  int numElem = getUnionFind().getNumElements();
382 
383  BT_PROFILE("processIslands");
384 
385  if(!m_splitIslands)
386  {
387  btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer();
388  int maxNumManifolds = dispatcher->getNumManifolds();
389  callback->processIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1);
390  }
391  else
392  {
393  // Sort manifolds, based on islands
394  // Sort the vector using predicate and std::sort
395  //std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate);
396 
397  int numManifolds = int (m_islandmanifold.size());
398 
399  //tried a radix sort, but quicksort/heapsort seems still faster
400  //@todo rewrite island management
401  //btPersistentManifoldSortPredicateDeterministic sorts contact manifolds based on islandid,
402  //but also based on object0 unique id and object1 unique id
403  if (collisionWorld->getDispatchInfo().m_deterministicOverlappingPairs)
404  {
406  } else
407  {
409  }
410 
411  //m_islandmanifold.heapSort(btPersistentManifoldSortPredicate());
412 
413  //now process all active islands (sets of manifolds for now)
414 
415  int startManifoldIndex = 0;
416  int endManifoldIndex = 1;
417 
418  //int islandId;
419 
420 
421 
422  // printf("Start Islands\n");
423 
424  //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
425  for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
426  {
427  int islandId = getUnionFind().getElement(startIslandIndex).m_id;
428 
429 
430  bool islandSleeping = true;
431 
432  for (endIslandIndex = startIslandIndex;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
433  {
434  int i = getUnionFind().getElement(endIslandIndex).m_sz;
435  btCollisionObject* colObj0 = collisionObjects[i];
436  m_islandBodies.push_back(colObj0);
437  if (colObj0->isActive())
438  islandSleeping = false;
439  }
440 
441 
442  //find the accompanying contact manifold for this islandId
443  int numIslandManifolds = 0;
444  btPersistentManifold** startManifold = 0;
445 
446  if (startManifoldIndex<numManifolds)
447  {
448  int curIslandId = getIslandId(m_islandmanifold[startManifoldIndex]);
449  if (curIslandId == islandId)
450  {
451  startManifold = &m_islandmanifold[startManifoldIndex];
452 
453  for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(m_islandmanifold[endManifoldIndex]));endManifoldIndex++)
454  {
455 
456  }
458  numIslandManifolds = endManifoldIndex-startManifoldIndex;
459  }
460 
461  }
462 
463  if (!islandSleeping)
464  {
465  callback->processIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId);
466  // printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds);
467  }
468 
469  if (numIslandManifolds)
470  {
471  startManifoldIndex = endManifoldIndex;
472  }
473 
475  }
476  } // else if(!splitIslands)
477 
478 }
#define ACTIVE_TAG
btPersistentManifold is a contact point cache, it stays persistent as long as objects are overlapping...
void push_back(const T &_Val)
void sortIslands()
this is a special operation, destroying the content of btUnionFind.
Definition: btUnionFind.cpp:64
int find(int p, int q)
Definition: btUnionFind.h:76
The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods It...
int getIslandId(const btPersistentManifold *lhs)
virtual btPersistentManifold * getManifoldByIndexInternal(int index)=0
void reset(int N)
Definition: btUnionFind.cpp:41
static void getElement(int arrayLen, const char *cur, const char *old, char *oldPtr, char *curData)
Definition: bFile.cpp:868
btAlignedObjectArray< btCollisionObject * > m_islandBodies
function object that routes calls to operator<
#define btAssert(x)
Definition: btScalar.h:131
btOverlappingPairCache * getPairCache()
btElement & getElement(int index)
Definition: btUnionFind.h:61
void buildAndProcessIslands(btDispatcher *dispatcher, btCollisionWorld *collisionWorld, IslandCallback *callback)
void setHitFraction(btScalar hitFraction)
btCollisionObjectArray & getCollisionObjectArray()
#define SIMD_FORCE_INLINE
Definition: btScalar.h:81
const btCollisionObject * getBody0() const
void buildIslands(btDispatcher *dispatcher, btCollisionWorld *colWorld)
virtual void updateActivationState(btCollisionWorld *colWorld, btDispatcher *dispatcher)
#define ISLAND_SLEEPING
bool hasContactResponse() const
The btOverlappingPairCache provides an interface for overlapping pair management (add, remove, storage), used by the btBroadphaseInterface broadphases.
void setActivationState(int newState) const
int size() const
return the number of elements in the array
btBroadphaseProxy * getBroadphaseHandle()
bool isKinematicObject() const
bool isStaticOrKinematicObject() const
btCollisionObject can be used to manage collision detection objects.
void setDeactivationTime(btScalar time)
void setCompanionId(int id)
virtual int getNumOverlappingPairs() const =0
btBroadphaseProxy * m_pProxy1
virtual btPersistentManifold ** getInternalManifoldPointer()=0
void activate(bool forceActivation=false) const
btBroadphaseProxy * m_pProxy0
virtual int getNumManifolds() const =0
#define BT_PROFILE(name)
Definition: btQuickprof.h:216
CollisionWorld is interface and container for the collision detection.
virtual void processIsland(btCollisionObject **bodies, int numBodies, class btPersistentManifold **manifolds, int numManifolds, int islandId)=0
int getIslandTag() const
btDispatcherInfo & getDispatchInfo()
#define WANTS_DEACTIVATION
void resize(int newsize, const T &fillData=T())
void setIslandTag(int tag)
virtual void storeIslandActivationState(btCollisionWorld *world)
btAlignedObjectArray< btPersistentManifold * > m_islandmanifold
virtual bool needsResponse(const btCollisionObject *body0, const btCollisionObject *body1)=0
#define DISABLE_DEACTIVATION
bool m_deterministicOverlappingPairs
Definition: btDispatcher.h:66
int getNumElements() const
Definition: btUnionFind.h:52
virtual btBroadphasePair * getOverlappingPairArrayPtr()=0
void unite(int p, int q)
Definition: btUnionFind.h:81
The btDispatcher interface class can be used in combination with broadphase to dispatch calculations ...
Definition: btDispatcher.h:77
int getActivationState() const
const btCollisionObject * getBody1() const
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:292
bool isActive() const
void quickSort(const L &CompareFunc)
void findUnions(btDispatcher *dispatcher, btCollisionWorld *colWorld)
The btBroadphasePair class contains a pair of aabb-overlapping objects.