Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8059 was 6022, checked in by bensch, 19 years ago

orxonox/trunk: merged the NewModel branche back to the trunk.
merged with command
svn merge branches/newModel/ trunk/ -r 6016:HEAD
no conflicts

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