Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: some fixeds in the quadtree framework. No debug draw anymore

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