OPC_BoxPruning.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /*
  3. * OPCODE - Optimized Collision Detection
  4. * Copyright (C) 2001 Pierre Terdiman
  5. * Homepage: http://www.codercorner.com/Opcode.htm
  6. */
  7. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. /**
  10. * Contains code for box pruning.
  11. * \file IceBoxPruning.cpp
  12. * \author Pierre Terdiman
  13. * \date January, 29, 2000
  14. */
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. /*
  17. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  18. You could use a complex sweep-and-prune as implemented in I-Collide.
  19. You could use a complex hashing scheme as implemented in V-Clip or recently in ODE it seems.
  20. You could use a "Recursive Dimensional Clustering" algorithm as implemented in GPG2.
  21. Or you could use this.
  22. Faster ? I don't know. Probably not. It would be a shame. But who knows ?
  23. Easier ? Definitely. Enjoy the sheer simplicity.
  24. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  25. */
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. // Precompiled Header
  28. #include "Stdafx.h"
  29. using namespace Opcode;
  30. inline_ void FindRunningIndex(udword& index, float* array, udword* sorted, int last, float max)
  31. {
  32. int First=index;
  33. while(First<=last)
  34. {
  35. index = (First+last)>>1;
  36. if(max>array[sorted[index]]) First = index+1;
  37. else last = index-1;
  38. }
  39. }
  40. // ### could be log(n) !
  41. // and maybe use cmp integers
  42. extern ThreadLocalDataProviderProc g_pfnThreadLocalDataProvider;
  43. inline_ PRUNING_SORTER* GetCompletePruningSorter()
  44. {
  45. ThreadLocalData *pThreadLocalData = g_pfnThreadLocalDataProvider();
  46. return pThreadLocalData->gCompletePruningSorter;
  47. }
  48. inline_ PRUNING_SORTER* GetBipartitePruningSorter0()
  49. {
  50. ThreadLocalData *pThreadLocalData = g_pfnThreadLocalDataProvider();
  51. return pThreadLocalData->gBipartitePruningSorter0;
  52. }
  53. inline_ PRUNING_SORTER* GetBipartitePruningSorter1()
  54. {
  55. ThreadLocalData *pThreadLocalData = g_pfnThreadLocalDataProvider();
  56. return pThreadLocalData->gBipartitePruningSorter1;
  57. }
  58. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. /**
  60. * Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
  61. * \param nb0 [in] number of boxes in the first set
  62. * \param array0 [in] array of boxes for the first set
  63. * \param nb1 [in] number of boxes in the second set
  64. * \param array1 [in] array of boxes for the second set
  65. * \param pairs [out] array of overlapping pairs
  66. * \param axes [in] projection order (0,2,1 is often best)
  67. * \return true if success.
  68. */
  69. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. bool Opcode::BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes)
  71. {
  72. // Checkings
  73. if(!nb0 || !array0 || !nb1 || !array1) return false;
  74. // Catch axes
  75. udword Axis0 = axes.mAxis0;
  76. udword Axis1 = axes.mAxis1;
  77. udword Axis2 = axes.mAxis2;
  78. // Allocate some temporary data
  79. float* MinPosList0 = new float[nb0];
  80. float* MinPosList1 = new float[nb1];
  81. // 1) Build main lists using the primary axis
  82. for(udword i=0;i<nb0;i++) MinPosList0[i] = array0[i]->GetMin(Axis0);
  83. for(udword i=0;i<nb1;i++) MinPosList1[i] = array1[i]->GetMin(Axis0);
  84. // 2) Sort the lists
  85. PRUNING_SORTER* RS0 = GetBipartitePruningSorter0();
  86. PRUNING_SORTER* RS1 = GetBipartitePruningSorter1();
  87. const udword* Sorted0 = RS0->Sort(MinPosList0, nb0).GetRanks();
  88. const udword* Sorted1 = RS1->Sort(MinPosList1, nb1).GetRanks();
  89. // 3) Prune the lists
  90. udword Index0, Index1;
  91. const udword* const LastSorted0 = &Sorted0[nb0];
  92. const udword* const LastSorted1 = &Sorted1[nb1];
  93. const udword* RunningAddress0 = Sorted0;
  94. const udword* RunningAddress1 = Sorted1;
  95. while(RunningAddress1<LastSorted1 && Sorted0<LastSorted0)
  96. {
  97. Index0 = *Sorted0++;
  98. while(RunningAddress1<LastSorted1 && MinPosList1[*RunningAddress1]<MinPosList0[Index0]) RunningAddress1++;
  99. const udword* RunningAddress2_1 = RunningAddress1;
  100. while(RunningAddress2_1<LastSorted1 && MinPosList1[Index1 = *RunningAddress2_1++]<=array0[Index0]->GetMax(Axis0))
  101. {
  102. if(array0[Index0]->Intersect(*array1[Index1], Axis1))
  103. {
  104. if(array0[Index0]->Intersect(*array1[Index1], Axis2))
  105. {
  106. pairs.AddPair(Index0, Index1);
  107. }
  108. }
  109. }
  110. }
  111. ////
  112. while(RunningAddress0<LastSorted0 && Sorted1<LastSorted1)
  113. {
  114. Index0 = *Sorted1++;
  115. while(RunningAddress0<LastSorted0 && MinPosList0[*RunningAddress0]<=MinPosList1[Index0]) RunningAddress0++;
  116. const udword* RunningAddress2_0 = RunningAddress0;
  117. while(RunningAddress2_0<LastSorted0 && MinPosList0[Index1 = *RunningAddress2_0++]<=array1[Index0]->GetMax(Axis0))
  118. {
  119. if(array0[Index1]->Intersect(*array1[Index0], Axis1))
  120. {
  121. if(array0[Index1]->Intersect(*array1[Index0], Axis2))
  122. {
  123. pairs.AddPair(Index1, Index0);
  124. }
  125. }
  126. }
  127. }
  128. DELETEARRAY(MinPosList1);
  129. DELETEARRAY(MinPosList0);
  130. return true;
  131. }
  132. #define ORIGINAL_VERSION
  133. //#define JOAKIM
  134. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. /**
  136. * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
  137. * \param nb [in] number of boxes
  138. * \param array [in] array of boxes
  139. * \param pairs [out] array of overlapping pairs
  140. * \param axes [in] projection order (0,2,1 is often best)
  141. * \return true if success.
  142. */
  143. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  144. bool Opcode::CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes)
  145. {
  146. // Checkings
  147. if(!nb || !array) return false;
  148. // Catch axes
  149. udword Axis0 = axes.mAxis0;
  150. udword Axis1 = axes.mAxis1;
  151. udword Axis2 = axes.mAxis2;
  152. #ifdef ORIGINAL_VERSION
  153. // Allocate some temporary data
  154. // float* PosList = new float[nb];
  155. float* PosList = new float[nb+1];
  156. // 1) Build main list using the primary axis
  157. for(udword i=0;i<nb;i++) PosList[i] = array[i]->GetMin(Axis0);
  158. PosList[nb++] = MAX_FLOAT;
  159. // 2) Sort the list
  160. PRUNING_SORTER* RS = GetCompletePruningSorter();
  161. const udword* Sorted = RS->Sort(PosList, nb).GetRanks();
  162. // 3) Prune the list
  163. const udword* const LastSorted = &Sorted[nb];
  164. const udword* RunningAddress = Sorted;
  165. udword Index0, Index1;
  166. while(RunningAddress<LastSorted && Sorted<LastSorted)
  167. {
  168. Index0 = *Sorted++;
  169. // while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
  170. while(PosList[*RunningAddress++]<PosList[Index0]);
  171. if(RunningAddress<LastSorted)
  172. {
  173. const udword* RunningAddress2 = RunningAddress;
  174. // while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
  175. while(PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
  176. {
  177. // if(Index0!=Index1)
  178. // {
  179. if(array[Index0]->Intersect(*array[Index1], Axis1))
  180. {
  181. if(array[Index0]->Intersect(*array[Index1], Axis2))
  182. {
  183. pairs.AddPair(Index0, Index1);
  184. }
  185. }
  186. // }
  187. }
  188. }
  189. }
  190. DELETEARRAY(PosList);
  191. #endif
  192. #ifdef JOAKIM
  193. // Allocate some temporary data
  194. // float* PosList = new float[nb];
  195. float* MinList = new float[nb+1];
  196. // 1) Build main list using the primary axis
  197. for(udword i=0;i<nb;i++) MinList[i] = array[i]->GetMin(Axis0);
  198. MinList[nb] = MAX_FLOAT;
  199. // 2) Sort the list
  200. PRUNING_SORTER* RS = GetCompletePruningSorter();
  201. udword* Sorted = RS->Sort(MinList, nb+1).GetRanks();
  202. // 3) Prune the list
  203. // const udword* const LastSorted = &Sorted[nb];
  204. // const udword* const LastSorted = &Sorted[nb-1];
  205. const udword* RunningAddress = Sorted;
  206. udword Index0, Index1;
  207. // while(RunningAddress<LastSorted && Sorted<LastSorted)
  208. // while(RunningAddress<LastSorted)
  209. while(RunningAddress<&Sorted[nb])
  210. // while(Sorted<LastSorted)
  211. {
  212. // Index0 = *Sorted++;
  213. Index0 = *RunningAddress++;
  214. // while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
  215. // while(PosList[*RunningAddress++]<PosList[Index0]);
  216. //RunningAddress = Sorted;
  217. // if(RunningAddress<LastSorted)
  218. {
  219. const udword* RunningAddress2 = RunningAddress;
  220. // while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
  221. // float CurrentMin = array[Index0]->GetMin(Axis0);
  222. float CurrentMax = array[Index0]->GetMax(Axis0);
  223. while(MinList[Index1 = *RunningAddress2] <= CurrentMax)
  224. // while(PosList[Index1 = *RunningAddress] <= CurrentMax)
  225. {
  226. // if(Index0!=Index1)
  227. // {
  228. if(array[Index0]->Intersect(*array[Index1], Axis1))
  229. {
  230. if(array[Index0]->Intersect(*array[Index1], Axis2))
  231. {
  232. pairs.AddPair(Index0, Index1);
  233. }
  234. }
  235. // }
  236. RunningAddress2++;
  237. // RunningAddress++;
  238. }
  239. }
  240. }
  241. DELETEARRAY(MinList);
  242. #endif
  243. return true;
  244. }
  245. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. // Brute-force versions are kept:
  247. // - to check the optimized versions return the correct list of intersections
  248. // - to check the speed of the optimized code against the brute-force one
  249. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  250. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  251. /**
  252. * Brute-force bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
  253. * \param nb0 [in] number of boxes in the first set
  254. * \param array0 [in] array of boxes for the first set
  255. * \param nb1 [in] number of boxes in the second set
  256. * \param array1 [in] array of boxes for the second set
  257. * \param pairs [out] array of overlapping pairs
  258. * \return true if success.
  259. */
  260. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  261. bool Opcode::BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs)
  262. {
  263. // Checkings
  264. if(!nb0 || !array0 || !nb1 || !array1) return false;
  265. // Brute-force nb0*nb1 overlap tests
  266. for(udword i=0;i<nb0;i++)
  267. {
  268. for(udword j=0;j<nb1;j++)
  269. {
  270. if(array0[i]->Intersect(*array1[j])) pairs.AddPair(i, j);
  271. }
  272. }
  273. return true;
  274. }
  275. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. /**
  277. * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
  278. * \param nb [in] number of boxes
  279. * \param array [in] array of boxes
  280. * \param pairs [out] array of overlapping pairs
  281. * \return true if success.
  282. */
  283. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  284. bool Opcode::BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs)
  285. {
  286. // Checkings
  287. if(!nb || !array) return false;
  288. // Brute-force n(n-1)/2 overlap tests
  289. for(udword i=0;i<nb;i++)
  290. {
  291. for(udword j=i+1;j<nb;j++)
  292. {
  293. if(array[i]->Intersect(*array[j])) pairs.AddPair(i, j);
  294. }
  295. }
  296. return true;
  297. }