Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5164 was 5115, checked in by bensch, 19 years ago

orxonox/trunk: reimplemented the list functions, as i did before in revision 5110.
This time, i looked out for the bugs, and i think i found one

@patrick: i know, that you do not want to code at the moment… :/ → see mail

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