Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/chris/src/collision.cc @ 2080

Last change on this file since 2080 was 2012, checked in by chris, 21 years ago

orxonox/branches/chris: Improved doxygen compatibility again

File size: 9.4 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
179bool cctree_iterate(const Placement* pa, CC_Tree* ta, unsigned long* ahitflags, const Placement* pb, CC_Tree* tb, unsigned long* bhitflags)
180{
181  bool r = false;
182  int ia, ib;
183  Vector mra = pa->r + rotate_vector( ta->m, pa->w);
184  Vector mrb = pb->r + rotate_vector( tb->m, pb->w);
185  CC_Tree* use_a, *use_b;
186 
187  if( use_a == NULL || use_b == NULL) return false;
188 
189  if( sphere_sphere_collision( mra, ta->r, mrb, tb->r))
190  {
191    if( ta->n == 0 && tb->n == 0)
192    {
193      setflag( ahitflags, ta->data.ID);
194      setflag( bhitflags, tb->data.ID);
195      return true;
196    }
197    for( ia = 0; ia < ta->n || ta->n == 0; ia++)
198    {
199      if( ta->n == 0) use_a = ta;
200      else use_a = ta->data.b[ia];
201      for( ib = 0; ib < tb->n || ta->n == 0; ib++)
202      {
203        if( ta->n == 0) use_b = ta;
204        else use_b = ta->data.b[ib];
205       
206        r = r || cctree_iterate( pa, use_a, ahitflags, pb, use_b, bhitflags);
207       
208        if( tb->n == 0) break;
209      }
210      if( ta->n == 0) break;
211    }
212    return r;
213  }
214 
215  return false;
216}
217
218/**
219   \brief sets the <ID>th flag in flags
220   \param flags: pointer to the long used for flagging
221   \param ID: number of the flag to be set
222*/
223void setflag( unsigned long* flags, unsigned long ID)
224{
225  unsigned long f;
226  f = 1;
227  for( int i = 0; i < ID; i++)
228  {
229    f *= 2;
230  }
231  *flags = *flags | f;
232  return;
233}
234
235/**
236   \brief frees the memory allocated in a CC_Tree
237*/
238void free_CC_Tree( CC_Tree* tree)
239{
240  if (tree == NULL) return;
241  for (int i = 0; i < tree->n; i++)
242  {
243    free_CC_Tree( tree->data.b[i]);
244  }
245  free( tree);
246}
247
248/**
249   \brief loads a CC_Tree from a stream
250*/
251CC_Tree* load_CC_Tree (FILE* stream)
252{
253  CC_Tree* tree = NULL;
254  CC_Tree** branches = NULL;
255  float buf[4];
256  unsigned long n;
257  unsigned long ID;
258 
259  // first load vector and radius
260  if (fread( buf, sizeof (float), 4, stream) != 4) return NULL;
261  // then the amount of subbranches
262  if (fread( &n, sizeof(unsigned long), 1, stream) != 1) return NULL;
263  // then ID or the subbranches
264  if ( n == 0)
265  {
266    if (fread( &ID, sizeof(unsigned long), 1, stream) != 1) return NULL;
267  }
268  else
269  {
270    branches = (CC_Tree**)malloc( sizeof(CC_Tree*) * n);
271    for( int i = 0; i < n; i++)
272    {
273      if ((branches[i] = load_CC_Tree (stream)) == NULL)
274      {
275        for( int j = 0; j < i; j++)
276        {
277          free_CC_Tree (branches[j]);
278          free (branches);
279          return NULL;
280        }
281      }
282    }
283  }
284 
285  // assemble
286  tree = (CC_Tree*) malloc (sizeof(CC_Tree));
287  tree->m.x = buf[0];
288  tree->m.y = buf[1];
289  tree->m.z = buf[2];
290  tree->r = buf[3];
291  tree->n = n;
292  if( n == 0) tree->data.ID = ID;
293  else tree->data.b = branches;
294 
295  // then return
296  return tree;
297}
298
299/**
300   \brief saves a CC_Tree to a stream
301*/
302int save_CC_Tree (CC_Tree* tree, FILE* stream)
303{
304  float buf[4];
305 
306  buf[0] = tree->m.x;
307  buf[1] = tree->m.y;
308  buf[2] = tree->m.z;
309  buf[3] = tree->r;
310 
311  // first save vector and radius
312  if (fwrite( buf, sizeof (float), 4, stream) != 4) return -1;
313  // then the amount of subbranches
314  if (fwrite( &(tree->n), sizeof(unsigned long), 1, stream) != 1) return -1;
315  // then ID or the subbranches
316  if ( tree->n == 0)
317  {
318    if (fwrite( &(tree->data.ID), sizeof(unsigned long), 1, stream) != 1) return -1;
319  }
320  else
321  {
322    for( int i = 0; i < tree->n; i++)
323    {
324      if ( save_CC_Tree (tree->data.b[i], stream) == -1) return -1;
325    }
326  }
327   
328  // then return
329  return 0;
330}
331
332bool cctree_trace( const Placement* p, CC_Tree* t, unsigned long* hitflags, const Line* trace, Vector* impactpoint)
333{
334  bool r = false;
335  int i;
336  Vector mr = p->r + rotate_vector( t->m, p->w);
337  CC_Tree* use_t;
338  Vector* ips;
339  unsigned long* hfs;
340 
341  if( trace_sphere_collision (mr, t->r, trace, impactpoint))
342  {
343        if( t->n == 0)
344        {
345                setflag (hitflags, t->data.ID);
346                return true;
347        }
348        else
349        {
350                ips = new Vector[t->n];
351                hfs = new unsigned long[t->n];
352                for (i = 0; i < t->n; i++) hfs[i] = 0;
353                for (i = 0; i < t->n; i++)
354                {
355                        r = r || cctree_trace (p, t->data.b[i], &(hfs[i]), trace, &(ips[i]));
356                }
357                if( r)
358                {
359                        float kl = 0.0;
360                        float l = 0.0;
361                        int k = 0;
362                        for (i = 0; i < t->n; i++)
363                        {
364                                if( (kl = (trace->r - ips[i]).len()) > l)
365                                {
366                                        l = kl;
367                                        k = i;
368                                }
369                        }
370                        impactpoint->x = ips[k].x;
371                        impactpoint->y = ips[k].y;
372                        impactpoint->z = ips[k].z;
373                        *hitflags = hfs[k];
374                }
375                delete ips;
376                delete hfs;
377        }
378        return r;
379  }
380 
381  return false;
382}
Note: See TracBrowser for help on using the repository browser.