par_sprune.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // SPRUNE :: https://github.com/prideout/par
  2. // Sweep and Prune library for detecting axis-aligned box collisions in 2D.
  3. //
  4. // In addition to the comment block above each function declaration, the API
  5. // has informal documentation here:
  6. //
  7. // http://github.prideout.net/work-in-progress/
  8. //
  9. // The MIT License
  10. // Copyright (c) 2015 Philip Rideout
  11. #ifndef PAR_SPRUNE_H
  12. #define PAR_SPRUNE_H
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16. #include <stdint.h>
  17. #include <stdbool.h>
  18. #ifndef PAR_SPRUNE_INT
  19. #define PAR_SPRUNE_INT int32_t
  20. #endif
  21. #ifndef PAR_SPRUNE_FLT
  22. #define PAR_SPRUNE_FLT float
  23. #endif
  24. // -----------------------------------------------------------------------------
  25. // BEGIN PUBLIC API
  26. // -----------------------------------------------------------------------------
  27. typedef struct {
  28. PAR_SPRUNE_INT const* const collision_pairs; // list of two-tuples
  29. PAR_SPRUNE_INT const ncollision_pairs; // number of two-tuples
  30. PAR_SPRUNE_INT const* const culled; // filled by par_sprune_cull
  31. PAR_SPRUNE_INT const nculled; // set by par_sprune_cull
  32. } par_sprune_context;
  33. void par_sprune_free_context(par_sprune_context* context);
  34. // Takes an array of 4-tuples (minx miny maxx maxy) and performs SaP. Populates
  35. // "collision_pairs" and "ncollision_pairs". Optionally takes an existing
  36. // context to avoid memory churn; pass NULL for initial construction.
  37. par_sprune_context* par_sprune_overlap(PAR_SPRUNE_FLT const* aabbs,
  38. PAR_SPRUNE_INT naabbs, par_sprune_context* previous);
  39. // Reads new aabb data from the same pointer that was passed to the overlap
  40. // function and refreshes the "collision_pairs" field. Exploits temporal
  41. // coherence so it's very efficient for animation. If this returns false,
  42. // no changes to the collision set were detected.
  43. bool par_sprune_update(par_sprune_context* ctx);
  44. // Examines all collision groups and creates a culling set such that no
  45. // boxes would overlap if the culled boxes are removed. This function
  46. // populates the "culled" and "nculled" fields in par_sprune_context.
  47. // This is useful for hiding labels in GIS applications.
  48. void par_sprune_cull(par_sprune_context* context);
  49. // -----------------------------------------------------------------------------
  50. // END PUBLIC API
  51. // -----------------------------------------------------------------------------
  52. #ifdef __cplusplus
  53. }
  54. #endif
  55. #ifdef PAR_SPRUNE_IMPLEMENTATION
  56. #define PARINT PAR_SPRUNE_INT
  57. #define PARFLT PAR_SPRUNE_FLT
  58. #include <stdlib.h>
  59. #include <assert.h>
  60. #ifndef PAR_PI
  61. #define PAR_PI (3.14159265359)
  62. #define PAR_MIN(a, b) (a > b ? b : a)
  63. #define PAR_MAX(a, b) (a > b ? a : b)
  64. #define PAR_CLAMP(v, lo, hi) PAR_MAX(lo, PAR_MIN(hi, v))
  65. #define PAR_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
  66. #define PAR_SQR(a) ((a) * (a))
  67. #endif
  68. #ifndef PAR_MALLOC
  69. #define PAR_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
  70. #define PAR_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
  71. #define PAR_REALLOC(T, BUF, N) ((T*) realloc(BUF, sizeof(T) * (N)))
  72. #define PAR_FREE(BUF) free(BUF)
  73. #endif
  74. #ifndef PAR_ARRAY
  75. #define pa_free(a) ((a) ? PAR_FREE(pa___raw(a)), 0 : 0)
  76. #define pa_push(a, v) (pa___maybegrow(a, 1), (a)[pa___n(a)++] = (v))
  77. #define pa_count(a) ((a) ? pa___n(a) : 0)
  78. #define pa_add(a, n) (pa___maybegrow(a, n), pa___n(a) += (n))
  79. #define pa_last(a) ((a)[pa___n(a) - 1])
  80. #define pa_end(a) (a + pa_count(a))
  81. #define pa_clear(arr) if (arr) pa___n(arr) = 0
  82. #define pa___raw(a) ((int*) (a) -2)
  83. #define pa___m(a) pa___raw(a)[0]
  84. #define pa___n(a) pa___raw(a)[1]
  85. #define pa___needgrow(a, n) ((a) == 0 || pa___n(a) + (n) >= pa___m(a))
  86. #define pa___maybegrow(a, n) (pa___needgrow(a, (n)) ? pa___grow(a, n) : 0)
  87. #define pa___grow(a, n) (*((void**)& (a)) = pa___growf((void*) (a), (n), \
  88. sizeof(*(a))))
  89. static void* pa___growf(void* arr, int increment, int itemsize)
  90. {
  91. int dbl_cur = arr ? 2 * pa___m(arr) : 0;
  92. int min_needed = pa_count(arr) + increment;
  93. int m = dbl_cur > min_needed ? dbl_cur : min_needed;
  94. int* p = PAR_REALLOC(int, arr ? pa___raw(arr) : 0,
  95. itemsize * m / sizeof(int) + 2);
  96. if (p) {
  97. if (!arr) {
  98. p[1] = 0;
  99. }
  100. p[0] = m;
  101. return p + 2;
  102. }
  103. return (void*) (2 * sizeof(int));
  104. }
  105. #endif
  106. typedef struct {
  107. // Public:
  108. PARINT* collision_pairs;
  109. PARINT ncollision_pairs;
  110. PARINT* culled;
  111. PARINT nculled;
  112. // Private:
  113. PARFLT const* aabbs;
  114. PARINT naabbs;
  115. PARINT* sorted_indices[2];
  116. PARINT* pairs[2];
  117. } par_sprune__context;
  118. static inline int par_qsort_cmpswap(char *__restrict a, char *__restrict b,
  119. size_t w,
  120. int (*compar)(const void *_a, const void *_b,
  121. void *_arg),
  122. void *arg)
  123. {
  124. char tmp, *end = a+w;
  125. if (compar(a, b, arg) > 0) {
  126. for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
  127. return 1;
  128. }
  129. return 0;
  130. }
  131. // qsort doesn't take a context, so we have our own portable implementation.
  132. // Parameters:
  133. // base is the array to be sorted
  134. // nel is the number of elements in the array
  135. // w is the size in bytes of each element of the array
  136. // compar is the comparison function
  137. // arg is a pointer to be passed to the comparison function
  138. //
  139. static inline void par_qsort(
  140. void *base,
  141. size_t nel,
  142. size_t w,
  143. int (*compar)(const void *_a, const void *_b, void *_arg),
  144. void *arg)
  145. {
  146. char *b = (char*) base, *end = (char*) (b + nel * w);
  147. if (nel < 7) {
  148. char *pi, *pj;
  149. for (pi = b+w; pi < end; pi += w) {
  150. for (pj = pi; pj > b && par_qsort_cmpswap(pj-w, pj, w, compar, arg);
  151. pj -= w) {}
  152. }
  153. return;
  154. }
  155. char *x, *y, *xend, ch;
  156. char *pl, *pr;
  157. char *last = b+w*(nel-1), *tmp;
  158. char *l[3];
  159. l[0] = b;
  160. l[1] = b+w*(nel/2);
  161. l[2] = last;
  162. if (compar(l[0],l[1],arg) > 0) {
  163. tmp=l[0]; l[0]=l[1]; l[1]=tmp;
  164. }
  165. if (compar(l[1],l[2],arg) > 0) {
  166. tmp=l[1]; l[1]=l[2]; l[2]=tmp;
  167. if (compar(l[0],l[1],arg) > 0) {
  168. tmp=l[0]; l[0]=l[1]; l[1]=tmp;
  169. }
  170. }
  171. for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
  172. ch = *x; *x = *y; *y = ch;
  173. }
  174. pl = b;
  175. pr = last;
  176. while (pl < pr) {
  177. for (; pl < pr; pl += w) {
  178. if (par_qsort_cmpswap(pl, pr, w, compar, arg)) {
  179. pr -= w;
  180. break;
  181. }
  182. }
  183. for (; pl < pr; pr -= w) {
  184. if (par_qsort_cmpswap(pl, pr, w, compar, arg)) {
  185. pl += w;
  186. break;
  187. }
  188. }
  189. }
  190. par_qsort(b, (pl-b) / w, w, compar, arg);
  191. par_qsort(pl+w, (end - (pl+w)) / w, w, compar, arg);
  192. }
  193. void par_sprune_free_context(par_sprune_context* context)
  194. {
  195. par_sprune__context* ctx = (par_sprune__context*) context;
  196. pa_free(ctx->sorted_indices[0]);
  197. pa_free(ctx->sorted_indices[1]);
  198. pa_free(ctx->pairs[0]);
  199. pa_free(ctx->pairs[1]);
  200. pa_free(ctx->collision_pairs);
  201. PAR_FREE(ctx);
  202. }
  203. static void par_sprune__remove(PARINT* arr, PARINT val)
  204. {
  205. int i = pa_count(arr) - 1;
  206. for (; i >= 0; i--) {
  207. if (arr[i] == val) {
  208. break;
  209. }
  210. }
  211. assert(i >= 0);
  212. for (++i; i < pa_count(arr); i++) {
  213. PAR_SWAP(PARINT, arr[i - 1], arr[i]);
  214. }
  215. pa___n(arr)--;
  216. }
  217. typedef struct {
  218. PARFLT const* aabbs;
  219. } par__sprune_sorter;
  220. int par__cmpinds(const void* pa, const void* pb, void* psorter)
  221. {
  222. PARINT a = *((const PARINT*) pa);
  223. PARINT b = *((const PARINT*) pb);
  224. par__sprune_sorter* sorter = (par__sprune_sorter*) psorter;
  225. PARFLT const* aabbs = sorter->aabbs;
  226. PARFLT vala = aabbs[a];
  227. PARFLT valb = aabbs[b];
  228. if (vala > valb) return 1;
  229. if (vala < valb) return -1;
  230. if (a > b) return 1;
  231. if (a < b) return -1;
  232. return 0;
  233. }
  234. int par__cmppairs(const void* pa, const void* pb, void* unused)
  235. {
  236. PARINT a = *((const PARINT*) pa);
  237. PARINT b = *((const PARINT*) pb);
  238. if (a > b) return 1;
  239. if (a < b) return -1;
  240. a = *(1 + (const PARINT*) pa);
  241. b = *(1 + (const PARINT*) pb);
  242. if (a > b) return 1;
  243. if (a < b) return -1;
  244. return 0;
  245. }
  246. int par__cmpfind(const void* pa, const void* pb)
  247. {
  248. PARINT a = *((const PARINT*) pa);
  249. PARINT b = *((const PARINT*) pb);
  250. if (a > b) return 1;
  251. if (a < b) return -1;
  252. a = *(1 + (const PARINT*) pa);
  253. b = *(1 + (const PARINT*) pb);
  254. if (a > b) return 1;
  255. if (a < b) return -1;
  256. return 0;
  257. }
  258. par_sprune_context* par_sprune_overlap(PARFLT const* aabbs, PARINT naabbs,
  259. par_sprune_context* previous)
  260. {
  261. par_sprune__context* ctx = (par_sprune__context*) previous;
  262. if (!ctx) {
  263. ctx = PAR_CALLOC(par_sprune__context, 1);
  264. }
  265. ctx->aabbs = aabbs;
  266. ctx->naabbs = naabbs;
  267. for (int axis = 0; axis < 2; axis++) {
  268. pa_clear(ctx->sorted_indices[axis]);
  269. pa_add(ctx->sorted_indices[axis], naabbs * 2);
  270. pa_clear(ctx->pairs[axis]);
  271. }
  272. for (PARINT i = 0; i < naabbs; i++) {
  273. ctx->sorted_indices[0][i * 2 + 0] = i * 4 + 0;
  274. ctx->sorted_indices[1][i * 2 + 0] = i * 4 + 1;
  275. ctx->sorted_indices[0][i * 2 + 1] = i * 4 + 2;
  276. ctx->sorted_indices[1][i * 2 + 1] = i * 4 + 3;
  277. }
  278. par__sprune_sorter sorter;
  279. sorter.aabbs = ctx->aabbs;
  280. PARINT* active = 0;
  281. // Sweep a plane first across the X-axis, then down through the Y-axis.
  282. for (int axis = 0; axis < 2; axis++) {
  283. PARINT** pairs = &ctx->pairs[axis];
  284. PARINT* indices = ctx->sorted_indices[axis];
  285. par_qsort(indices, naabbs * 2, sizeof(PARINT), par__cmpinds, &sorter);
  286. pa_clear(active);
  287. for (PARINT i = 0; i < naabbs * 2; i++) {
  288. PARINT fltindex = indices[i];
  289. PARINT boxindex = fltindex / 4;
  290. bool ismin = ((fltindex - axis) % 4) == 0;
  291. if (ismin) {
  292. for (int j = 0; j < pa_count(active); j++) {
  293. pa_push(*pairs, active[j]);
  294. pa_push(*pairs, boxindex);
  295. pa_push(*pairs, boxindex);
  296. pa_push(*pairs, active[j]);
  297. }
  298. pa_push(active, boxindex);
  299. } else {
  300. par_sprune__remove(active, boxindex);
  301. }
  302. }
  303. }
  304. // Sort the Y-axis collision pairs to make it easier to intersect it
  305. // with the set of X-axis collision pairs. We also sort the X-axis
  306. // pairs because it's required for subsequent calls to par_sprune_update.
  307. PARINT* xpairs = ctx->pairs[0];
  308. PARINT* ypairs = ctx->pairs[1];
  309. int nxpairs = pa_count(xpairs) / 2;
  310. int nypairs = pa_count(ypairs) / 2;
  311. int pairsize = 2 * sizeof(PARINT);
  312. pa_free(active);
  313. par_qsort(xpairs, nxpairs, pairsize, par__cmppairs, 0);
  314. par_qsort(ypairs, nypairs, pairsize, par__cmppairs, 0);
  315. pa_clear(ctx->collision_pairs);
  316. // Find the intersection of X-axis overlaps and Y-axis overlaps.
  317. for (int i = 0; i < pa_count(xpairs); i += 2) {
  318. PARINT* key = xpairs + i;
  319. if (key[1] < key[0]) {
  320. continue;
  321. }
  322. void* found = bsearch(key, ypairs, nypairs, pairsize, par__cmpfind);
  323. if (found) {
  324. pa_push(ctx->collision_pairs, key[0]);
  325. pa_push(ctx->collision_pairs, key[1]);
  326. }
  327. }
  328. ctx->ncollision_pairs = pa_count(ctx->collision_pairs) / 2;
  329. return (par_sprune_context*) ctx;
  330. }
  331. void par_sprune__insert_pair(PARINT** pairs, PARINT a, PARINT b)
  332. {
  333. PARINT key[2] = {a, b};
  334. int npairs = pa_count(*pairs) / 2;
  335. int pairsize = 2 * sizeof(PARINT);
  336. void* found = bsearch(key, *pairs, npairs, pairsize, par__cmpfind);
  337. if (found) {
  338. puts("Does this ever get hit? If not, remove the bsearch");
  339. return;
  340. }
  341. pa_push(*pairs, a);
  342. pa_push(*pairs, b);
  343. pa_push(*pairs, b);
  344. pa_push(*pairs, a);
  345. // TODO insertion sort here
  346. }
  347. void par_sprune__remove_pair(PARINT** pairs, PARINT a, PARINT b)
  348. {
  349. // TODO March two cursors through...
  350. // Start Swapping when encountering AB or BA
  351. }
  352. bool par_sprune_update(par_sprune_context* context)
  353. {
  354. par_sprune__context* ctx = (par_sprune__context*) context;
  355. PARINT naabbs = ctx->naabbs;
  356. PARFLT const* aabbs = ctx->aabbs;
  357. // Since the intervals are "almost sorted" (temporal coherence), use
  358. // a simple insertion sort rather than quicksort.
  359. bool dirty = false;
  360. for (int axis = 0; axis < 2; axis++) {
  361. PARINT** pairs = &ctx->pairs[axis];
  362. PARINT* indices = ctx->sorted_indices[axis];
  363. for (int i = 1; i < naabbs * 2; i++) {
  364. int j = i;
  365. while (j > 0) {
  366. PARFLT valj = aabbs[indices[j]];
  367. PARFLT valprev = aabbs[indices[j - 1]];
  368. if (valprev <= valj) {
  369. break;
  370. }
  371. PARINT fltindexj = indices[j];
  372. PARINT boxindexj = fltindexj / 4;
  373. bool isminj = ((fltindexj - axis) % 4) == 0;
  374. PARINT fltindexjm1 = indices[j - 1];
  375. PARINT boxindexjm1 = fltindexjm1 / 4;
  376. bool isminjm1 = ((fltindexjm1 - axis) % 4) == 0;
  377. if (isminj && !isminjm1){
  378. par_sprune__insert_pair(pairs, boxindexj, boxindexjm1);
  379. dirty = true;
  380. } else if (!isminj && isminjm1){
  381. par_sprune__remove_pair(pairs, boxindexj, boxindexjm1);
  382. dirty = true;
  383. }
  384. PAR_SWAP(PARINT, indices[j], indices[j - 1]);
  385. j--;
  386. }
  387. }
  388. }
  389. PARINT* xpairs = ctx->pairs[0];
  390. PARINT* ypairs = ctx->pairs[1];
  391. int nypairs = pa_count(ypairs) / 2;
  392. int pairsize = 2 * sizeof(PARINT);
  393. pa_clear(ctx->collision_pairs);
  394. // Find the intersection of X-axis overlaps and Y-axis overlaps.
  395. for (int i = 0; i < pa_count(xpairs); i += 2) {
  396. PARINT* key = xpairs + i;
  397. if (key[1] < key[0]) {
  398. continue;
  399. }
  400. void* found = bsearch(key, ypairs, nypairs, pairsize, par__cmpfind);
  401. if (found) {
  402. pa_push(ctx->collision_pairs, key[0]);
  403. pa_push(ctx->collision_pairs, key[1]);
  404. }
  405. }
  406. ctx->ncollision_pairs = pa_count(ctx->collision_pairs) / 2;
  407. return dirty;
  408. }
  409. #undef PARINT
  410. #undef PARFLT
  411. #endif // PAR_SPRUNE_IMPLEMENTATION
  412. #endif // PAR_SPRUNE_H