Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/chris: Implemented traceing (line-sphere collision)

File size: 6.7 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
24CollisionCluster::CollisionCluster (float rad = 1.0, Vector mid = Vector(0,0,0))
25{
26  root = (CC_Tree*) malloc( sizeof( CC_Tree));
27  root->n = 0;
28  root->data.ID = 0;
29  root->r = rad;
30  root->m = mid;
31}
32
33CollisionCluster::CollisionCluster (char* filename)
34{
35  FILE* stream;
36  char hbuffer[3];
37  stream = fopen (filename, "rb");
38  if( stream == NULL)
39  {
40    root = NULL;
41    return;
42  }
43  if( fread (hbuffer, sizeof( char), 2, stream) != 2)
44  {
45    root = NULL;
46    return;
47  }
48 
49  hbuffer[2] = 0;
50  if( strcmp (hbuffer, "CC"))
51  {
52    root = NULL;
53    return;
54  }
55 
56  root = load_CC_Tree (stream);
57  fclose (stream);
58}
59
60CollisionCluster::~CollisionCluster ()
61{
62  free_CC_Tree( root);
63}
64
65int CollisionCluster::store (char* filename)
66{
67  int r;
68  FILE* stream;
69  stream = fopen( filename, "wb");
70  if( stream == NULL) return -1;
71  r = save_CC_Tree (root, stream);
72  fclose (stream);
73  return r;
74}
75
76bool check_trace (const Placement* pa, const CollisionCluster* a, unsigned long* ahitflags, const Line* trace, Vector* impactpoint)
77{
78        CC_Tree* t;
79        if( (t = a->root) == NULL) return false;
80       
81  return cctree_trace( pa, t, ahitflags, trace, impactpoint);
82}
83
84bool check_collision (const Placement* pa, const CollisionCluster* a, unsigned long* ahitflags, const Placement* pb, const CollisionCluster* b, unsigned long* bhitflags)
85{
86  CC_Tree* ta, *tb;
87  if( (ta = a->root) == NULL) return false;
88  if( (tb = b->root) == NULL) return false;
89 
90  return cctree_iterate(pa, ta, ahitflags, pb, tb, bhitflags);
91}
92
93bool sphere_sphere_collision( Vector m1, float r1, Vector m2, float r2)
94{
95  if ((m1-m2).len() < r1+r2) return true;
96  return false;
97}
98
99bool trace_sphere_collision( Vector m, float r, const Line* l, Vector* impactpoint)
100{
101  float A, B, C, D, t[2];
102  Vector d = l->r - m;
103  int i;
104 
105  A = l->a * l->a;
106  B = 2 * (l->a * d);
107  C = (d*d) - r*r;
108  D = B*B - 4*A*C;
109 
110  if (D < 0) return false;
111 
112  t[0] = (-B+sqrt(D))/(2*A);
113  t[1] = (-B-sqrt(D))/(2*A);
114 
115  if( (t[0] > 1 || t[0] < 0) && (t[1] < 0 || t[1] > 1)) return false;
116  if( t[0] > t[1]) i = 0;
117  else i = 1;
118
119  impactpoint->x = (l->r + (l->a * t[i])).x;
120  impactpoint->y = (l->r + (l->a * t[i])).y;
121  impactpoint->z = (l->r + (l->a * t[i])).z;
122 
123  return true;
124}
125
126bool cctree_iterate(const Placement* pa, CC_Tree* ta, unsigned long* ahitflags, const Placement* pb, CC_Tree* tb, unsigned long* bhitflags)
127{
128  bool r = false;
129  int ia, ib;
130  Vector mra = pa->r + rotate_vector( ta->m, pa->w);
131  Vector mrb = pb->r + rotate_vector( tb->m, pb->w);
132  CC_Tree* use_a, *use_b;
133 
134  if( use_a == NULL || use_b == NULL) return false;
135 
136  if( sphere_sphere_collision( mra, ta->r, mrb, tb->r))
137  {
138    if( ta->n == 0 && tb->n == 0)
139    {
140      setflag( ahitflags, ta->data.ID);
141      setflag( bhitflags, tb->data.ID);
142      return true;
143    }
144    for( ia = 0; ia < ta->n || ta->n == 0; ia++)
145    {
146      if( ta->n == 0) use_a = ta;
147      else use_a = ta->data.b[ia];
148      for( ib = 0; ib < tb->n || ta->n == 0; ib++)
149      {
150        if( ta->n == 0) use_b = ta;
151        else use_b = ta->data.b[ib];
152       
153        r = r || cctree_iterate( pa, use_a, ahitflags, pb, use_b, bhitflags);
154       
155        if( tb->n == 0) break;
156      }
157      if( ta->n == 0) break;
158    }
159    return r;
160  }
161 
162  return false;
163}
164
165void setflag( unsigned long* flags, unsigned long ID)
166{
167  unsigned long f;
168  f = 1;
169  for( int i = 0; i < ID; i++)
170  {
171    f *= 2;
172  }
173  *flags = *flags | f;
174  return;
175}
176
177void free_CC_Tree( CC_Tree* tree)
178{
179  if (tree == NULL) return;
180  for (int i = 0; i < tree->n; i++)
181  {
182    free_CC_Tree( tree->data.b[i]);
183  }
184  free( tree);
185}
186
187CC_Tree* load_CC_Tree (FILE* stream)
188{
189  CC_Tree* tree = NULL;
190  CC_Tree** branches = NULL;
191  float buf[4];
192  unsigned long n;
193  unsigned long ID;
194 
195  // first load vector and radius
196  if (fread( buf, sizeof (float), 4, stream) != 4) return NULL;
197  // then the amount of subbranches
198  if (fread( &n, sizeof(unsigned long), 1, stream) != 1) return NULL;
199  // then ID or the subbranches
200  if ( n == 0)
201  {
202    if (fread( &ID, sizeof(unsigned long), 1, stream) != 1) return NULL;
203  }
204  else
205  {
206    branches = (CC_Tree**)malloc( sizeof(CC_Tree*) * n);
207    for( int i = 0; i < n; i++)
208    {
209      if ((branches[i] = load_CC_Tree (stream)) == NULL)
210      {
211        for( int j = 0; j < i; j++)
212        {
213          free_CC_Tree (branches[j]);
214          free (branches);
215          return NULL;
216        }
217      }
218    }
219  }
220 
221  // assemble
222  tree = (CC_Tree*) malloc (sizeof(CC_Tree));
223  tree->m.x = buf[0];
224  tree->m.y = buf[1];
225  tree->m.z = buf[2];
226  tree->r = buf[3];
227  tree->n = n;
228  if( n == 0) tree->data.ID = ID;
229  else tree->data.b = branches;
230 
231  // then return
232  return tree;
233}
234
235int save_CC_Tree (CC_Tree* tree, FILE* stream)
236{
237  float buf[4];
238 
239  buf[0] = tree->m.x;
240  buf[1] = tree->m.y;
241  buf[2] = tree->m.z;
242  buf[3] = tree->r;
243 
244  // first save vector and radius
245  if (fwrite( buf, sizeof (float), 4, stream) != 4) return -1;
246  // then the amount of subbranches
247  if (fwrite( &(tree->n), sizeof(unsigned long), 1, stream) != 1) return -1;
248  // then ID or the subbranches
249  if ( tree->n == 0)
250  {
251    if (fwrite( &(tree->data.ID), sizeof(unsigned long), 1, stream) != 1) return -1;
252  }
253  else
254  {
255    for( int i = 0; i < tree->n; i++)
256    {
257      if ( save_CC_Tree (tree->data.b[i], stream) == -1) return -1;
258    }
259  }
260   
261  // then return
262  return 0;
263}
264
265bool cctree_trace( const Placement* p, CC_Tree* t, unsigned long* hitflags, const Line* trace, Vector* impactpoint)
266{
267  bool r = false;
268  int i;
269  Vector mr = p->r + rotate_vector( t->m, p->w);
270  CC_Tree* use_t;
271  Vector* ips;
272  unsigned long* hfs;
273 
274  if( trace_sphere_collision (mr, t->r, trace, impactpoint))
275  {
276        if( t->n == 0)
277        {
278                setflag (hitflags, t->data.ID);
279                return true;
280        }
281        else
282        {
283                ips = new Vector[t->n];
284                hfs = new unsigned long[t->n];
285                for (i = 0; i < t->n; i++) hfs[i] = 0;
286                for (i = 0; i < t->n; i++)
287                {
288                        r = r || cctree_trace (p, t->data.b[i], &(hfs[i]), trace, &(ips[i]));
289                }
290                if( r)
291                {
292                        float kl = 0.0;
293                        float l = 0.0;
294                        int k = 0;
295                        for (i = 0; i < t->n; i++)
296                        {
297                                if( (kl = (trace->r - ips[i]).len()) > l)
298                                {
299                                        l = kl;
300                                        k = i;
301                                }
302                        }
303                        impactpoint->x = ips[k].x;
304                        impactpoint->y = ips[k].y;
305                        impactpoint->z = ips[k].z;
306                        *hitflags = hfs[k];
307                }
308                delete ips;
309                delete hfs;
310        }
311        return r;
312  }
313 
314  return false;
315}
Note: See TracBrowser for help on using the repository browser.