Changed: HAVE_PTHREAD_ATTR_SETINHERITSCHED and HAVE_PTHREAD_ATTR_SETSTACKLAZY defines...
[ode.git] / GIMPACT / src / gim_boxpruning.cpp
blobf2e77d7cb3ca05f4e806aca6f5fa282913e6114f
2 /*
3 -----------------------------------------------------------------------------
4 This source file is part of GIMPACT Library.
6 For the latest info, see http://gimpact.sourceforge.net/
8 Copyright (c) 2006 Francisco Leon. C.C. 80087371.
9 email: projectileman@yahoo.com
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of EITHER:
13 (1) The GNU Lesser General Public License as published by the Free
14 Software Foundation; either version 2.1 of the License, or (at
15 your option) any later version. The text of the GNU Lesser
16 General Public License is included with this library in the
17 file GIMPACT-LICENSE-LGPL.TXT.
18 (2) The BSD-style license that is included with this library in
19 the file GIMPACT-LICENSE-BSD.TXT.
21 This library is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
24 GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
26 -----------------------------------------------------------------------------
30 #include "GIMPACT/gim_boxpruning.h"
34 //! Allocate memory for all aabb set.
35 void gim_aabbset_alloc(GIM_AABB_SET * aabbset, GUINT32 count)
37 aabbset->m_count = count;
38 aabbset->m_boxes = (aabb3f *)gim_alloc(sizeof(aabb3f)*count);
40 if(count<GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES)
42 aabbset->m_maxcoords = 0;
43 aabbset->m_sorted_mincoords = 0;
45 else
47 aabbset->m_maxcoords = (GUINT32 *)gim_alloc(sizeof(GUINT32)*aabbset->m_count );
48 aabbset->m_sorted_mincoords = (GIM_RSORT_TOKEN *)gim_alloc(sizeof(GIM_RSORT_TOKEN)*aabbset->m_count);
50 aabbset->m_shared = 0;
51 INVALIDATE_AABB(aabbset->m_global_bound);
54 //! Destroys the aabb set.
55 void gim_aabbset_destroy(GIM_AABB_SET * aabbset)
57 aabbset->m_count = 0;
58 if(aabbset->m_shared==0)
60 gim_free(aabbset->m_boxes,0);
61 gim_free(aabbset->m_maxcoords,0);
62 gim_free(aabbset->m_sorted_mincoords,0);
64 aabbset->m_boxes = 0;
65 aabbset->m_sorted_mincoords = 0;
66 aabbset->m_maxcoords = 0;
69 void gim_aabbset_calc_global_bound(GIM_AABB_SET * aabbset)
71 aabb3f * paabb = aabbset->m_boxes;
72 aabb3f * globalbox = &aabbset->m_global_bound;
73 AABB_COPY((*globalbox),(*paabb));
75 GUINT32 count = aabbset->m_count-1;
76 paabb++;
77 while(count)
79 MERGEBOXES(*globalbox,*paabb)
80 paabb++;
81 count--;
86 //! Sorts the boxes for box prunning.
87 /*!
88 1) find the integer representation of the aabb coords
89 2) Sorts the min coords
90 3) Calcs the global bound
91 \pre aabbset must be allocated. And the boxes must be already set.
92 \param aabbset
93 \param calc_global_bound If 1 , calcs the global bound
94 \post If aabbset->m_sorted_mincoords == 0, then it allocs the sorted coordinates
96 void gim_aabbset_sort(GIM_AABB_SET * aabbset, char calc_global_bound)
98 if(aabbset->m_sorted_mincoords == 0)
99 {//allocate
100 aabbset->m_maxcoords = (GUINT32 *)gim_alloc(sizeof(GUINT32)*aabbset->m_count );
101 aabbset->m_sorted_mincoords = (GIM_RSORT_TOKEN *)gim_alloc(sizeof(GIM_RSORT_TOKEN)*aabbset->m_count);
104 GUINT32 i, count = aabbset->m_count;
105 aabb3f * paabb = aabbset->m_boxes;
106 GUINT32 * maxcoords = aabbset->m_maxcoords;
107 GIM_RSORT_TOKEN * sorted_tokens = aabbset->m_sorted_mincoords;
109 if(count<860)//Calibrated on a Pentium IV
111 //Sort by quick sort
112 //Calculate keys
113 for(i=0;i<count;i++)
115 GIM_CONVERT_VEC3F_GUINT_XZ_UPPER(paabb[i].maxX,paabb[i].maxZ,maxcoords[i]);
116 GIM_CONVERT_VEC3F_GUINT_XZ(paabb[i].minX,paabb[i].minZ,sorted_tokens[i].m_key);
117 sorted_tokens[i].m_value = i;
119 GIM_QUICK_SORT_ARRAY(GIM_RSORT_TOKEN , sorted_tokens, count, RSORT_TOKEN_COMPARATOR,GIM_DEF_EXCHANGE_MACRO);
121 else
123 //Sort by radix sort
124 GIM_RSORT_TOKEN * unsorted = (GIM_RSORT_TOKEN *)gim_alloc(sizeof(GIM_RSORT_TOKEN )*count);
125 //Calculate keys
126 for(i=0;i<count;i++)
128 GIM_CONVERT_VEC3F_GUINT_XZ_UPPER(paabb[i].maxX,paabb[i].maxZ,maxcoords[i]);
129 GIM_CONVERT_VEC3F_GUINT_XZ(paabb[i].minX,paabb[i].minZ,unsorted[i].m_key);
130 unsorted[i].m_value = i;
132 GIM_RADIX_SORT_RTOKENS(unsorted,sorted_tokens,count);
133 gim_free(unsorted,0);
136 if(calc_global_bound) gim_aabbset_calc_global_bound(aabbset);
139 //utility macros
141 /*#define PUSH_PAIR(i,j,pairset)\
143 GIM_PAIR _pair={i,j};\
144 GIM_DYNARRAY_PUSH_ITEM(GIM_PAIR,pairset,_pair);\
147 #define PUSH_PAIR(i,j,pairset)\
149 GIM_DYNARRAY_PUSH_EMPTY(GIM_PAIR,pairset);\
150 GIM_PAIR * _pair = GIM_DYNARRAY_POINTER(GIM_PAIR,pairset) + (pairset).m_size - 1;\
151 _pair->m_index1 = i;\
152 _pair->m_index2 = j;\
155 #define PUSH_PAIR_INV(i,j,pairset)\
157 GIM_DYNARRAY_PUSH_EMPTY(GIM_PAIR,pairset);\
158 GIM_PAIR * _pair = GIM_DYNARRAY_POINTER(GIM_PAIR,pairset) + (pairset).m_size - 1;\
159 _pair->m_index1 = j;\
160 _pair->m_index2 = i;\
163 #define FIND_OVERLAPPING_FOWARD(\
164 curr_index,\
165 test_count,\
166 test_aabb,\
167 max_coord_uint,\
168 sorted_tokens,\
169 aabbarray,\
170 pairset,\
171 push_pair_macro)\
173 GUINT32 _i = test_count;\
174 char _intersected;\
175 GIM_RSORT_TOKEN * _psorted_tokens = sorted_tokens;\
176 while(_i>0 && max_coord_uint >= _psorted_tokens->m_key)\
178 AABBCOLLISION(_intersected,test_aabb,aabbarray[_psorted_tokens->m_value]);\
179 if(_intersected)\
181 push_pair_macro(curr_index, _psorted_tokens->m_value,pairset);\
183 _psorted_tokens++;\
184 _i--;\
188 //! log(N) Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
190 \pre aabbset must be allocated and sorted, the boxes must be already set.
191 \param aabbset Must be sorted. Global bound isn't required
192 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
194 void gim_aabbset_self_intersections_sorted(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs)
196 collision_pairs->m_size = 0;
197 GUINT32 count = aabbset->m_count;
198 aabb3f * paabb = aabbset->m_boxes;
199 GUINT32 * maxcoords = aabbset->m_maxcoords;
200 GIM_RSORT_TOKEN * sorted_tokens = aabbset->m_sorted_mincoords;
201 aabb3f test_aabb;
202 while(count>1)
204 ///current cache variables
205 GUINT32 curr_index = sorted_tokens->m_value;
206 GUINT32 max_coord_uint = maxcoords[curr_index];
207 AABB_COPY(test_aabb,paabb[curr_index]);
209 ///next pairs
210 sorted_tokens++;
211 count--;
212 FIND_OVERLAPPING_FOWARD( curr_index, count, test_aabb, max_coord_uint, sorted_tokens , paabb, (*collision_pairs),PUSH_PAIR);
216 //! NxN Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
218 \pre aabbset must be allocated, the boxes must be already set.
219 \param aabbset Global bound isn't required. Doen't need to be sorted.
220 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
222 void gim_aabbset_self_intersections_brute_force(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs)
224 collision_pairs->m_size = 0;
225 GUINT32 i,j;
226 GUINT32 count = aabbset->m_count;
227 aabb3f * paabb = aabbset->m_boxes;
228 char intersected;
229 for (i=0;i< count-1 ;i++ )
231 for (j=i+1;j<count ;j++ )
233 AABBCOLLISION(intersected,paabb[i],paabb[j]);
234 if(intersected)
236 PUSH_PAIR(i,j,(*collision_pairs));
242 //! log(N) Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
244 \pre aabbset1 and aabbset2 must be allocated and sorted, the boxes must be already set.
245 \param aabbset1 Must be sorted, Global bound is required.
246 \param aabbset2 Must be sorted, Global bound is required.
247 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
249 void gim_aabbset_bipartite_intersections_sorted(GIM_AABB_SET * aabbset1, GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs)
251 char intersected;
252 collision_pairs->m_size = 0;
254 AABBCOLLISION(intersected,aabbset1->m_global_bound,aabbset2->m_global_bound);
255 if(intersected == 0) return;
257 GUINT32 count1 = aabbset1->m_count;
258 aabb3f * paabb1 = aabbset1->m_boxes;
259 GUINT32 * maxcoords1 = aabbset1->m_maxcoords;
260 GIM_RSORT_TOKEN * sorted_tokens1 = aabbset1->m_sorted_mincoords;
262 GUINT32 count2 = aabbset2->m_count;
263 aabb3f * paabb2 = aabbset2->m_boxes;
264 GUINT32 * maxcoords2 = aabbset2->m_maxcoords;
265 GIM_RSORT_TOKEN * sorted_tokens2 = aabbset2->m_sorted_mincoords;
267 GUINT32 curr_index;
269 GUINT32 max_coord_uint;
270 aabb3f test_aabb;
272 //Classify boxes
273 //Find Set intersection
274 aabb3f int_abbb;
275 BOXINTERSECTION(aabbset1->m_global_bound,aabbset2->m_global_bound, int_abbb);
277 //Clasify set 1
278 GIM_RSORT_TOKEN * classified_tokens1 = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*count1);
279 GUINT32 i,classified_count1 = 0,classified_count2 = 0;
282 for (i=0;i<count1;i++ )
284 curr_index = sorted_tokens1[i].m_value;
285 AABBCOLLISION(intersected,paabb1[curr_index],int_abbb);
286 if(intersected)
288 classified_tokens1[classified_count1] = sorted_tokens1[i];
289 classified_count1++;
293 if(classified_count1==0)
295 gim_free(classified_tokens1 ,0);
296 return; // no pairs
299 //Clasify set 2
300 GIM_RSORT_TOKEN * classified_tokens2 = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*count2);
302 for (i=0;i<count2;i++ )
304 curr_index = sorted_tokens2[i].m_value;
305 AABBCOLLISION(intersected,paabb2[curr_index],int_abbb);
306 if(intersected)
308 classified_tokens2[classified_count2] = sorted_tokens2[i];
309 classified_count2++;
313 if(classified_count2==0)
315 gim_free(classified_tokens1 ,0);
316 gim_free(classified_tokens2 ,0);
317 return; // no pairs
320 sorted_tokens1 = classified_tokens1;
321 sorted_tokens2 = classified_tokens2;
323 while(classified_count1>0&&classified_count2>0)
325 if(sorted_tokens1->m_key <= sorted_tokens2->m_key)
327 ///current cache variables
328 curr_index = sorted_tokens1->m_value;
329 max_coord_uint = maxcoords1[curr_index];
330 AABB_COPY(test_aabb,paabb1[curr_index]);
331 ///next pairs
332 sorted_tokens1++;
333 classified_count1--;
334 FIND_OVERLAPPING_FOWARD( curr_index, classified_count2, test_aabb, max_coord_uint, sorted_tokens2 , paabb2, (*collision_pairs), PUSH_PAIR);
336 else ///Switch test
338 ///current cache variables
339 curr_index = sorted_tokens2->m_value;
340 max_coord_uint = maxcoords2[curr_index];
341 AABB_COPY(test_aabb,paabb2[curr_index]);
342 ///next pairs
343 sorted_tokens2++;
344 classified_count2--;
345 FIND_OVERLAPPING_FOWARD( curr_index, classified_count1, test_aabb, max_coord_uint, sorted_tokens1 , paabb1, (*collision_pairs), PUSH_PAIR_INV );
348 gim_free(classified_tokens1 ,0);
349 gim_free(classified_tokens2 ,0);
352 //! NxM Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
354 \pre aabbset1 and aabbset2 must be allocated and sorted, the boxes must be already set.
355 \param aabbset1 Must be sorted, Global bound is required.
356 \param aabbset2 Must be sorted, Global bound is required.
357 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
359 void gim_aabbset_bipartite_intersections_brute_force(GIM_AABB_SET * aabbset1,GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs)
361 char intersected;
362 collision_pairs->m_size = 0;
363 AABBCOLLISION(intersected,aabbset1->m_global_bound,aabbset2->m_global_bound);
364 if(intersected == 0) return;
366 aabb3f int_abbb;
367 //Find Set intersection
368 BOXINTERSECTION(aabbset1->m_global_bound,aabbset2->m_global_bound, int_abbb);
369 //Clasify set 1
370 GUINT32 i,j;
371 GUINT32 classified_count = 0;
373 GUINT32 count = aabbset1->m_count;
374 aabb3f * paabb1 = aabbset1->m_boxes;
375 aabb3f * paabb2 = aabbset2->m_boxes;
377 GUINT32 * classified = (GUINT32 *) gim_alloc(sizeof(GUINT32)*count);
379 for (i=0;i<count;i++ )
381 AABBCOLLISION(intersected,paabb1[i],int_abbb);
382 if(intersected)
384 classified[classified_count] = i;
385 classified_count++;
389 if(classified_count==0)
391 gim_free(classified,0);
392 return; // no pairs
395 //intesect set2
396 count = aabbset2->m_count;
397 for (i=0;i<count;i++)
399 AABBCOLLISION(intersected,paabb2[i],int_abbb);
400 if(intersected)
402 for (j=0;j<classified_count;j++)
404 AABBCOLLISION(intersected,paabb2[i],paabb1[classified[j]]);
405 if(intersected)
407 PUSH_PAIR(classified[j],i,(*collision_pairs));
412 gim_free(classified,0);
416 //! Initalizes the set. Sort Boxes if needed.
418 \pre aabbset must be allocated. And the boxes must be already set.
419 \post If the set has less of GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES boxes, only calcs the global box,
420 else it Sorts the entire set( Only applicable for large sets)
422 void gim_aabbset_update(GIM_AABB_SET * aabbset)
424 if(aabbset->m_count < GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES)
425 {//Brute force approach
426 gim_aabbset_calc_global_bound(aabbset);
428 else
429 {//Sorted force approach
430 gim_aabbset_sort(aabbset,1);
434 //! Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
436 This function sorts the set and then it calls to gim_aabbset_self_intersections_brute_force or gim_aabbset_self_intersections_sorted.
438 \param aabbset Set of boxes. Sorting isn't required.
439 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
440 \pre aabbset must be allocated and initialized.
441 \post If aabbset->m_count >= GIM_MIN_SORTED_PRUNING_BOXES, then it calls to gim_aabbset_sort and then to gim_aabbset_self_intersections_sorted.
443 void gim_aabbset_self_intersections(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs)
445 if(aabbset->m_count < GIM_MIN_SORTED_PRUNING_BOXES)
446 {//Brute force approach
447 gim_aabbset_self_intersections_brute_force(aabbset,collision_pairs);
449 else
450 {//Sorted force approach
451 gim_aabbset_sort(aabbset,0);
452 gim_aabbset_self_intersections_sorted(aabbset,collision_pairs);
456 //! Collides two sets. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
458 \pre aabbset1 and aabbset2 must be allocated and updated. See .
459 \param aabbset1 Must be sorted, Global bound is required.
460 \param aabbset2 Must be sorted, Global bound is required.
461 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
463 void gim_aabbset_bipartite_intersections(GIM_AABB_SET * aabbset1, GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs)
465 if(aabbset1->m_sorted_mincoords == 0||aabbset2->m_sorted_mincoords == 0)
466 {//Brute force approach
467 gim_aabbset_bipartite_intersections_brute_force(aabbset1,aabbset2,collision_pairs);
469 else
470 {//Sorted force approach
471 gim_aabbset_bipartite_intersections_sorted(aabbset1,aabbset2,collision_pairs);
475 void gim_aabbset_box_collision(aabb3f *test_aabb, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided)
477 collided->m_size = 0;
478 char intersected;
479 AABBCOLLISION(intersected,aabbset->m_global_bound,(*test_aabb));
480 if(intersected == 0) return;
482 GUINT32 i;
483 GUINT32 count = aabbset->m_count;
484 aabb3f * paabb = aabbset->m_boxes;
485 aabb3f _testaabb;
486 AABB_COPY(_testaabb,*test_aabb);
488 for (i=0;i< count;i++ )
490 AABBCOLLISION(intersected,paabb[i],_testaabb);
491 if(intersected)
493 GIM_DYNARRAY_PUSH_ITEM(GUINT32,(*collided),i);
498 void gim_aabbset_ray_collision(vec3f vorigin,vec3f vdir, GREAL tmax, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided)
500 collided->m_size = 0;
501 char intersected;
502 GREAL tparam = 0;
503 BOX_INTERSECTS_RAY(aabbset->m_global_bound, vorigin, vdir, tparam, tmax,intersected);
504 if(intersected==0) return;
506 GUINT32 i;
507 GUINT32 count = aabbset->m_count;
508 aabb3f * paabb = aabbset->m_boxes;
510 for (i=0;i< count;i++ )
512 BOX_INTERSECTS_RAY(paabb[i], vorigin, vdir, tparam, tmax,intersected);
513 if(intersected)
515 GIM_DYNARRAY_PUSH_ITEM(GUINT32,(*collided),i);
518 (void)tparam;