OPC_BoxPruning.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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. #include "Opcode.h"
  28. using namespace Opcode;
  29. inline_ void FindRunningIndex(udword& index, float* array, udword* sorted, int last, float max)
  30. {
  31. int First=index;
  32. while(First<=last)
  33. {
  34. index = (First+last)>>1;
  35. if(max>array[sorted[index]]) First = index+1;
  36. else last = index-1;
  37. }
  38. }
  39. // ### could be log(n) !
  40. // and maybe use cmp integers
  41. // InsertionSort has better coherence, RadixSort is better for one-shot queries.
  42. #define PRUNING_SORTER RadixSort
  43. //#define PRUNING_SORTER InsertionSort
  44. // Static for coherence
  45. static PRUNING_SORTER* gCompletePruningSorter = null;
  46. static PRUNING_SORTER* gBipartitePruningSorter0 = null;
  47. static PRUNING_SORTER* gBipartitePruningSorter1 = null;
  48. inline_ PRUNING_SORTER* GetCompletePruningSorter()
  49. {
  50. if(!gCompletePruningSorter) gCompletePruningSorter = new PRUNING_SORTER;
  51. return gCompletePruningSorter;
  52. }
  53. inline_ PRUNING_SORTER* GetBipartitePruningSorter0()
  54. {
  55. if(!gBipartitePruningSorter0) gBipartitePruningSorter0 = new PRUNING_SORTER;
  56. return gBipartitePruningSorter0;
  57. }
  58. inline_ PRUNING_SORTER* GetBipartitePruningSorter1()
  59. {
  60. if(!gBipartitePruningSorter1) gBipartitePruningSorter1 = new PRUNING_SORTER;
  61. return gBipartitePruningSorter1;
  62. }
  63. void ReleasePruningSorters()
  64. {
  65. DELETESINGLE(gBipartitePruningSorter1);
  66. DELETESINGLE(gBipartitePruningSorter0);
  67. DELETESINGLE(gCompletePruningSorter);
  68. }
  69. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. /**
  71. * Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
  72. * \param nb0 [in] number of boxes in the first set
  73. * \param array0 [in] array of boxes for the first set
  74. * \param nb1 [in] number of boxes in the second set
  75. * \param array1 [in] array of boxes for the second set
  76. * \param pairs [out] array of overlapping pairs
  77. * \param axes [in] projection order (0,2,1 is often best)
  78. * \return true if success.
  79. */
  80. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  81. bool Opcode::BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes)
  82. {
  83. // Checkings
  84. if(!nb0 || !array0 || !nb1 || !array1) return false;
  85. // Catch axes
  86. udword Axis0 = axes.mAxis0;
  87. udword Axis1 = axes.mAxis1;
  88. udword Axis2 = axes.mAxis2;
  89. // Allocate some temporary data
  90. float* MinPosList0 = new float[nb0];
  91. float* MinPosList1 = new float[nb1];
  92. // 1) Build main lists using the primary axis
  93. for(udword i=0;i<nb0;i++) MinPosList0[i] = array0[i]->GetMin(Axis0);
  94. for(udword i=0;i<nb1;i++) MinPosList1[i] = array1[i]->GetMin(Axis0);
  95. // 2) Sort the lists
  96. PRUNING_SORTER* RS0 = GetBipartitePruningSorter0();
  97. PRUNING_SORTER* RS1 = GetBipartitePruningSorter1();
  98. const udword* Sorted0 = RS0->Sort(MinPosList0, nb0).GetRanks();
  99. const udword* Sorted1 = RS1->Sort(MinPosList1, nb1).GetRanks();
  100. // 3) Prune the lists
  101. udword Index0, Index1;
  102. const udword* const LastSorted0 = &Sorted0[nb0];
  103. const udword* const LastSorted1 = &Sorted1[nb1];
  104. const udword* RunningAddress0 = Sorted0;
  105. const udword* RunningAddress1 = Sorted1;
  106. while(RunningAddress1<LastSorted1 && Sorted0<LastSorted0)
  107. {
  108. Index0 = *Sorted0++;
  109. while(RunningAddress1<LastSorted1 && MinPosList1[*RunningAddress1]<MinPosList0[Index0]) RunningAddress1++;
  110. const udword* RunningAddress2_1 = RunningAddress1;
  111. while(RunningAddress2_1<LastSorted1 && MinPosList1[Index1 = *RunningAddress2_1++]<=array0[Index0]->GetMax(Axis0))
  112. {
  113. if(array0[Index0]->Intersect(*array1[Index1], Axis1))
  114. {
  115. if(array0[Index0]->Intersect(*array1[Index1], Axis2))
  116. {
  117. pairs.AddPair(Index0, Index1);
  118. }
  119. }
  120. }
  121. }
  122. ////
  123. while(RunningAddress0<LastSorted0 && Sorted1<LastSorted1)
  124. {
  125. Index0 = *Sorted1++;
  126. while(RunningAddress0<LastSorted0 && MinPosList0[*RunningAddress0]<=MinPosList1[Index0]) RunningAddress0++;
  127. const udword* RunningAddress2_0 = RunningAddress0;
  128. while(RunningAddress2_0<LastSorted0 && MinPosList0[Index1 = *RunningAddress2_0++]<=array1[Index0]->GetMax(Axis0))
  129. {
  130. if(array0[Index1]->Intersect(*array1[Index0], Axis1))
  131. {
  132. if(array0[Index1]->Intersect(*array1[Index0], Axis2))
  133. {
  134. pairs.AddPair(Index1, Index0);
  135. }
  136. }
  137. }
  138. }
  139. DELETEARRAY(MinPosList1);
  140. DELETEARRAY(MinPosList0);
  141. return true;
  142. }
  143. #define ORIGINAL_VERSION
  144. //#define JOAKIM
  145. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146. /**
  147. * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
  148. * \param nb [in] number of boxes
  149. * \param array [in] array of boxes
  150. * \param pairs [out] array of overlapping pairs
  151. * \param axes [in] projection order (0,2,1 is often best)
  152. * \return true if success.
  153. */
  154. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. bool Opcode::CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes)
  156. {
  157. // Checkings
  158. if(!nb || !array) return false;
  159. // Catch axes
  160. udword Axis0 = axes.mAxis0;
  161. udword Axis1 = axes.mAxis1;
  162. udword Axis2 = axes.mAxis2;
  163. #ifdef ORIGINAL_VERSION
  164. // Allocate some temporary data
  165. // float* PosList = new float[nb];
  166. float* PosList = new float[nb+1];
  167. // 1) Build main list using the primary axis
  168. for(udword i=0;i<nb;i++) PosList[i] = array[i]->GetMin(Axis0);
  169. PosList[nb++] = MAX_FLOAT;
  170. // 2) Sort the list
  171. PRUNING_SORTER* RS = GetCompletePruningSorter();
  172. const udword* Sorted = RS->Sort(PosList, nb).GetRanks();
  173. // 3) Prune the list
  174. const udword* const LastSorted = &Sorted[nb];
  175. const udword* RunningAddress = Sorted;
  176. udword Index0, Index1;
  177. while(RunningAddress<LastSorted && Sorted<LastSorted)
  178. {
  179. Index0 = *Sorted++;
  180. // while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
  181. while(PosList[*RunningAddress++]<PosList[Index0]);
  182. if(RunningAddress<LastSorted)
  183. {
  184. const udword* RunningAddress2 = RunningAddress;
  185. // while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
  186. while(PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
  187. {
  188. // if(Index0!=Index1)
  189. // {
  190. if(array[Index0]->Intersect(*array[Index1], Axis1))
  191. {
  192. if(array[Index0]->Intersect(*array[Index1], Axis2))
  193. {
  194. pairs.AddPair(Index0, Index1);
  195. }
  196. }
  197. // }
  198. }
  199. }
  200. }
  201. DELETEARRAY(PosList);
  202. #endif
  203. #ifdef JOAKIM
  204. // Allocate some temporary data
  205. // float* PosList = new float[nb];
  206. float* MinList = new float[nb+1];
  207. // 1) Build main list using the primary axis
  208. for(udword i=0;i<nb;i++) MinList[i] = array[i]->GetMin(Axis0);
  209. MinList[nb] = MAX_FLOAT;
  210. // 2) Sort the list
  211. PRUNING_SORTER* RS = GetCompletePruningSorter();
  212. udword* Sorted = RS->Sort(MinList, nb+1).GetRanks();
  213. // 3) Prune the list
  214. // const udword* const LastSorted = &Sorted[nb];
  215. // const udword* const LastSorted = &Sorted[nb-1];
  216. const udword* RunningAddress = Sorted;
  217. udword Index0, Index1;
  218. // while(RunningAddress<LastSorted && Sorted<LastSorted)
  219. // while(RunningAddress<LastSorted)
  220. while(RunningAddress<&Sorted[nb])
  221. // while(Sorted<LastSorted)
  222. {
  223. // Index0 = *Sorted++;
  224. Index0 = *RunningAddress++;
  225. // while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
  226. // while(PosList[*RunningAddress++]<PosList[Index0]);
  227. //RunningAddress = Sorted;
  228. // if(RunningAddress<LastSorted)
  229. {
  230. const udword* RunningAddress2 = RunningAddress;
  231. // while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
  232. // float CurrentMin = array[Index0]->GetMin(Axis0);
  233. float CurrentMax = array[Index0]->GetMax(Axis0);
  234. while(MinList[Index1 = *RunningAddress2] <= CurrentMax)
  235. // while(PosList[Index1 = *RunningAddress] <= CurrentMax)
  236. {
  237. // if(Index0!=Index1)
  238. // {
  239. if(array[Index0]->Intersect(*array[Index1], Axis1))
  240. {
  241. if(array[Index0]->Intersect(*array[Index1], Axis2))
  242. {
  243. pairs.AddPair(Index0, Index1);
  244. }
  245. }
  246. // }
  247. RunningAddress2++;
  248. // RunningAddress++;
  249. }
  250. }
  251. }
  252. DELETEARRAY(MinList);
  253. #endif
  254. return true;
  255. }
  256. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  257. // Brute-force versions are kept:
  258. // - to check the optimized versions return the correct list of intersections
  259. // - to check the speed of the optimized code against the brute-force one
  260. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  261. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. /**
  263. * Brute-force bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
  264. * \param nb0 [in] number of boxes in the first set
  265. * \param array0 [in] array of boxes for the first set
  266. * \param nb1 [in] number of boxes in the second set
  267. * \param array1 [in] array of boxes for the second set
  268. * \param pairs [out] array of overlapping pairs
  269. * \return true if success.
  270. */
  271. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. bool Opcode::BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs)
  273. {
  274. // Checkings
  275. if(!nb0 || !array0 || !nb1 || !array1) return false;
  276. // Brute-force nb0*nb1 overlap tests
  277. for(udword i=0;i<nb0;i++)
  278. {
  279. for(udword j=0;j<nb1;j++)
  280. {
  281. if(array0[i]->Intersect(*array1[j])) pairs.AddPair(i, j);
  282. }
  283. }
  284. return true;
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  287. /**
  288. * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
  289. * \param nb [in] number of boxes
  290. * \param array [in] array of boxes
  291. * \param pairs [out] array of overlapping pairs
  292. * \return true if success.
  293. */
  294. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  295. bool Opcode::BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs)
  296. {
  297. // Checkings
  298. if(!nb || !array) return false;
  299. // Brute-force n(n-1)/2 overlap tests
  300. for(udword i=0;i<nb;i++)
  301. {
  302. for(udword j=i+1;j<nb;j++)
  303. {
  304. if(array[i]->Intersect(*array[j])) pairs.AddPair(i, j);
  305. }
  306. }
  307. return true;
  308. }