Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/graphics/spatial_separation/quadtree_node.cc @ 5232

Last change on this file since 5232 was 5232, checked in by patrick, 19 years ago

orxonox/trunk: solved a memory leak in the QuadtreeNode

File size: 17.7 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Patrick Boenzli
13   co-programmer: ...
14*/
15
16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_SPATIAL_SEPARATION
17
18#include "quadtree_node.h"
19
20#include "quadtree.h"
21#include "material.h"
22#include "abstract_model.h"
23#include "list.h"
24#include "vector.h"
25#include "debug.h"
26
27using namespace std;
28
29
30/**
31 *  standard constructor
32 */
33QuadtreeNode::QuadtreeNode (sTriangleExt** triangles, int numTriangles,
34                            const float* pVertices, int numVertices,
35                            Quadtree* quadtree, QuadtreeNode* parent,
36                            Rectangle* rect, int treeDepth, const int maxDepth, int index
37                           )
38{
39  /* save all important variables localy */
40  this->numTriangles = numTriangles;
41  this->pTriangles = triangles;
42  this->numVertices = numVertices;
43  this->pVertices = pVertices;
44
45  this->quadtree = quadtree;
46  this->parent = parent;
47  this->pDimension = rect;
48  this->treeDepth = treeDepth;
49  this->maxDepth = maxDepth;
50  this->indexNode = index;
51
52  /* debug output */
53  for( int i = 0; i < this->treeDepth; ++i)
54    PRINT(3)(" |");
55  PRINT(3)(" | +-| (Event) Building Node Nr. %i Depth: %i/%i, pointer: %p\n", this->indexNode, treeDepth, maxDepth, this);
56
57  for( int i = 0; i < this->treeDepth; ++i)
58    PRINT(3)(" |");
59  PRINT(3)(" | +-| (II) Rectangle Center (%5.2f, %5.2f), half axis length: %5.2f\n",
60  this->pDimension->getCenter().x, this->pDimension->getCenter().z, this->pDimension->getAxis());
61
62  this->init();
63}
64
65
66/**
67 *  standard constructor
68 */
69QuadtreeNode::QuadtreeNode(modelInfo* pModelInfo, Quadtree* quadtree, const int maxDepth)
70{
71  /* save all important variables localy */
72  this->pModelInfo = pModelInfo;
73  this->quadtree = quadtree;
74  this->maxDepth = maxDepth;
75  this->treeDepth = 0;
76  this->indexNode = 0;
77
78  /* create an array of triangle references */
79  this->pTriangles = new sTriangleExt*[this->pModelInfo->numTriangles];
80  this->numTriangles = this->pModelInfo->numTriangles;
81  this->pVertices = this->pModelInfo->pVertices;
82  this->numVertices = this->pModelInfo->numVertices;
83  for( int i = 0; i < this->pModelInfo->numTriangles; ++i)
84    this->pTriangles[i] = &this->pModelInfo->pTriangles[i];
85
86  /* debug output */
87  for( int i = 0; i < this->treeDepth; ++i)
88    PRINT(3)(" |");
89  PRINT(3)(" | +-| (Event) Building Node Nr. %i Depth: %i/%i, pointer: %p\n", this->indexNode, treeDepth, maxDepth, this);
90
91  /* set some important variables */
92  this->pDimension = this->getDimFromModel();
93
94  this->init();
95}
96
97
98/**
99 *  takes the rest of the initialisation process
100 */
101void QuadtreeNode::init()
102{
103  this->setClassID(CL_QUADTREE_NODE, "QuadtreeNode");
104
105  /* init the rest of the variables for both init types */
106  this->offset = 0.0f;
107  this->nodeIter = -1;
108  this->bDraw = false;
109
110  this->parent = NULL;
111  this->nodeA = NULL;
112  this->nodeB = NULL;
113  this->nodeC = NULL;
114  this->nodeD = NULL;
115  this->nodes = new QuadtreeNode*[4];
116  for(int i = 0; i < 4; ++i)
117    this->nodes[i] = NULL;
118
119  /* now separate the nodes */
120  if( this->treeDepth < this->maxDepth)
121    this->separateNode();
122}
123
124
125/**
126 *  standard deconstructor
127 */
128QuadtreeNode::~QuadtreeNode ()
129{
130  if( this->nodeA != NULL)
131    delete this->nodeA;
132  if( this->nodeB != NULL)
133    delete this->nodeB;
134  if( this->nodeC != NULL)
135    delete this->nodeC;
136  if( this->nodeD != NULL)
137    delete this->nodeD;
138
139  if( this->pTriangles)
140    delete [] this->pTriangles;
141
142  if( this->pDimension)
143    delete this->pDimension;
144}
145
146
147
148/**
149 *  this functions builds up a hash table containing all leafs of the Quadtree in a sorted array
150 * @param nodeList the nodelist array to add them
151 * @param index the current index in the array
152
153  The algorithm used for this purpose is home-brown. its not to fast but and the nodes are not always in the right
154  order. this is why there will be needed a quicksort later on.
155 */
156void QuadtreeNode::buildHashTable(QuadtreeNode** nodeList, int* index)
157{
158  if( this->nodeIter == -1)
159    this->nodeIter = *index;
160
161  /*              offset              #of elements in a row            #of rows in a quadtree          */
162  int threshold = this->nodeIter + (int)pow(2, this->maxDepth) * (int)pow(2, maxDepth - treeDepth - 1);
163  int loopLimit = (*index < threshold)?2:4;
164
165  /* is it a leaf? */
166  if( this->treeDepth < this->maxDepth)
167    for(int i = (*index < threshold)?0:2; i < loopLimit; ++i)
168      this->nodes[i]->buildHashTable(nodeList, index);
169  else
170    nodeList[(*index)++] = this;
171}
172
173
174
175/**
176 *  gives the signal to separate the model into a quadtree
177 * @param treeDepth the max depth, the steps to go if treeDept == 0 leaf reached
178
179 * @todo ATTENION: This function is currently not used and not implemented, but would be a nice addon
180 */
181void QuadtreeNode::separateNode(float minLength)
182{
183  /* dimension calculation & limit checking */
184  if( minLength <= this->pDimension->getAxis())
185    return;
186
187  /* node separation */
188//   this->separateNode();
189//   this->nodeA->separateNode(minLength);
190//   this->nodeB->separateNode(minLength);
191//   this->nodeC->separateNode(minLength);
192//   this->nodeD->separateNode(minLength);
193}
194
195
196/**
197 *  gives the signal to separate the model into a quadtree
198 * @param treeDepth the max depth, the steps to go if treeDept == 0 leaf reached
199 */
200void QuadtreeNode::separateNode()
201{
202  /* separate the four regions into the four lists */
203  tList<sTriangleExt*>*           listA = new tList<sTriangleExt*>();    //!< triangle list of nodeA
204  tList<sTriangleExt*>*           listB = new tList<sTriangleExt*>();    //!< triangle list of nodeB
205  tList<sTriangleExt*>*           listC = new tList<sTriangleExt*>();    //!< triangle list of nodeC
206  tList<sTriangleExt*>*           listD = new tList<sTriangleExt*>();    //!< triangle list of nodeD
207  const float*                    pVert;                                 //!< pointer to the vertices
208  Vector                          rectCenter;                            //!< vector to the center of the rect
209
210  rectCenter = this->pDimension->getCenter();
211  for( int i = 0; i < this->numTriangles; ++i)
212  {
213    for( int j = 0; j < 3; ++j)
214    {
215      pVert = &this->pVertices[this->pTriangles[i]->indexToVertices[j]];
216      if( pVert[0] > rectCenter.x + this->offset && pVert[2] > rectCenter.z + this->offset)
217        listA->add(&this->pTriangles[i]);
218      if( pVert[0] < rectCenter.x + this->offset && pVert[2] > rectCenter.z + this->offset)
219        listB->add(&this->pTriangles[i]);
220      if( pVert[0] < rectCenter.x + this->offset && pVert[2] < rectCenter.z + this->offset)
221        listC->add(&this->pTriangles[i]);
222      if( pVert[0] > rectCenter.x + this->offset && pVert[2] < rectCenter.z + this->offset)
223        listD->add(&this->pTriangles[i]);
224    }
225  }
226  for( int i = 0; i < treeDepth; ++i)
227    PRINT(3)(" |");
228  PRINT(3)(" | +-| (II) Quadtree Counts - separating: A: %i, B: %i, C: %i, D: %i\n", listA->getSize(), listB->getSize(), listC->getSize(), listD->getSize());
229
230
231  /* Separating into to the triangle arrays */
232  sTriangleExt**                 pTriA;                                 //!< Triangle array A
233  sTriangleExt**                 pTriB;                                 //!< Triangle array B
234  sTriangleExt**                 pTriC;                                 //!< Triangle array C
235  sTriangleExt**                 pTriD;                                 //!< Triangle array D
236  int                            lenA;                                  //!< length array A
237  int                            lenB;                                  //!< length array B
238  int                            lenC;                                  //!< length array C
239  int                            lenD;                                  //!< length array D
240  tIterator<sTriangleExt*>*      iterator;                              //!< iterator for the list iterations
241  sTriangleExt**                 tempTri;                               //!< temp save place for triangle pointer
242  int                            counter;                               //!< counter for the while loops
243
244  lenA = listA->getSize();
245  lenB = listB->getSize();
246  lenC = listC->getSize();
247  lenD = listD->getSize();
248
249  pTriA = new sTriangleExt*[listA->getSize()];
250  pTriB = new sTriangleExt*[listB->getSize()];
251  pTriC = new sTriangleExt*[listC->getSize()];
252  pTriD = new sTriangleExt*[listD->getSize()];
253
254  counter = 0;
255  iterator = listA->getIterator();
256  tempTri = iterator->firstElement();
257  while( tempTri)
258  {
259    pTriA[counter] = *tempTri;
260    tempTri = iterator->nextElement();
261    ++counter;
262  }
263  delete iterator;
264
265  counter = 0;
266  iterator = listB->getIterator();
267  tempTri = iterator->firstElement();
268  while( tempTri)
269  {
270    pTriB[counter] = *tempTri;
271    tempTri = iterator->nextElement();
272    ++counter;
273  }
274  delete iterator;
275
276  counter = 0;
277  iterator = listC->getIterator();
278  tempTri = iterator->firstElement();
279  while( tempTri)
280  {
281    pTriC[counter] = *tempTri;
282    tempTri = iterator->nextElement();
283    ++counter;
284  }
285  delete iterator;
286
287  counter = 0;
288  iterator = listD->getIterator();
289  tempTri = iterator->firstElement();
290  while( tempTri)
291  {
292    pTriD[counter] = *tempTri;
293    tempTri = iterator->nextElement();
294    ++counter;
295  }
296  delete iterator;
297
298  /* now do cleanup */
299  delete listA;
300  delete listB;
301  delete listC;
302  delete listD;
303
304
305  /* now create the rectangle dimensions */
306  Vector                     v;                                                             //!< temp saving place
307  Rectangle*                 rA;                                                            //!< new size of the node A
308  Rectangle*                 rB;                                                            //!< new size of the node B
309  Rectangle*                 rC;                                                            //!< new size of the node C
310  Rectangle*                 rD;                                                            //!< new size of the node D
311
312
313  v.x = this->pDimension->getCenter().x + this->pDimension->getAxis() / 2.0f;
314  v.y = 0.0;
315  v.z = this->pDimension->getCenter().z + this->pDimension->getAxis() / 2.0f;
316  rA = new Rectangle(v, this->pDimension->getAxis() / 2.0f);
317  v.z = this->pDimension->getCenter().z - this->pDimension->getAxis() / 2.0f;
318  rB = new Rectangle(v, this->pDimension->getAxis() / 2.0f);
319  v.x = this->pDimension->getCenter().x - this->pDimension->getAxis() / 2.0f;
320  rC = new Rectangle(v, this->pDimension->getAxis() / 2.0f);
321  v.z = this->pDimension->getCenter().z + this->pDimension->getAxis() / 2.0f;
322  rD = new Rectangle(v, this->pDimension->getAxis() / 2.0f);
323
324  /* now create the new nodes  */
325  this->nodeA = new QuadtreeNode(pTriA, lenA, this->pVertices, this->numVertices, this->quadtree, this, rA, this->treeDepth + 1, this->maxDepth, (this->treeDepth + 1) * 10 + 0);
326  this->nodeB = new QuadtreeNode(pTriB, lenB, this->pVertices, this->numVertices, this->quadtree, this, rB, this->treeDepth + 1, this->maxDepth, (this->treeDepth + 1) * 10 + 1);
327  this->nodeC = new QuadtreeNode(pTriC, lenC, this->pVertices, this->numVertices, this->quadtree, this, rC, this->treeDepth + 1, this->maxDepth, (this->treeDepth + 1) * 10 + 2);
328  this->nodeD = new QuadtreeNode(pTriD, lenD, this->pVertices, this->numVertices, this->quadtree, this, rD, this->treeDepth + 1, this->maxDepth, (this->treeDepth + 1) * 10 + 3);
329
330  /* map the array references, this is for faster and automatical interfacing  \todo: use only array */
331  this->nodes[0] = this->nodeA;
332  this->nodes[1] = this->nodeB;
333  this->nodes[2] = this->nodeC;
334  this->nodes[3] = this->nodeD;
335}
336
337
338/**
339 *  gets the maximal dimension of a model
340 * @return the dimension of the AbstractModel as a Rectangle
341
342   The rectangle is x-z axis aligned. ATTENTION: if there are any vertices in the model, that exceed the
343   size of 999999.0, there probably will be some errors in the dimensions calculations. Write an email to
344   patrick@orxonox.ethz.ch if you will ever encounter a model bigger than 999999.0 units, I will realy be
345   happy to see orxonox used to extensivly :)
346 */
347Rectangle* QuadtreeNode::getDimFromModel()
348{
349  float            maxX, maxY;                       //!< the maximal coordinates axis
350  float            minX, minY;                       //!< minimal axis coorindates
351  const float*     pVertices;                        //!< pointer to the current vertices
352
353  maxX = -999999; maxY = -999999;
354  minX =  999999; minY =  999999;
355  /* get maximal/minimal x/y */
356  for( int i = 0; i < this->numTriangles; ++i)
357  {
358    for( int j = 0; j < 3; ++j)
359    {
360
361      pVertices = &this->pVertices[this->pTriangles[i]->indexToVertices[j]];
362      if( pVertices[0] > maxX)
363        maxX = pVertices[0];
364      if( pVertices[2] > maxY)
365        maxY = pVertices[2];
366
367      if( pVertices[0] < minX)
368        minX = pVertices[0];
369      if( pVertices[2] < minY)
370        minY = pVertices[2];
371    }
372  }
373
374  Rectangle* rect = new Rectangle();
375  rect->setCenter((maxX + minX) / 2.0f, 0.0f, (maxY + minY) / 2.0f); /* this is little strange, since y is in opengl the up vector */
376  rect->setAxis(fmax(((fabs(maxX) + fabs(minX)) / 2.0f), ((fabs(maxY) + fabs(minY)) / 2.0f)));
377
378  for( int i = 0; i < this->treeDepth; ++i)
379    PRINT(3)(" |");
380  PRINT(3)(" | +-| (II) Rectangle Dimension  (%5.2f, %5.2f) to (%5.2f, %5.2f), Center (%5.2f, %5.2f)\n", minX, minY, maxX, maxY, rect->getCenter().x, rect->getCenter().z, rect->getAxis());
381  return rect;
382}
383
384
385 /**
386 * checks if a point is included in this quadtree
387 * @param v the vector to be checked
388 * @returns true if the vector is included
389  */
390bool QuadtreeNode::includesPoint(const Vector& v) const
391{
392  Vector center = this->pDimension->getCenter();
393  float ax = this->pDimension->getAxis();
394
395  if( v.x > center.x - ax && v.x < center.x + ax &&
396      v.z > center.z - ax && v.z < center.z + ax )
397    return true;
398  return false;
399}
400
401
402
403float QuadtreeNode::getHeight(const Vector& position) const
404{
405  Vector a, b, c;
406  sTriangleExt* tri;
407
408  for( int i = 0; i < this->numTriangles; ++i)
409  {
410    a = *(sVec3D*)&this->pVertices[this->pTriangles[i]->indexToVertices[0]];
411    b = *(sVec3D*)&this->pVertices[this->pTriangles[i]->indexToVertices[1]];
412    c = *(sVec3D*)&this->pVertices[this->pTriangles[i]->indexToVertices[2]];
413
414    if( unlikely(this->pointInTriangle(position, a, b, c)))
415    {
416      tri = this->pTriangles[i];
417      break;
418    }
419  }
420
421  /* calculate height out of the data collected above */
422
423}
424
425
426/**
427 *  get triangles that includes the position
428 * @param position the position that is going to be checked
429 * @returns the triangle in which the position is included, NULL if there is no such triangle
430
431 There is some random behaviour if there are more than one triangle at the same y
432 coordinate. At the moment the function just takes the first triangle, that included the
433 vector
434 */
435sTriangleExt* QuadtreeNode::getTriangle(const Vector& position) const
436{
437  Vector a, b, c;
438  PRINTF(0)("Get Triangle, %i\n", this->numTriangles);
439
440  for( int i = 0; i < numTriangles; ++i)
441    {
442
443      a = *(sVec3D*)&this->pVertices[this->pTriangles[i]->indexToVertices[0]];
444      b = *(sVec3D*)&this->pVertices[this->pTriangles[i]->indexToVertices[1]];
445      c = *(sVec3D*)&this->pVertices[this->pTriangles[i]->indexToVertices[2]];
446
447      if( unlikely(this->pointInTriangle(position, a, b, c)))
448        return this->pTriangles[i];
449
450    }
451  return NULL;
452}
453
454
455/**
456 *  checks if the point is in the triangle
457 * @param point to be checked
458 * @param rectangle edge a
459 * @param rectangle edge b
460 * @param rectangle edge c
461 * @returns true if the point is inside
462 */
463bool QuadtreeNode::pointInTriangle(const Vector&p, const Vector& a, const Vector& b, const Vector& c) const
464{
465
466  PRINTF(0)("p: (%f, %f, %f)\n", p.x, p.y, p.z);
467  PRINTF(0)("a: (%f, %f, %f)\n", a.x, a.y, a.z);
468  PRINTF(0)("b: (%f, %f, %f)\n", b.x, b.y, b.z);
469  PRINTF(0)("c: (%f, %f, %f)\n", c.x, c.y, c.z);
470
471  if( this->sameSide(p, a, b, c) && this->sameSide(p, b, a, c) && sameSide(p, c, a, b))
472    return true;
473  return false;
474}
475
476
477/**
478 *  checks if two points are on the same side
479 * @param point one to be checked
480 * @param point two to be checked
481 * @param begining point of the line
482 * @param end of the line
483 */
484bool QuadtreeNode::sameSide(const Vector& p1, const Vector&p2, const Vector& a, const Vector& b) const
485{
486  Vector cp1 = (b - a).cross(p1 - a);
487  Vector cp2 = (b - a).cross(p2 - a);
488
489  if( unlikely(cp1.dot(cp2) >= 0)) return true;
490  return false;
491}
492
493
494/**
495 *  draws all the debug quadtree squares
496 */
497void QuadtreeNode::drawTree() const
498{
499  if( this->treeDepth == this->maxDepth)
500  {
501    Vector t1 = this->pDimension->getCenter();
502    float ax = this->pDimension->getAxis();
503    float h = 50.0f;
504
505    this->quadtree->getMaterial(this->indexNode)->select();
506    glBegin(GL_QUADS);
507    glVertex3f(t1.x + ax, h - this->treeDepth * 10.0f, t1.z + ax);
508    glVertex3f(t1.x - ax, h - this->treeDepth * 10.0f, t1.z + ax);
509    glVertex3f(t1.x - ax, h - this->treeDepth * 10.0f, t1.z - ax);
510    glVertex3f(t1.x + ax, h - this->treeDepth * 10.0f, t1.z - ax);
511    glEnd();
512  }
513
514
515  if( this->nodeA != NULL)
516    this->nodeA->drawTree();
517  if( this->nodeB != NULL)
518    this->nodeB->drawTree();
519  if( this->nodeC != NULL)
520    this->nodeC->drawTree();
521  if( this->nodeD != NULL)
522    this->nodeD->drawTree();
523}
524
525
526/**
527 *  draws only this quadtree square
528 */
529void QuadtreeNode::draw() const
530{
531  if( likely(!this->bDraw))
532    return;
533
534  Vector t1 = this->pDimension->getCenter();
535  float ax = this->pDimension->getAxis();
536  float h = 70.0f;
537
538  glBegin(GL_QUADS);
539  this->quadtree->getMaterial(this->indexNode)->select();
540
541  glVertex3f(t1.x + ax, h, t1.z + ax);
542  glVertex3f(t1.x - ax, h, t1.z + ax);
543  glVertex3f(t1.x - ax, h, t1.z - ax);
544  glVertex3f(t1.x + ax, h, t1.z - ax);
545
546  glEnd();
547}
Note: See TracBrowser for help on using the repository browser.