Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/chris/core/collision.cc @ 1981

Last change on this file since 1981 was 1981, checked in by chris, 20 years ago

orxonox/branches/chris: added doxygen-optimized comments

File size: 9.5 KB
Line 
1
2
3/*
4   orxonox - the future of 3D-vertical-scrollers
5
6   Copyright (C) 2004 orx
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   ### File Specific:
14   main-programmer: Christian Meyer
15   co-programmer: ...
16*/
17
18
19#include "collision.h"
20
21
22using namespace std;
23
24/**
25   \brief simple CollisionCluster constructor
26   \param rad: the radius of the base sphere
27   \param mid: the middle point of the sphere
28*/
29CollisionCluster::CollisionCluster (float rad = 1.0, Vector mid = Vector(0,0,0))
30{
31  root = (CC_Tree*) malloc( sizeof( CC_Tree));
32  root->n = 0;
33  root->data.ID = 0;
34  root->r = rad;
35  root->m = mid;
36}
37
38/**
39   \brief loads a CollisionCluster from a data file
40   \param filename: self-explanatory
41*/
42CollisionCluster::CollisionCluster (char* filename)
43{
44  FILE* stream;
45  char hbuffer[3];
46  stream = fopen (filename, "rb");
47  if( stream == NULL)
48  {
49    root = NULL;
50    return;
51  }
52  if( fread (hbuffer, sizeof( char), 2, stream) != 2)
53  {
54    root = NULL;
55    return;
56  }
57 
58  hbuffer[2] = 0;
59  if( strcmp (hbuffer, "CC"))
60  {
61    root = NULL;
62    return;
63  }
64 
65  root = load_CC_Tree (stream);
66  fclose (stream);
67}
68
69/**
70   \brief Simple destructor that cleans up all the mess
71*/
72CollisionCluster::~CollisionCluster ()
73{
74  free_CC_Tree( root);
75}
76
77/**
78   \brief stores the CollisionCluster into a file
79   \param filename: self-explanatory
80   \return zero on success, -1 on error
81*/
82int CollisionCluster::store (char* filename)
83{
84  int r;
85  FILE* stream;
86  stream = fopen( filename, "wb");
87  if( stream == NULL) return -1;
88  r = save_CC_Tree (root, stream);
89  fclose (stream);
90  return r;
91}
92
93/**
94   \brief performs a collision check between a CollisionCluster and a Line
95   \param pa: pointer to the Placement of the CollisionCluster
96   \param a: pointer to the CollisionCluster
97   \param ahitflags: pointer to an unsigned long to store hitlocation data
98   \param trace: pointer to the Line
99   \param impactpoint: pointer to a Vector where the point of intersection is stored in
100   \return true on collision, false otherwise. If true is returned, the flag in ahitflags that symbolises the hit subsphere is set, and impactpoint is set to the Location where the intersection occured
101*/
102bool check_trace (const Placement* pa, const CollisionCluster* a, unsigned long* ahitflags, const Line* trace, Vector* impactpoint)
103{
104        CC_Tree* t;
105        if( (t = a->root) == NULL) return false;
106       
107  return cctree_trace( pa, t, ahitflags, trace, impactpoint);
108}
109
110/**
111   \brief performs a collision check between two CollisionClusters
112   \param pa: pointer to the Placement of the first CollisionCluster
113   \param a: pointer to the first CollisionCluster
114   \param ahitflags: pointer to an unsigned long to store hitlocation data on the first CollisionCluster
115   \param pb: pointer to the Placement of the second CollisionCluster
116   \param b: pointer to the second CollisionCluster
117   \param bhitflags: pointer to an unsigned long to store hitlocation data on the second CollisionCluster
118   \return true on collision, false otherwise
119   If true is returned, all flags in ahitflags and bhitflags that symbolize intersecting subspheres in the respective CollisionCluster are set
120*/
121bool check_collision (const Placement* pa, const CollisionCluster* a, unsigned long* ahitflags, const Placement* pb, const CollisionCluster* b, unsigned long* bhitflags)
122{
123  CC_Tree* ta, *tb;
124  if( (ta = a->root) == NULL) return false;
125  if( (tb = b->root) == NULL) return false;
126 
127  return cctree_iterate(pa, ta, ahitflags, pb, tb, bhitflags);
128}
129
130/**
131   \brief performs an intersection check between two spheres
132   \param m1: center point of first sphere
133   \param r1: radius of first sphere
134   \param m2: center point of second sphere
135   \param r2: radius of second sphere
136   \return true on intersection, false otherwise
137*/
138bool sphere_sphere_collision( Vector m1, float r1, Vector m2, float r2)
139{
140  if ((m1-m2).len() < r1+r2) return true;
141  return false;
142}
143
144/**
145   \brief performs an intersection check between a Line and a sphere
146   \param m: center point of the sphere
147   \param r: radius of the sphere
148   \param l: pointer to the Line
149   \param impactpoint: pointer to a buffer to store the point of intersection
150   \return true on intersection, false otherwise. If true is returned, impactpoint is set to the loaction where the intersection occured
151*/
152bool trace_sphere_collision( Vector m, float r, const Line* l, Vector* impactpoint)
153{
154  float A, B, C, D, t[2];
155  Vector d = l->r - m;
156  int i;
157 
158  A = l->a * l->a;
159  B = 2 * (l->a * d);
160  C = (d*d) - r*r;
161  D = B*B - 4*A*C;
162 
163  if (D < 0) return false;
164 
165  t[0] = (-B+sqrt(D))/(2*A);
166  t[1] = (-B-sqrt(D))/(2*A);
167 
168  if( (t[0] > 1 || t[0] < 0) && (t[1] < 0 || t[1] > 1)) return false;
169  if( t[0] > t[1]) i = 0;
170  else i = 1;
171
172  impactpoint->x = (l->r + (l->a * t[i])).x;
173  impactpoint->y = (l->r + (l->a * t[i])).y;
174  impactpoint->z = (l->r + (l->a * t[i])).z;
175 
176  return true;
177}
178
179/**
180   \brief recursive implementation for collision detection within a CC_Tree
181*/
182bool cctree_iterate(const Placement* pa, CC_Tree* ta, unsigned long* ahitflags, const Placement* pb, CC_Tree* tb, unsigned long* bhitflags)
183{
184  bool r = false;
185  int ia, ib;
186  Vector mra = pa->r + rotate_vector( ta->m, pa->w);
187  Vector mrb = pb->r + rotate_vector( tb->m, pb->w);
188  CC_Tree* use_a, *use_b;
189 
190  if( use_a == NULL || use_b == NULL) return false;
191 
192  if( sphere_sphere_collision( mra, ta->r, mrb, tb->r))
193  {
194    if( ta->n == 0 && tb->n == 0)
195    {
196      setflag( ahitflags, ta->data.ID);
197      setflag( bhitflags, tb->data.ID);
198      return true;
199    }
200    for( ia = 0; ia < ta->n || ta->n == 0; ia++)
201    {
202      if( ta->n == 0) use_a = ta;
203      else use_a = ta->data.b[ia];
204      for( ib = 0; ib < tb->n || ta->n == 0; ib++)
205      {
206        if( ta->n == 0) use_b = ta;
207        else use_b = ta->data.b[ib];
208       
209        r = r || cctree_iterate( pa, use_a, ahitflags, pb, use_b, bhitflags);
210       
211        if( tb->n == 0) break;
212      }
213      if( ta->n == 0) break;
214    }
215    return r;
216  }
217 
218  return false;
219}
220
221/**
222   \brief sets the <ID>th flag in flags
223   \param flags: pointer to the long used for flagging
224   \param ID: number of the flag to be set
225*/
226void setflag( unsigned long* flags, unsigned long ID)
227{
228  unsigned long f;
229  f = 1;
230  for( int i = 0; i < ID; i++)
231  {
232    f *= 2;
233  }
234  *flags = *flags | f;
235  return;
236}
237
238/**
239   \brief frees the memory allocated in a CC_Tree
240*/
241void free_CC_Tree( CC_Tree* tree)
242{
243  if (tree == NULL) return;
244  for (int i = 0; i < tree->n; i++)
245  {
246    free_CC_Tree( tree->data.b[i]);
247  }
248  free( tree);
249}
250
251/**
252   \brief loads a CC_Tree from a stream
253*/
254CC_Tree* load_CC_Tree (FILE* stream)
255{
256  CC_Tree* tree = NULL;
257  CC_Tree** branches = NULL;
258  float buf[4];
259  unsigned long n;
260  unsigned long ID;
261 
262  // first load vector and radius
263  if (fread( buf, sizeof (float), 4, stream) != 4) return NULL;
264  // then the amount of subbranches
265  if (fread( &n, sizeof(unsigned long), 1, stream) != 1) return NULL;
266  // then ID or the subbranches
267  if ( n == 0)
268  {
269    if (fread( &ID, sizeof(unsigned long), 1, stream) != 1) return NULL;
270  }
271  else
272  {
273    branches = (CC_Tree**)malloc( sizeof(CC_Tree*) * n);
274    for( int i = 0; i < n; i++)
275    {
276      if ((branches[i] = load_CC_Tree (stream)) == NULL)
277      {
278        for( int j = 0; j < i; j++)
279        {
280          free_CC_Tree (branches[j]);
281          free (branches);
282          return NULL;
283        }
284      }
285    }
286  }
287 
288  // assemble
289  tree = (CC_Tree*) malloc (sizeof(CC_Tree));
290  tree->m.x = buf[0];
291  tree->m.y = buf[1];
292  tree->m.z = buf[2];
293  tree->r = buf[3];
294  tree->n = n;
295  if( n == 0) tree->data.ID = ID;
296  else tree->data.b = branches;
297 
298  // then return
299  return tree;
300}
301
302/**
303   \brief saves a CC_Tree to a stream
304*/
305int save_CC_Tree (CC_Tree* tree, FILE* stream)
306{
307  float buf[4];
308 
309  buf[0] = tree->m.x;
310  buf[1] = tree->m.y;
311  buf[2] = tree->m.z;
312  buf[3] = tree->r;
313 
314  // first save vector and radius
315  if (fwrite( buf, sizeof (float), 4, stream) != 4) return -1;
316  // then the amount of subbranches
317  if (fwrite( &(tree->n), sizeof(unsigned long), 1, stream) != 1) return -1;
318  // then ID or the subbranches
319  if ( tree->n == 0)
320  {
321    if (fwrite( &(tree->data.ID), sizeof(unsigned long), 1, stream) != 1) return -1;
322  }
323  else
324  {
325    for( int i = 0; i < tree->n; i++)
326    {
327      if ( save_CC_Tree (tree->data.b[i], stream) == -1) return -1;
328    }
329  }
330   
331  // then return
332  return 0;
333}
334
335/**
336   \brief recursive implementation for traceing detection within a CC_Tree
337*/
338bool cctree_trace( const Placement* p, CC_Tree* t, unsigned long* hitflags, const Line* trace, Vector* impactpoint)
339{
340  bool r = false;
341  int i;
342  Vector mr = p->r + rotate_vector( t->m, p->w);
343  CC_Tree* use_t;
344  Vector* ips;
345  unsigned long* hfs;
346 
347  if( trace_sphere_collision (mr, t->r, trace, impactpoint))
348  {
349        if( t->n == 0)
350        {
351                setflag (hitflags, t->data.ID);
352                return true;
353        }
354        else
355        {
356                ips = new Vector[t->n];
357                hfs = new unsigned long[t->n];
358                for (i = 0; i < t->n; i++) hfs[i] = 0;
359                for (i = 0; i < t->n; i++)
360                {
361                        r = r || cctree_trace (p, t->data.b[i], &(hfs[i]), trace, &(ips[i]));
362                }
363                if( r)
364                {
365                        float kl = 0.0;
366                        float l = 0.0;
367                        int k = 0;
368                        for (i = 0; i < t->n; i++)
369                        {
370                                if( (kl = (trace->r - ips[i]).len()) > l)
371                                {
372                                        l = kl;
373                                        k = i;
374                                }
375                        }
376                        impactpoint->x = ips[k].x;
377                        impactpoint->y = ips[k].y;
378                        impactpoint->z = ips[k].z;
379                        *hitflags = hfs[k];
380                }
381                delete ips;
382                delete hfs;
383        }
384        return r;
385  }
386 
387  return false;
388}
Note: See TracBrowser for help on using the repository browser.