par_sprune.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // SPRUNE :: https://github.com/prideout/par
  2. // Sweep and Prune library for detecting axis-aligned box collisions in 2D.
  3. //
  4. // For an emscripten demo of this library, take a look at the following link.
  5. //
  6. // https://prideout.net/d3cpp
  7. //
  8. // The axis-aligned bounding boxes are specified by (minx, miny, maxx, maxy).
  9. // Simple usage example:
  10. //
  11. // float boxes[] = {
  12. // 0.10, 0.10, 0.30, 0.30, // box 0
  13. // 0.20, 0.20, 0.40, 0.40, // box 1
  14. // 0.60, 0.15, 0.70, 0.25, // box 2
  15. // };
  16. // int nboxes = 3;
  17. // par_sprune_context* ctx = par_sprune_overlap(boxes, nboxes, 0);
  18. // int const* pairs = ctx->collision_pairs;
  19. // for (int i = 0; i < ctx->ncollision_pairs * 2; i += 2) {
  20. // printf("box %d overlaps box %d\n", pairs[i], pairs[i + 1]);
  21. // }
  22. // par_sprune_free_context(ctx);
  23. //
  24. // Distributed under the MIT License, see bottom of file.
  25. #ifndef PAR_SPRUNE_H
  26. #define PAR_SPRUNE_H
  27. #ifdef __cplusplus
  28. extern "C" {
  29. #endif
  30. #include <stdint.h>
  31. #include <stdbool.h>
  32. #ifndef PAR_SPRUNE_INT
  33. #define PAR_SPRUNE_INT int32_t
  34. #endif
  35. #ifndef PAR_SPRUNE_FLT
  36. #define PAR_SPRUNE_FLT float
  37. #endif
  38. // -----------------------------------------------------------------------------
  39. // BEGIN PUBLIC API
  40. // -----------------------------------------------------------------------------
  41. typedef struct {
  42. PAR_SPRUNE_INT const* const collision_pairs; // list of two-tuples
  43. PAR_SPRUNE_INT const ncollision_pairs; // number of two-tuples
  44. PAR_SPRUNE_INT const* const culled; // filled by par_sprune_cull
  45. PAR_SPRUNE_INT const nculled; // set by par_sprune_cull
  46. } par_sprune_context;
  47. void par_sprune_free_context(par_sprune_context* context);
  48. // Takes an array of 4-tuples (minx miny maxx maxy) and performs SaP. Populates
  49. // "collision_pairs" and "ncollision_pairs". Optionally takes an existing
  50. // context to avoid memory churn; pass NULL for initial construction.
  51. par_sprune_context* par_sprune_overlap(PAR_SPRUNE_FLT const* aabbs,
  52. PAR_SPRUNE_INT naabbs, par_sprune_context* previous);
  53. // Reads new aabb data from the same pointer that was passed to the overlap
  54. // function and refreshes the two relevant fields. This function should
  55. // only be used when the number of aabbs remains constant. If this returns
  56. // false, no changes to the collision set were detected.
  57. bool par_sprune_update(par_sprune_context* ctx);
  58. // Examines all collision groups and creates a culling set such that no boxes
  59. // would overlap if the culled boxes are removed. When two boxes collide, the
  60. // box that occurs earlier in the list is more likely to be culled. Populates
  61. // the "culled" and "nculled" fields in par_sprune_context. This is useful for
  62. // hiding labels in GIS applications.
  63. void par_sprune_cull(par_sprune_context* context);
  64. // -----------------------------------------------------------------------------
  65. // END PUBLIC API
  66. // -----------------------------------------------------------------------------
  67. #ifdef __cplusplus
  68. }
  69. #endif
  70. #ifdef PAR_SPRUNE_IMPLEMENTATION
  71. #define PARINT PAR_SPRUNE_INT
  72. #define PARFLT PAR_SPRUNE_FLT
  73. #include <stdlib.h>
  74. #include <assert.h>
  75. #ifndef PAR_PI
  76. #define PAR_PI (3.14159265359)
  77. #define PAR_MIN(a, b) (a > b ? b : a)
  78. #define PAR_MAX(a, b) (a > b ? a : b)
  79. #define PAR_CLAMP(v, lo, hi) PAR_MAX(lo, PAR_MIN(hi, v))
  80. #define PAR_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
  81. #define PAR_SQR(a) ((a) * (a))
  82. #endif
  83. #ifndef PAR_MALLOC
  84. #define PAR_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
  85. #define PAR_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
  86. #define PAR_REALLOC(T, BUF, N) ((T*) realloc(BUF, sizeof(T) * (N)))
  87. #define PAR_FREE(BUF) free(BUF)
  88. #endif
  89. #ifndef PAR_ARRAY
  90. #define PAR_ARRAY
  91. #define pa_free(a) ((a) ? PAR_FREE(pa___raw(a)), 0 : 0)
  92. #define pa_push(a, v) (pa___maybegrow(a, (int) 1), (a)[pa___n(a)++] = (v))
  93. #define pa_count(a) ((a) ? pa___n(a) : 0)
  94. #define pa_add(a, n) (pa___maybegrow(a, (int) n), pa___n(a) += (n))
  95. #define pa_last(a) ((a)[pa___n(a) - 1])
  96. #define pa_end(a) (a + pa_count(a))
  97. #define pa_clear(arr) if (arr) pa___n(arr) = 0
  98. #define pa___raw(a) ((int*) (a) -2)
  99. #define pa___m(a) pa___raw(a)[0]
  100. #define pa___n(a) pa___raw(a)[1]
  101. #define pa___needgrow(a, n) ((a) == 0 || pa___n(a) + ((int) n) >= pa___m(a))
  102. #define pa___maybegrow(a, n) (pa___needgrow(a, (n)) ? pa___grow(a, n) : 0)
  103. #define pa___grow(a, n) (*((void**)& (a)) = pa___growf((void*) (a), (n), \
  104. sizeof(*(a))))
  105. // ptr[-2] is capacity, ptr[-1] is size.
  106. static void* pa___growf(void* arr, int increment, int itemsize)
  107. {
  108. int dbl_cur = arr ? 2 * pa___m(arr) : 0;
  109. int min_needed = pa_count(arr) + increment;
  110. int m = dbl_cur > min_needed ? dbl_cur : min_needed;
  111. int* p = (int *) PAR_REALLOC(uint8_t, arr ? pa___raw(arr) : 0,
  112. itemsize * m + sizeof(int) * 2);
  113. if (p) {
  114. if (!arr) {
  115. p[1] = 0;
  116. }
  117. p[0] = m;
  118. return p + 2;
  119. }
  120. return (void*) (2 * sizeof(int));
  121. }
  122. #endif
  123. typedef struct {
  124. // Public:
  125. PARINT* collision_pairs;
  126. PARINT ncollision_pairs;
  127. PARINT* culled;
  128. PARINT nculled;
  129. // Private:
  130. PARFLT const* aabbs;
  131. PARINT naabbs;
  132. PARINT* sorted_indices[2];
  133. PARINT* pairs[2];
  134. } par_sprune__context;
  135. static inline int par_qsort_cmpswap(char *__restrict a, char *__restrict b,
  136. size_t w,
  137. int (*compar)(const void *_a, const void *_b,
  138. void *_arg),
  139. void *arg)
  140. {
  141. char tmp, *end = a+w;
  142. if (compar(a, b, arg) > 0) {
  143. for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
  144. return 1;
  145. }
  146. return 0;
  147. }
  148. // qsort doesn't take a context, so we have our own portable implementation.
  149. // Parameters:
  150. // base is the array to be sorted
  151. // nel is the number of elements in the array
  152. // w is the size in bytes of each element of the array
  153. // compar is the comparison function
  154. // arg is a pointer to be passed to the comparison function
  155. //
  156. static inline void par_qsort(
  157. void *base,
  158. size_t nel,
  159. size_t w,
  160. int (*compar)(const void *_a, const void *_b, void *_arg),
  161. void *arg)
  162. {
  163. char *b = (char*) base, *end = (char*) (b + nel * w);
  164. if (nel < 7) {
  165. char *pi, *pj;
  166. for (pi = b+w; pi < end; pi += w) {
  167. for (pj = pi; pj > b && par_qsort_cmpswap(pj-w, pj, w, compar, arg);
  168. pj -= w) {}
  169. }
  170. return;
  171. }
  172. char *x, *y, *xend, ch;
  173. char *pl, *pr;
  174. char *last = b+w*(nel-1), *tmp;
  175. char *l[3];
  176. l[0] = b;
  177. l[1] = b+w*(nel/2);
  178. l[2] = last;
  179. if (compar(l[0],l[1],arg) > 0) {
  180. tmp=l[0]; l[0]=l[1]; l[1]=tmp;
  181. }
  182. if (compar(l[1],l[2],arg) > 0) {
  183. tmp=l[1]; l[1]=l[2]; l[2]=tmp;
  184. if (compar(l[0],l[1],arg) > 0) {
  185. tmp=l[0]; l[0]=l[1]; l[1]=tmp;
  186. }
  187. }
  188. for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
  189. ch = *x; *x = *y; *y = ch;
  190. }
  191. pl = b;
  192. pr = last;
  193. while (pl < pr) {
  194. for (; pl < pr; pl += w) {
  195. if (par_qsort_cmpswap(pl, pr, w, compar, arg)) {
  196. pr -= w;
  197. break;
  198. }
  199. }
  200. for (; pl < pr; pr -= w) {
  201. if (par_qsort_cmpswap(pl, pr, w, compar, arg)) {
  202. pl += w;
  203. break;
  204. }
  205. }
  206. }
  207. par_qsort(b, (pl-b) / w, w, compar, arg);
  208. par_qsort(pl+w, (end - (pl+w)) / w, w, compar, arg);
  209. }
  210. void par_sprune_free_context(par_sprune_context* context)
  211. {
  212. par_sprune__context* ctx = (par_sprune__context*) context;
  213. pa_free(ctx->sorted_indices[0]);
  214. pa_free(ctx->sorted_indices[1]);
  215. pa_free(ctx->pairs[0]);
  216. pa_free(ctx->pairs[1]);
  217. pa_free(ctx->collision_pairs);
  218. PAR_FREE(ctx);
  219. }
  220. static void par_sprune__remove(PARINT* arr, PARINT val)
  221. {
  222. int i = pa_count(arr) - 1;
  223. for (; i >= 0; i--) {
  224. if (arr[i] == val) {
  225. break;
  226. }
  227. }
  228. assert(i >= 0);
  229. for (++i; i < pa_count(arr); i++) {
  230. PAR_SWAP(PARINT, arr[i - 1], arr[i]);
  231. }
  232. pa___n(arr)--;
  233. }
  234. typedef struct {
  235. PARFLT const* aabbs;
  236. } par__sprune_sorter;
  237. static int par__cmpinds(const void* pa, const void* pb, void* psorter)
  238. {
  239. PARINT a = *((const PARINT*) pa);
  240. PARINT b = *((const PARINT*) pb);
  241. par__sprune_sorter* sorter = (par__sprune_sorter*) psorter;
  242. PARFLT const* aabbs = sorter->aabbs;
  243. PARFLT vala = aabbs[a];
  244. PARFLT valb = aabbs[b];
  245. if (vala > valb) return 1;
  246. if (vala < valb) return -1;
  247. if (a > b) return 1;
  248. if (a < b) return -1;
  249. return 0;
  250. }
  251. static int par__cmppairs(const void* pa, const void* pb, void* unused)
  252. {
  253. PARINT a = *((const PARINT*) pa);
  254. PARINT b = *((const PARINT*) pb);
  255. if (a > b) return 1;
  256. if (a < b) return -1;
  257. a = *(1 + (const PARINT*) pa);
  258. b = *(1 + (const PARINT*) pb);
  259. if (a > b) return 1;
  260. if (a < b) return -1;
  261. return 0;
  262. }
  263. static int par__cmpfind(const void* pa, const void* pb)
  264. {
  265. PARINT a = *((const PARINT*) pa);
  266. PARINT b = *((const PARINT*) pb);
  267. if (a > b) return 1;
  268. if (a < b) return -1;
  269. a = *(1 + (const PARINT*) pa);
  270. b = *(1 + (const PARINT*) pb);
  271. if (a > b) return 1;
  272. if (a < b) return -1;
  273. return 0;
  274. }
  275. par_sprune_context* par_sprune_overlap(PARFLT const* aabbs, PARINT naabbs,
  276. par_sprune_context* previous)
  277. {
  278. par_sprune__context* ctx = (par_sprune__context*) previous;
  279. if (!ctx) {
  280. ctx = PAR_CALLOC(par_sprune__context, 1);
  281. }
  282. ctx->aabbs = aabbs;
  283. ctx->naabbs = naabbs;
  284. for (int axis = 0; axis < 2; axis++) {
  285. pa_clear(ctx->sorted_indices[axis]);
  286. pa_add(ctx->sorted_indices[axis], naabbs * 2);
  287. pa_clear(ctx->pairs[axis]);
  288. }
  289. for (PARINT i = 0; i < naabbs; i++) {
  290. ctx->sorted_indices[0][i * 2 + 0] = i * 4 + 0;
  291. ctx->sorted_indices[1][i * 2 + 0] = i * 4 + 1;
  292. ctx->sorted_indices[0][i * 2 + 1] = i * 4 + 2;
  293. ctx->sorted_indices[1][i * 2 + 1] = i * 4 + 3;
  294. }
  295. par__sprune_sorter sorter;
  296. sorter.aabbs = ctx->aabbs;
  297. PARINT* active = 0;
  298. // Sweep a plane first across the X-axis, then down through the Y-axis.
  299. for (int axis = 0; axis < 2; axis++) {
  300. PARINT** pairs = &ctx->pairs[axis];
  301. PARINT* indices = ctx->sorted_indices[axis];
  302. par_qsort(indices, naabbs * 2, sizeof(PARINT), par__cmpinds, &sorter);
  303. pa_clear(active);
  304. for (PARINT i = 0; i < naabbs * 2; i++) {
  305. PARINT fltindex = indices[i];
  306. PARINT boxindex = fltindex / 4;
  307. bool ismin = ((fltindex - axis) % 4) == 0;
  308. if (ismin) {
  309. for (int j = 0; j < pa_count(active); j++) {
  310. pa_push(*pairs, active[j]);
  311. pa_push(*pairs, boxindex);
  312. pa_push(*pairs, boxindex);
  313. pa_push(*pairs, active[j]);
  314. }
  315. pa_push(active, boxindex);
  316. } else {
  317. par_sprune__remove(active, boxindex);
  318. }
  319. }
  320. }
  321. // Sort the Y-axis collision pairs to make it easier to intersect it
  322. // with the set of X-axis collision pairs. We also sort the X-axis
  323. // pairs because it's required for subsequent calls to par_sprune_update.
  324. PARINT* xpairs = ctx->pairs[0];
  325. PARINT* ypairs = ctx->pairs[1];
  326. int nxpairs = pa_count(xpairs) / 2;
  327. int nypairs = pa_count(ypairs) / 2;
  328. int pairsize = 2 * sizeof(PARINT);
  329. pa_free(active);
  330. par_qsort(xpairs, nxpairs, pairsize, par__cmppairs, 0);
  331. par_qsort(ypairs, nypairs, pairsize, par__cmppairs, 0);
  332. pa_clear(ctx->collision_pairs);
  333. // Find the intersection of X-axis overlaps and Y-axis overlaps.
  334. for (int i = 0; i < pa_count(xpairs); i += 2) {
  335. PARINT* key = xpairs + i;
  336. if (key[1] < key[0]) {
  337. continue;
  338. }
  339. void* found = bsearch(key, ypairs, nypairs, pairsize, par__cmpfind);
  340. if (found) {
  341. pa_push(ctx->collision_pairs, key[0]);
  342. pa_push(ctx->collision_pairs, key[1]);
  343. }
  344. }
  345. ctx->ncollision_pairs = pa_count(ctx->collision_pairs) / 2;
  346. return (par_sprune_context*) ctx;
  347. }
  348. bool par_sprune_update(par_sprune_context* context)
  349. {
  350. par_sprune__context* ctx = (par_sprune__context*) context;
  351. PARINT* collision_pairs = ctx->collision_pairs;
  352. PARINT ncollision_pairs = ctx->ncollision_pairs;
  353. ctx->collision_pairs = 0;
  354. par_sprune_overlap(ctx->aabbs, ctx->naabbs, context);
  355. bool dirty = ncollision_pairs != ctx->ncollision_pairs;
  356. if (!dirty) {
  357. int pairsize = 2 * sizeof(PARINT);
  358. for (int i = 0; i < ctx->ncollision_pairs; i += 2) {
  359. PARINT* key = ctx->collision_pairs + i;
  360. if (!bsearch(key, collision_pairs, ncollision_pairs,
  361. pairsize, par__cmpfind)) {
  362. dirty = true;
  363. break;
  364. }
  365. }
  366. }
  367. pa_free(collision_pairs);
  368. return dirty;
  369. }
  370. bool par_sprune__is_culled(par_sprune__context* ctx, PARINT key)
  371. {
  372. for (int i = 0; i < pa_count(ctx->culled); i++) {
  373. if (key == ctx->culled[i]) {
  374. return true;
  375. }
  376. }
  377. return false;
  378. }
  379. static int par__cmpfindsingle(const void* pa, const void* pb)
  380. {
  381. PARINT a = *((const PARINT*) pa);
  382. PARINT b = *((const PARINT*) pb);
  383. if (a > b) return 1;
  384. if (a < b) return -1;
  385. return 0;
  386. }
  387. void par_sprune_cull(par_sprune_context* context)
  388. {
  389. par_sprune__context* ctx = (par_sprune__context*) context;
  390. pa_clear(ctx->culled);
  391. PARINT* collision_pairs = ctx->collision_pairs;
  392. PARINT ncollision_pairs = ctx->ncollision_pairs;
  393. int pairsize = 2 * sizeof(PARINT);
  394. for (int i = 0; i < ctx->naabbs; i++) {
  395. PARINT* found = (PARINT*) bsearch(&i, collision_pairs, ncollision_pairs,
  396. pairsize, par__cmpfindsingle);
  397. if (!found) {
  398. continue;
  399. }
  400. if (!par_sprune__is_culled(ctx, found[0]) &&
  401. !par_sprune__is_culled(ctx, found[1])) {
  402. pa_push(ctx->culled, found[0]);
  403. }
  404. }
  405. ctx->nculled = pa_count(ctx->culled);
  406. }
  407. #undef PARINT
  408. #undef PARFLT
  409. #endif // PAR_SPRUNE_IMPLEMENTATION
  410. #endif // PAR_SPRUNE_H
  411. // par_sprune is distributed under the MIT license:
  412. //
  413. // Copyright (c) 2019 Philip Rideout
  414. //
  415. // Permission is hereby granted, free of charge, to any person obtaining a copy
  416. // of this software and associated documentation files (the "Software"), to deal
  417. // in the Software without restriction, including without limitation the rights
  418. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  419. // copies of the Software, and to permit persons to whom the Software is
  420. // furnished to do so, subject to the following conditions:
  421. //
  422. // The above copyright notice and this permission notice shall be included in
  423. // all copies or substantial portions of the Software.
  424. //
  425. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  426. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  427. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  428. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  429. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  430. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  431. // SOFTWARE.