Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/GIMPACT/src/gim_boxpruning.cpp @ 216

Last change on this file since 216 was 216, checked in by mathiask, 17 years ago

[Physik] add ode-0.9

File size: 17.1 KB
Line 
1
2/*
3-----------------------------------------------------------------------------
4This source file is part of GIMPACT Library.
5
6For the latest info, see http://gimpact.sourceforge.net/
7
8Copyright (c) 2006 Francisco Leon. C.C. 80087371.
9email: projectileman@yahoo.com
10
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.
20
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.
25
26-----------------------------------------------------------------------------
27*/
28
29
30#include "GIMPACT/gim_boxpruning.h"
31
32
33
34//! Allocate memory for all aabb set.
35void gim_aabbset_alloc(GIM_AABB_SET * aabbset, GUINT count)
36{
37    aabbset->m_count = count;
38    aabbset->m_boxes = (aabb3f *)gim_alloc(sizeof(aabb3f)*count);
39
40    if(count<GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES)
41    {
42        aabbset->m_maxcoords = 0;
43        aabbset->m_sorted_mincoords = 0;
44    }
45    else
46    {
47        aabbset->m_maxcoords = (GUINT *)gim_alloc(sizeof(GUINT)*aabbset->m_count );
48        aabbset->m_sorted_mincoords = (GIM_RSORT_TOKEN *)gim_alloc(sizeof(GIM_RSORT_TOKEN)*aabbset->m_count);
49    }
50    aabbset->m_shared = 0;
51    INVALIDATE_AABB(aabbset->m_global_bound);
52}
53
54//! Destroys the aabb set.
55void gim_aabbset_destroy(GIM_AABB_SET * aabbset)
56{
57    aabbset->m_count = 0;
58    if(aabbset->m_shared==0)
59    {
60        gim_free(aabbset->m_boxes,0);
61        gim_free(aabbset->m_maxcoords,0);
62        gim_free(aabbset->m_sorted_mincoords,0);
63    }
64    aabbset->m_boxes = 0;
65    aabbset->m_sorted_mincoords = 0;
66    aabbset->m_maxcoords = 0;
67}
68
69void gim_aabbset_calc_global_bound(GIM_AABB_SET * aabbset)
70{
71    aabb3f * paabb = aabbset->m_boxes;
72    aabb3f * globalbox = &aabbset->m_global_bound;
73    AABB_COPY((*globalbox),(*paabb));
74
75    GUINT count = aabbset->m_count-1;
76    paabb++;
77    while(count)
78    {
79        MERGEBOXES(*globalbox,*paabb)
80        paabb++;
81        count--;
82    }
83}
84
85
86//! Sorts the boxes for box prunning.
87/*!
881) find the integer representation of the aabb coords
892) Sorts the min coords
903) 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
95*/
96void gim_aabbset_sort(GIM_AABB_SET * aabbset, char calc_global_bound)
97{
98    if(aabbset->m_sorted_mincoords == 0)
99    {//allocate
100        aabbset->m_maxcoords = (GUINT *)gim_alloc(sizeof(GUINT)*aabbset->m_count );
101        aabbset->m_sorted_mincoords = (GIM_RSORT_TOKEN *)gim_alloc(sizeof(GIM_RSORT_TOKEN)*aabbset->m_count);
102    }
103
104    GUINT i, count = aabbset->m_count;
105    aabb3f * paabb = aabbset->m_boxes;
106    GUINT * maxcoords = aabbset->m_maxcoords;
107    GIM_RSORT_TOKEN * sorted_tokens = aabbset->m_sorted_mincoords;
108
109    if(count<860)//Calibrated on a Pentium IV
110    {
111        //Sort by quick sort
112            //Calculate keys
113        for(i=0;i<count;i++)
114        {
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;
118        }
119        GIM_QUICK_SORT_ARRAY(GIM_RSORT_TOKEN , sorted_tokens, count, RSORT_TOKEN_COMPARATOR,GIM_DEF_EXCHANGE_MACRO);
120    }
121    else
122    {
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++)
127        {
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;
131        }
132        GIM_RADIX_SORT_RTOKENS(unsorted,sorted_tokens,count);
133        gim_free(unsorted,0);
134    }
135
136    if(calc_global_bound) gim_aabbset_calc_global_bound(aabbset);
137}
138
139//utility macros
140
141/*#define PUSH_PAIR(i,j,pairset)\
142{\
143    GIM_PAIR _pair={i,j};\
144    GIM_DYNARRAY_PUSH_ITEM(GIM_PAIR,pairset,_pair);\
145}*/
146
147#define PUSH_PAIR(i,j,pairset)\
148{\
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;\
153}
154
155#define PUSH_PAIR_INV(i,j,pairset)\
156{\
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;\
161}
162
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)\
172{\
173    GUINT _i = test_count;\
174    char _intersected;\
175    GIM_RSORT_TOKEN * _psorted_tokens = sorted_tokens;\
176    while(max_coord_uint >= _psorted_tokens->m_key && _i>0)\
177    {\
178        AABBCOLLISION(_intersected,test_aabb,aabbarray[_psorted_tokens->m_value]);\
179        if(_intersected)\
180        {\
181            push_pair_macro(curr_index, _psorted_tokens->m_value,pairset);\
182        }\
183        _psorted_tokens++;\
184        _i--;\
185    }\
186}
187
188//! log(N) Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
189/*!
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)
193*/
194void gim_aabbset_self_intersections_sorted(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs)
195{
196    collision_pairs->m_size = 0;
197    GUINT count = aabbset->m_count;
198    aabb3f * paabb = aabbset->m_boxes;
199    GUINT * maxcoords = aabbset->m_maxcoords;
200    GIM_RSORT_TOKEN * sorted_tokens = aabbset->m_sorted_mincoords;
201    aabb3f test_aabb;
202    while(count>1)
203    {
204        ///current cache variables
205        GUINT  curr_index = sorted_tokens->m_value;
206        GUINT max_coord_uint = maxcoords[curr_index];
207        AABB_COPY(test_aabb,paabb[curr_index]);
208
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);
213    }
214}
215
216//! NxN Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
217/*!
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)
221*/
222void gim_aabbset_self_intersections_brute_force(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs)
223{
224    collision_pairs->m_size = 0;
225    GUINT i,j;
226    GUINT count = aabbset->m_count;
227    aabb3f * paabb = aabbset->m_boxes;
228    char intersected;
229    for (i=0;i< count-1 ;i++ )
230    {
231        for (j=i+1;j<count ;j++ )
232        {
233            AABBCOLLISION(intersected,paabb[i],paabb[j]);
234            if(intersected)
235            {
236                PUSH_PAIR(i,j,(*collision_pairs));
237            }
238        }
239    }
240}
241
242//! log(N) Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
243/*!
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)
248*/
249void gim_aabbset_bipartite_intersections_sorted(GIM_AABB_SET * aabbset1, GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs)
250{
251    char intersected;
252    collision_pairs->m_size = 0;
253
254    AABBCOLLISION(intersected,aabbset1->m_global_bound,aabbset2->m_global_bound);
255    if(intersected == 0) return;
256
257    GUINT count1 = aabbset1->m_count;
258    aabb3f * paabb1 = aabbset1->m_boxes;
259    GUINT * maxcoords1 = aabbset1->m_maxcoords;
260    GIM_RSORT_TOKEN * sorted_tokens1 = aabbset1->m_sorted_mincoords;
261
262    GUINT count2 = aabbset2->m_count;
263    aabb3f * paabb2 = aabbset2->m_boxes;
264    GUINT * maxcoords2 = aabbset2->m_maxcoords;
265    GIM_RSORT_TOKEN * sorted_tokens2 = aabbset2->m_sorted_mincoords;
266
267    GUINT  curr_index;
268
269    GUINT max_coord_uint;
270    aabb3f test_aabb;
271
272    //Classify boxes
273    //Find  Set intersection
274    aabb3f int_abbb;
275    BOXINTERSECTION(aabbset1->m_global_bound,aabbset2->m_global_bound, int_abbb);
276
277    //Clasify set 1
278    GIM_RSORT_TOKEN * classified_tokens1 = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*count1);
279    GUINT i,classified_count1 = 0,classified_count2 = 0;
280
281
282    for (i=0;i<count1;i++ )
283    {
284        curr_index = sorted_tokens1[i].m_value;
285        AABBCOLLISION(intersected,paabb1[curr_index],int_abbb);
286        if(intersected)
287        {
288            classified_tokens1[classified_count1] = sorted_tokens1[i];
289            classified_count1++;
290        }
291    }
292
293    if(classified_count1==0)
294    {
295        gim_free(classified_tokens1 ,0);
296        return; // no pairs
297    }
298
299    //Clasify set 2
300    GIM_RSORT_TOKEN * classified_tokens2 = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*count2);
301
302    for (i=0;i<count2;i++ )
303    {
304        curr_index = sorted_tokens2[i].m_value;
305        AABBCOLLISION(intersected,paabb2[curr_index],int_abbb);
306        if(intersected)
307        {
308            classified_tokens2[classified_count2] = sorted_tokens2[i];
309            classified_count2++;
310        }
311    }
312
313    if(classified_count2==0)
314    {
315        gim_free(classified_tokens1 ,0);
316        gim_free(classified_tokens2 ,0);
317        return; // no pairs
318    }
319
320    sorted_tokens1 = classified_tokens1;
321    sorted_tokens2 = classified_tokens2;
322
323    while(classified_count1>0&&classified_count2>0)
324    {
325        if(sorted_tokens1->m_key <= sorted_tokens2->m_key)
326        {
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);
335        }
336        else ///Switch test
337        {
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 );
346        }
347    }
348    gim_free(classified_tokens1 ,0);
349    gim_free(classified_tokens2 ,0);
350}
351
352//! NxM Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
353/*!
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)
358*/
359void gim_aabbset_bipartite_intersections_brute_force(GIM_AABB_SET * aabbset1,GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs)
360{
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;
365
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    GUINT i,j;
371    GUINT classified_count = 0;
372
373    GUINT count = aabbset1->m_count;
374    aabb3f * paabb1 = aabbset1->m_boxes;
375    aabb3f * paabb2 = aabbset2->m_boxes;
376
377    GUINT * classified = (GUINT *) gim_alloc(sizeof(GUINT)*count);
378
379    for (i=0;i<count;i++ )
380    {
381        AABBCOLLISION(intersected,paabb1[i],int_abbb);
382        if(intersected)
383        {
384            classified[classified_count] = i;
385            classified_count++;
386        }
387    }
388
389    if(classified_count==0) return; // no pairs
390
391    //intesect set2
392    count = aabbset2->m_count;
393    for (i=0;i<count;i++)
394    {
395        AABBCOLLISION(intersected,paabb2[i],int_abbb);
396        if(intersected)
397        {
398            for (j=0;j<classified_count;j++)
399            {
400                AABBCOLLISION(intersected,paabb2[i],paabb1[classified[j]]);
401                if(intersected)
402                {
403                    PUSH_PAIR(classified[j],i,(*collision_pairs));
404                }
405            }
406        }
407    }
408    gim_free(classified,0);
409}
410
411
412//! Initalizes the set. Sort Boxes if needed.
413/*!
414\pre aabbset must be allocated. And the boxes must be already set.
415\post If the set has less of GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES boxes, only calcs the global box,
416 else it Sorts the entire set( Only applicable for large sets)
417*/
418void gim_aabbset_update(GIM_AABB_SET * aabbset)
419{
420    if(aabbset->m_count < GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES)
421    {//Brute force approach
422        gim_aabbset_calc_global_bound(aabbset);
423    }
424    else
425    {//Sorted force approach
426        gim_aabbset_sort(aabbset,1);
427    }
428}
429
430//! Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
431/*!
432This function sorts the set and then it calls to gim_aabbset_self_intersections_brute_force or gim_aabbset_self_intersections_sorted.
433
434\param aabbset Set of boxes. Sorting isn't required.
435\param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
436\pre aabbset must be allocated and initialized.
437\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.
438*/
439void gim_aabbset_self_intersections(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs)
440{
441    if(aabbset->m_count < GIM_MIN_SORTED_PRUNING_BOXES)
442    {//Brute force approach
443        gim_aabbset_self_intersections_brute_force(aabbset,collision_pairs);
444    }
445    else
446    {//Sorted force approach
447        gim_aabbset_sort(aabbset,0);
448        gim_aabbset_self_intersections_sorted(aabbset,collision_pairs);
449    }
450}
451
452//! Collides two sets. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
453/*!
454\pre aabbset1 and aabbset2 must be allocated and updated. See .
455\param aabbset1 Must be sorted, Global bound is required.
456\param aabbset2 Must be sorted, Global bound is required.
457\param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
458*/
459void gim_aabbset_bipartite_intersections(GIM_AABB_SET * aabbset1, GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs)
460{
461    if(aabbset1->m_sorted_mincoords == 0||aabbset2->m_sorted_mincoords == 0)
462    {//Brute force approach
463        gim_aabbset_bipartite_intersections_brute_force(aabbset1,aabbset2,collision_pairs);
464    }
465    else
466    {//Sorted force approach
467        gim_aabbset_bipartite_intersections_sorted(aabbset1,aabbset2,collision_pairs);
468    }
469}
470
471void gim_aabbset_box_collision(aabb3f *test_aabb, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided)
472{
473    collided->m_size = 0;
474    char intersected;
475    AABBCOLLISION(intersected,aabbset->m_global_bound,(*test_aabb));
476    if(intersected == 0) return;
477
478    GUINT i;
479    GUINT count = aabbset->m_count;
480    aabb3f * paabb = aabbset->m_boxes;
481    aabb3f _testaabb;
482    AABB_COPY(_testaabb,*test_aabb);
483
484    for (i=0;i< count;i++ )
485    {
486        AABBCOLLISION(intersected,paabb[i],_testaabb);
487        if(intersected)
488        {
489            GIM_DYNARRAY_PUSH_ITEM(GUINT,(*collided),i);
490        }
491    }
492}
493
494void gim_aabbset_ray_collision(vec3f vorigin,vec3f vdir, GREAL tmax, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided)
495{
496    collided->m_size = 0;
497    char intersected;
498    GREAL tparam = 0;
499    BOX_INTERSECTS_RAY(aabbset->m_global_bound, vorigin, vdir, tparam, tmax,intersected);
500    if(intersected==0) return;
501
502    GUINT i;
503    GUINT count = aabbset->m_count;
504    aabb3f * paabb = aabbset->m_boxes;
505
506    for (i=0;i< count;i++ )
507    {
508        BOX_INTERSECTS_RAY(paabb[i], vorigin, vdir, tparam, tmax,intersected);
509        if(intersected)
510        {
511            GIM_DYNARRAY_PUSH_ITEM(GUINT,(*collided),i);
512        }
513    }
514}
Note: See TracBrowser for help on using the repository browser.