Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: added the last functions needed to get the heigt from the terrain. test phase now

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