source: GTP/trunk/Lib/Vis/Preprocessing/src/KdTree.cpp @ 2015

Revision 2015, 35.5 KB checked in by bittner, 17 years ago (diff)

pvs efficiency tuning

RevLine 
[372]1#include <stack>
2#include <algorithm>
3#include <queue>
4#include "Environment.h"
5#include "Mesh.h"
6#include "KdTree.h"
[469]7#include "ViewCell.h"
[505]8#include "Beam.h"
[372]9
10
[1989]11// $$JB HACK
12#define KD_PVS_AREA (1e-5f)
[372]13
[863]14namespace GtpVisibilityPreprocessor {
[860]15
[1176]16int KdNode::sMailId = 1;
17int KdNode::sReservedMailboxes = 1;
[863]18
[1197]19inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
20{
21        return obj1->mId < obj2->mId;
22}
23
24
[1761]25KdNode::KdNode(KdInterior *parent):mParent(parent), mMailbox(0), mIntersectable(NULL)
26
[372]27{
28  if (parent)
29    mDepth = parent->mDepth+1;
30  else
31    mDepth = 0;
32}
33
[1002]34
35KdInterior::~KdInterior()
36{
37        // recursivly destroy children
38        DEL_PTR(mFront);
39        DEL_PTR(mBack);
40}
41
42
[1999]43KdLeaf::~KdLeaf()
44{
45        DEL_PTR(mViewCell); 
46}
47
48
[372]49KdTree::KdTree()
50{
[878]51
52 
[372]53  mRoot = new KdLeaf(NULL, 0);
[1004]54  Environment::GetSingleton()->GetIntValue("KdTree.Termination.maxNodes", mTermMaxNodes);
55  Environment::GetSingleton()->GetIntValue("KdTree.Termination.maxDepth", mTermMaxDepth);
56  Environment::GetSingleton()->GetIntValue("KdTree.Termination.minCost", mTermMinCost);
57  Environment::GetSingleton()->GetFloatValue("KdTree.Termination.maxCostRatio", mMaxCostRatio);
58  Environment::GetSingleton()->GetFloatValue("KdTree.Termination.ct_div_ci", mCt_div_ci);
59  Environment::GetSingleton()->GetFloatValue("KdTree.splitBorder", mSplitBorder);
[372]60
[1004]61  Environment::GetSingleton()->GetBoolValue("KdTree.sahUseFaces", mSahUseFaces);
[372]62
63  char splitType[64];
[1004]64  Environment::GetSingleton()->GetStringValue("KdTree.splitMethod", splitType);
[372]65 
66  mSplitMethod = SPLIT_SPATIAL_MEDIAN;
67  if (strcmp(splitType, "spatialMedian") == 0)
68    mSplitMethod = SPLIT_SPATIAL_MEDIAN;
69  else
70    if (strcmp(splitType, "objectMedian") == 0)
71      mSplitMethod = SPLIT_OBJECT_MEDIAN;
72    else
73      if (strcmp(splitType, "SAH") == 0)
74        mSplitMethod = SPLIT_SAH;
75      else {
76        cerr<<"Wrong kd split type "<<splitType<<endl;
77        exit(1);
78      }
79  splitCandidates = NULL;
80}
81
[1002]82
83KdTree::~KdTree()
84{
[1999]85    DEL_PTR(mRoot);
86
87        CLEAR_CONTAINER(mKdIntersectables);
[1002]88}
89
90
[372]91bool
92KdTree::Construct()
93{
[1076]94
[372]95  if (!splitCandidates)
[2003]96    splitCandidates = new vector<SortableEntry *>;
[372]97
98  // first construct a leaf that will get subdivide
99  KdLeaf *leaf = (KdLeaf *) mRoot;
100
101  mStat.nodes = 1;
102
103  mBox.Initialize();
104  ObjectContainer::const_iterator mi;
105  for ( mi = leaf->mObjects.begin();
106        mi != leaf->mObjects.end();
107        mi++) {
[752]108        //      cout<<(*mi)->GetBox()<<endl;
109        mBox.Include((*mi)->GetBox());
[372]110  }
111
[752]112  cout <<"KdTree Root Box:"<<mBox<<endl;
[372]113  mRoot = Subdivide(TraversalData(leaf, mBox, 0));
114
115  // remove the allocated array
[2003]116  CLEAR_CONTAINER(*splitCandidates);
[372]117  delete splitCandidates;
118
[1989]119  float area = GetBox().SurfaceArea()*KD_PVS_AREA;
120
121  SetPvsTerminationNodes(area);
122 
[372]123  return true;
124}
125
126KdNode *
127KdTree::Subdivide(const TraversalData &tdata)
128{
129
130  KdNode *result = NULL;
131
132  priority_queue<TraversalData> tStack;
133  //  stack<STraversalData> tStack;
134 
135  tStack.push(tdata);
136  AxisAlignedBox3 backBox, frontBox;
137
138  while (!tStack.empty()) {
[752]139        //      cout<<mStat.Nodes()<<" "<<mTermMaxNodes<<endl;
140        if (mStat.Nodes() > mTermMaxNodes) {
141          //    if ( GetMemUsage() > maxMemory ) {
[372]142      // count statistics on unprocessed leafs
143      while (!tStack.empty()) {
[752]144                EvaluateLeafStats(tStack.top());
145                tStack.pop();
[372]146      }
147      break;
148    }
[752]149         
150       
[372]151    TraversalData data = tStack.top();
152    tStack.pop();
153   
154    KdNode *node = SubdivideNode((KdLeaf *) data.mNode,
[752]155                                                                 data.mBox,
156                                                                 backBox,
157                                                                 frontBox
158                                                                 );
159
160        if (result == NULL)
[372]161      result = node;
162   
163    if (!node->IsLeaf()) {
164
165      KdInterior *interior = (KdInterior *) node;
166      // push the children on the stack
167      tStack.push(TraversalData(interior->mBack, backBox, data.mDepth+1));
168      tStack.push(TraversalData(interior->mFront, frontBox, data.mDepth+1));
169     
170    } else {
171      EvaluateLeafStats(data);
172    }
173  }
174 
175  return result;
176
177}
178
179
180
181bool
182KdTree::TerminationCriteriaMet(const KdLeaf *leaf)
183{
184  //  cerr<<"\n OBJECTS="<<leaf->mObjects.size()<<endl;
185  return
[1108]186    ((int)leaf->mObjects.size() <= mTermMinCost) ||
[372]187    (leaf->mDepth >= mTermMaxDepth);
188 
189}
190
191
192int
193KdTree::SelectPlane(KdLeaf *leaf,
[752]194                                        const AxisAlignedBox3 &box,
195                                        float &position
196                                        )
[372]197{
198  int axis = -1;
199 
200  switch (mSplitMethod)
201    {
202    case SPLIT_SPATIAL_MEDIAN: {
203      axis = box.Size().DrivingAxis();
204      position = (box.Min()[axis] + box.Max()[axis])*0.5f;
205      break;
206    }
207    case SPLIT_SAH: {
208      int objectsBack, objectsFront;
209      float costRatio;
[1584]210      bool mOnlyDrivingAxis = true;
[1387]211
212          if (mOnlyDrivingAxis) {
[752]213                axis = box.Size().DrivingAxis();
214                costRatio = BestCostRatio(leaf,
215                                                                  box,
216                                                                  axis,
217                                                                  position,
218                                                                  objectsBack,
219                                                                  objectsFront);
[372]220      } else {
[752]221                costRatio = MAX_FLOAT;
222                for (int i=0; i < 3; i++) {
223                  float p;
224                  float r = BestCostRatio(leaf,
225                                                                  box,
226                                                                  i,
227                                                                  p,
228                                                                  objectsBack,
229                                                                  objectsFront);
230                  if (r < costRatio) {
231                        costRatio = r;
232                        axis = i;
233                        position = p;
234                  }
235                }
[372]236      }
237     
238      if (costRatio > mMaxCostRatio) {
[752]239                //cout<<"Too big cost ratio "<<costRatio<<endl;
240                axis = -1;
[372]241      }
242      break;
243    }
244   
245    }
246  return axis;
247}
248
249KdNode *
250KdTree::SubdivideNode(
251                      KdLeaf *leaf,
252                      const AxisAlignedBox3 &box,
253                      AxisAlignedBox3 &backBBox,
254                      AxisAlignedBox3 &frontBBox
255                      )
256{
257 
258  if (TerminationCriteriaMet(leaf))
[469]259          return leaf;
260
[372]261  float position;
262 
263  // select subdivision axis
264  int axis = SelectPlane( leaf, box, position );
265
266  if (axis == -1) {
267    return leaf;
268  }
269 
270  mStat.nodes+=2;
271  mStat.splits[axis]++;
272 
273  // add the new nodes to the tree
274  KdInterior *node = new KdInterior(leaf->mParent);
275
276  node->mAxis = axis;
277  node->mPosition = position;
278  node->mBox = box;
279 
280  backBBox = box;
281  frontBBox = box;
282 
283  // first count ray sides
284  int objectsBack = 0;
285  int objectsFront = 0;
286 
287  backBBox.SetMax(axis, position);
288  frontBBox.SetMin(axis, position);
289
290  ObjectContainer::const_iterator mi;
291
292  for ( mi = leaf->mObjects.begin();
293        mi != leaf->mObjects.end();
294        mi++) {
295    // determine the side of this ray with respect to the plane
296    AxisAlignedBox3 box = (*mi)->GetBox();
297    if (box.Max(axis) > position )
298      objectsFront++;
299   
300    if (box.Min(axis) < position )
301      objectsBack++;
302  }
303
304 
305  KdLeaf *back = new KdLeaf(node, objectsBack);
306  KdLeaf *front = new KdLeaf(node, objectsFront);
307
[1074]308 
[372]309  // replace a link from node's parent
310  if (  leaf->mParent )
311    leaf->mParent->ReplaceChildLink(leaf, node);
312
313  // and setup child links
314  node->SetupChildLinks(back, front);
315 
316  for (mi = leaf->mObjects.begin();
317       mi != leaf->mObjects.end();
318       mi++) {
319    // determine the side of this ray with respect to the plane
320    AxisAlignedBox3 box = (*mi)->GetBox();
[1736]321       
322        // matt: no more ref
[1143]323        // for handling multiple objects: keep track of references
[1736]324        //if (leaf->IsRoot())
325        //      (*mi)->mReferences = 1; // initialise references at root
[1143]326       
[1736]327        // matt: no more ref
328        //-- (*mi)->mReferences; // remove parent ref
[372]329
[1143]330
331        if (box.Max(axis) >= position )
332        {
[372]333      front->mObjects.push_back(*mi);
[1736]334          //++ (*mi)->mReferences;
[1143]335        }
336       
[372]337    if (box.Min(axis) < position )
[1143]338        {
[372]339      back->mObjects.push_back(*mi);
[1736]340        // matt: no more ref
341        //  ++ (*mi)->mReferences;
[1143]342        }
343
[1144]344    mStat.objectRefs -= (int)leaf->mObjects.size();
345    mStat.objectRefs += objectsBack + objectsFront;
346  }
347
[1143]348        // store objects referenced in more than one leaf
349        // for easy access
350        ProcessMultipleRefs(back);
351        ProcessMultipleRefs(front);
352
[1286]353        delete leaf;
354        return node;
[372]355}
356
357
[1143]358void KdTree::ProcessMultipleRefs(KdLeaf *leaf) const
359{
360        // find objects from multiple kd-leaves
361        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
362
363        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
364        {
365                Intersectable *object = *oit;
366               
[1736]367                // matt: no more ref
368                /*if (object->mReferences > 1)
[1143]369                {
370                        leaf->mMultipleObjects.push_back(object);
[1736]371                }*/
[1143]372        }
373}
374
375
[372]376void
377KdTreeStatistics::Print(ostream &app) const
378{
379  app << "===== KdTree statistics ===============\n";
380
381  app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
382
383  app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
384
[667]385  app << "#N_SPLITS ( Number of splits in axes x y z dx dy dz)\n";
[372]386  for (int i=0; i<7; i++)
387    app << splits[i] <<" ";
388  app <<endl;
389
390  app << "#N_RAYREFS ( Number of rayRefs )\n" <<
391    rayRefs << "\n";
392
393  app << "#N_RAYRAYREFS  ( Number of rayRefs / ray )\n" <<
394    rayRefs/(double)rays << "\n";
395
396  app << "#N_LEAFRAYREFS  ( Number of rayRefs / leaf )\n" <<
397    rayRefs/(double)Leaves() << "\n";
398
[1184]399  app << "#N_MAXOBJECTREFS  ( Max number of object refs / leaf )\n" <<
[372]400    maxObjectRefs << "\n";
401
402  app << "#N_NONEMPTYRAYREFS  ( Number of rayRefs in nonEmpty leaves / non empty leaf )\n" <<
403    rayRefsNonZeroQuery/(double)(Leaves() - zeroQueryNodes) << "\n";
404
405  app << "#N_LEAFDOMAINREFS  ( Number of query domain Refs / leaf )\n" <<
406    objectRefs/(double)Leaves() << "\n";
407
408  //  app << setprecision(4);
409
410  app << "#N_PEMPTYLEAVES  ( Percentage of leaves with zero query domains )\n"<<
411    zeroQueryNodes*100/(double)Leaves()<<endl;
412
413  app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maxdepth )\n"<<
414    maxDepthNodes*100/(double)Leaves()<<endl;
415
416  app << "#N_PMINCOSTLEAVES  ( Percentage of leaves with minCost )\n"<<
417    minCostNodes*100/(double)Leaves()<<endl;
418
419  app << "#N_ADDED_RAYREFS  (Number of dynamically added ray references )\n"<<
420    addedRayRefs<<endl;
421
422  app << "#N_REMOVED_RAYREFS  (Number of dynamically removed ray references )\n"<<
423    removedRayRefs<<endl;
424
425  //  app << setprecision(4);
426
427  //  app << "#N_CTIME  ( Construction time [s] )\n"
428  //      << Time() << " \n";
429
430  app << "===== END OF KdTree statistics ==========\n";
431
432}
433
434
435
436void
437KdTree::EvaluateLeafStats(const TraversalData &data)
438{
439
440  // the node became a leaf -> evaluate stats for leafs
441  KdLeaf *leaf = (KdLeaf *)data.mNode;
442
443  if (data.mDepth > mTermMaxDepth)
444    mStat.maxDepthNodes++;
445 
446  if ( (int)(leaf->mObjects.size()) < mTermMinCost)
447    mStat.minCostNodes++;
448 
449 
450  if ( (int)(leaf->mObjects.size()) > mStat.maxObjectRefs)
[469]451    mStat.maxObjectRefs = (int)leaf->mObjects.size();
[372]452 
453}
454
455
456
457void
[1233]458KdTree::SortSubdivisionCandidates(
[372]459                            KdLeaf *node,
460                            const int axis
461                            )
462{
[2003]463        CLEAR_CONTAINER(*splitCandidates);
464  //splitCandidates->clear();
[372]465 
[469]466  int requestedSize = 2*(int)node->mObjects.size();
[372]467  // creates a sorted split candidates array
468  if (splitCandidates->capacity() > 500000 &&
469      requestedSize < (int)(splitCandidates->capacity()/10) ) {
470    delete splitCandidates;
[2003]471    splitCandidates = new vector<SortableEntry *>;
[372]472  }
473 
474  splitCandidates->reserve(requestedSize);
475 
476  // insert all queries
477  for(ObjectContainer::const_iterator mi = node->mObjects.begin();
478      mi != node->mObjects.end();
479      mi++) {
480    AxisAlignedBox3 box = (*mi)->GetBox();
481
[2003]482    splitCandidates->push_back(new SortableEntry(SortableEntry::BOX_MIN,
[752]483                                                                                         box.Min(axis),
484                                                                                         *mi)
485                                                           );
[372]486   
487   
[2003]488    splitCandidates->push_back(new SortableEntry(SortableEntry::BOX_MAX,
[752]489                                                                                         box.Max(axis),
490                                                                                         *mi)
491                                                           );
[372]492  }
493 
494  stable_sort(splitCandidates->begin(), splitCandidates->end());
495}
496
497
498float
499KdTree::BestCostRatio(
[752]500                                          KdLeaf *node,
501                                          const AxisAlignedBox3 &box,
502                                          const int axis,
503                                          float &position,
504                                          int &objectsBack,
505                                          int &objectsFront
506                                          )
[372]507{
508
[1387]509#define DEBUG_COST 0
510
511#if DEBUG_COST
512  static int nodeId = -1;
513  char filename[256];
514 
515  static int lastAxis = 100;
516  if (axis <= lastAxis)
517        nodeId++;
518
519  lastAxis = axis;
520 
521  sprintf(filename, "sah-cost%d-%d.log", nodeId, axis);
522  ofstream costStream;
523 
524  if (nodeId < 100)
525        costStream.open(filename);
526
527#endif
528 
[1233]529  SortSubdivisionCandidates(node, axis);
[372]530 
531  // go through the lists, count the number of objects left and right
532  // and evaluate the following cost funcion:
533  // C = ct_div_ci  + (ol + or)/queries
534
535  float totalIntersections = 0.0f;
[2003]536  vector<SortableEntry *>::const_iterator ci;
[372]537
538  for(ci = splitCandidates->begin();
539      ci < splitCandidates->end();
540      ci++)
[2003]541    if ((*ci)->type == SortableEntry::BOX_MIN) {
542      totalIntersections += (*ci)->intersectable->IntersectionComplexity();
[372]543    }
544       
545  float intersectionsLeft = 0;
546  float intersectionsRight = totalIntersections;
547       
[469]548  int objectsLeft = 0, objectsRight = (int)node->mObjects.size();
[372]549 
550  float minBox = box.Min(axis);
551  float maxBox = box.Max(axis);
552  float boxArea = box.SurfaceArea();
553 
554  float minBand = minBox + mSplitBorder*(maxBox - minBox);
555  float maxBand = minBox + (1.0f - mSplitBorder)*(maxBox - minBox);
556 
[469]557  float minSum = 1e20f;
[372]558 
559  for(ci = splitCandidates->begin();
560      ci < splitCandidates->end();
561      ci++) {
[2003]562    switch ((*ci)->type) {
[372]563    case SortableEntry::BOX_MIN:
564      objectsLeft++;
[2003]565      intersectionsLeft += (*ci)->intersectable->IntersectionComplexity();
[372]566      break;
567    case SortableEntry::BOX_MAX:
568      objectsRight--;
[2003]569      intersectionsRight -= (*ci)->intersectable->IntersectionComplexity();
[372]570      break;
571    }
572
[2003]573    if ((*ci)->value > minBand && (*ci)->value < maxBand) {
[372]574      AxisAlignedBox3 lbox = box;
575      AxisAlignedBox3 rbox = box;
[2003]576      lbox.SetMax(axis, (*ci)->value);
577      rbox.SetMin(axis, (*ci)->value);
[372]578
579      float sum;
580      if (mSahUseFaces)
[752]581                sum = intersectionsLeft*lbox.SurfaceArea() + intersectionsRight*rbox.SurfaceArea();
[372]582      else
[752]583                sum = objectsLeft*lbox.SurfaceArea() + objectsRight*rbox.SurfaceArea();
[372]584     
585      //      cout<<"pos="<<(*ci).value<<"\t q=("<<ql<<","<<qr<<")\t r=("<<rl<<","<<rr<<")"<<endl;
586      //      cout<<"cost= "<<sum<<endl;
[1387]587
588#if DEBUG_COST
589  if (nodeId < 100) {
590        float oldCost = mSahUseFaces ? totalIntersections : node->mObjects.size();
591        float newCost = mCt_div_ci + sum/boxArea;
592        float ratio = newCost/oldCost;
[2003]593        costStream<<(*ci)->value<<" "<<ratio<<endl;
[1387]594  }
595#endif
596         
[372]597      if (sum < minSum) {
[752]598                minSum = sum;
[2003]599                position = (*ci)->value;
[752]600               
601                objectsBack = objectsLeft;
602                objectsFront = objectsRight;
[372]603      }
604    }
605  }
606 
607  float oldCost = mSahUseFaces ? totalIntersections : node->mObjects.size();
608  float newCost = mCt_div_ci + minSum/boxArea;
609  float ratio = newCost/oldCost;
610 
611#if 0
612  cout<<"===================="<<endl;
613  cout<<"costRatio="<<ratio<<" pos="<<position<<" t="<<(position - minBox)/(maxBox - minBox)
614      <<"\t o=("<<objectsBack<<","<<objectsFront<<")"<<endl;
615#endif
616  return ratio;
617}
618
619int
620KdTree::CastRay(
[462]621                                Ray &ray
622                                )
[372]623{
[1984]624 
[372]625  int hits = 0;
626 
627  stack<RayTraversalData> tStack;
628 
629  float maxt = 1e6;
630  float mint = 0;
[1583]631
[1584]632  //  ray.ComputeInvertedDir();
[372]633  Intersectable::NewMail();
634
635  if (!mBox.GetMinMaxT(ray, &mint, &maxt))
636    return 0;
637
638  if (mint < 0)
639    mint = 0;
[1584]640
[372]641 
642  maxt += Limits::Threshold;
643 
644  Vector3 entp = ray.Extrap(mint);
645  Vector3 extp = ray.Extrap(maxt);
646 
647  KdNode *node = mRoot;
648  KdNode *farChild;
649  float position;
650  int axis;
[752]651
[372]652 
653  while (1) {
654    if (!node->IsLeaf()) {
655      KdInterior *in = (KdInterior *) node;
656      position = in->mPosition;
657      axis = in->mAxis;
658
659      if (entp[axis] <= position) {
[752]660                if (extp[axis] <= position) {
661                  node = in->mBack;
662                  // cases N1,N2,N3,P5,Z2,Z3
663                  continue;
664                } else {
665                  // case N4
666                  node = in->mBack;
667                  farChild = in->mFront;
668                }
[372]669      }
670      else {
[752]671                if (position <= extp[axis]) {
672                  node = in->mFront;
673                  // cases P1,P2,P3,N5,Z1
674                  continue;
675                } else {
676                  node = in->mFront;
677                  farChild = in->mBack;
678                  // case P4
679                }
680          }
[372]681      // $$ modification 3.5.2004 - hints from Kamil Ghais
682      // case N4 or P4
683      float tdist = (position - ray.GetLoc(axis)) / ray.GetDir(axis);
684      tStack.push(RayTraversalData(farChild, extp, maxt));
685      extp = ray.GetLoc() + ray.GetDir()*tdist;
686      maxt = tdist;
[752]687        } else {
688          // compute intersection with all objects in this leaf
689          KdLeaf *leaf = (KdLeaf *) node;
690          if (ray.mFlags & Ray::STORE_KDLEAVES)
691                ray.kdLeaves.push_back(leaf);
692         
693          ObjectContainer::const_iterator mi;
694          for ( mi = leaf->mObjects.begin();
[1867]695                        mi != leaf->mObjects.end();
696                        mi++) {
697                Intersectable *object = *mi;
698                if (!object->Mailed() ) {
699                  object->Mail();
700                  if (ray.mFlags & Ray::STORE_TESTED_OBJECTS)
701                        ray.testedObjects.push_back(object);
702                 
703                  static int oi=1;
704                  if (MeshDebug)
705                        cout<<"Object "<<oi++;
706                 
707                  hits += object->CastRay(ray);
708                 
709                  if (MeshDebug) {
710                        if (!ray.intersections.empty())
711                          cout<<"nearest t="<<ray.intersections[0].mT<<endl;
712                        else
713                          cout<<"nearest t=-INF"<<endl;
714                  }       
715                }
[752]716          }
717         
718          if (hits && ray.GetType() == Ray::LOCAL_RAY)
[1867]719                if (ray.intersections[0].mT <= maxt)
720                  break;
[752]721         
722          // get the next node from the stack
723          if (tStack.empty())
[1867]724                break;
[752]725         
726          entp = extp;
727          mint = maxt;
728          if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
[1867]729                break;
[752]730         
731          RayTraversalData &s  = tStack.top();
732          node = s.mNode;
733          extp = s.mExitPoint;
734          maxt = s.mMaxT;
735          tStack.pop();
736        }
[372]737  }
738  return hits;
739}
740
[469]741int KdTree::CastLineSegment(const Vector3 &origin,
742                                                        const Vector3 &termination,
[882]743                                                        ViewCellContainer &viewcells)
[469]744{
745        int hits = 0;
746        float mint = 0.0f, maxt = 1.0f;
747        const Vector3 dir = termination - origin;
748
[475]749        stack<RayTraversalData> tStack;
[469]750
751        Intersectable::NewMail();
752
753        //maxt += Limits::Threshold;
754
755        Vector3 entp = origin;
756        Vector3 extp = termination;
757
758        KdNode *node = mRoot;
759        KdNode *farChild;
760
761        float position;
762        int axis;
763
764        while (1)
765        {
[2015]766          if (!node->IsLeaf()) {
767                KdInterior *in = (KdInterior *)node;
768                position = in->mPosition;
769                axis = in->mAxis;
770               
771                if (entp[axis] <= position)
772                  {
773                        if (extp[axis] <= position)
774                          {
775                                node = in->mBack;
776                                // cases N1,N2,N3,P5,Z2,Z3
777                                continue;
778                          }
[469]779                        else
[2015]780                          {
781                                // case N4
782                                node = in->mBack;
783                                farChild = in->mFront;
784                          }
785                  }
[469]786                else
[2015]787                  {
788                        if (position <= extp[axis])
789                          {
790                                node = in->mFront;
791                                // cases P1,P2,P3,N5,Z1
792                                continue;
793                          }
794                        else
795                          {
796                                node = in->mFront;
797                                farChild = in->mBack;
798                                // case P4
799                          }
800                  }
801               
802                // $$ modification 3.5.2004 - hints from Kamil Ghais
803                // case N4 or P4
804                float tdist = (position - origin[axis]) / dir[axis];
805                //tStack.push(RayTraversalData(farChild, extp, maxt)); //TODO
806                extp = origin + dir * tdist;
807                maxt = tdist;
808          }
809          else
[469]810                {
[2015]811                  // compute intersection with all objects in this leaf
[2014]812                  KdLeaf *leaf = (KdLeaf *)node;
[2015]813                 
814                  // add view cell to intersections
815                  ViewCell *vc = leaf->mViewCell;
816                 
817                  if (!vc->Mailed()) {
818                        vc->Mail();
819                        viewcells.push_back(vc);
820                        ++ hits;
821                  }
822                 
823                  // get the next node from the stack
824                  if (tStack.empty())
825                        break;
826                 
827                  entp = extp;
828                  mint = maxt;
829                 
830                  RayTraversalData &s  = tStack.top();
831                  node = s.mNode;
832                  extp = s.mExitPoint;
833                  maxt = s.mMaxT;
834                  tStack.pop();
[469]835                }
836        }
[2015]837       
[469]838        return hits;
839}
840
[1974]841void
842KdTree::CollectKdObjects(const AxisAlignedBox3 &box,
[1989]843                                                 ObjectContainer &objects
[1974]844                                                 )
845{
846  stack<KdNode *> nodeStack;
847 
848  nodeStack.push(mRoot);
[469]849
[1974]850  while (!nodeStack.empty()) {
851    KdNode *node = nodeStack.top();
852    nodeStack.pop();
[1989]853        if (node->IsLeaf() || node->mPvsTermination == 1)  {
[1974]854          Intersectable *object = GetOrCreateKdIntersectable(node);
855          if (!object->Mailed()) {
856                object->Mail();
857                objects.push_back(object);
858          }
859        } else {
860      KdInterior *interior = (KdInterior *)node;
861         
862          if ( box.Max()[interior->mAxis] > interior->mPosition )
863                nodeStack.push(interior->mFront);
864         
865          if (box.Min()[interior->mAxis] < interior->mPosition)
866                nodeStack.push(interior->mBack);
867    }
868  }
869}
870
[372]871void
[859]872KdTree::CollectObjects(const AxisAlignedBox3 &box,
873                                           ObjectContainer &objects)
874{
875  stack<KdNode *> nodeStack;
876
877  nodeStack.push(mRoot);
878
879  while (!nodeStack.empty()) {
880    KdNode *node = nodeStack.top();
881    nodeStack.pop();
882    if (node->IsLeaf()) {
883      KdLeaf *leaf = (KdLeaf *)node;
884      for (int j=0; j < leaf->mObjects.size(); j++) {
885                Intersectable *object = leaf->mObjects[j];
[904]886                if (!object->Mailed() && Overlap(box, object->GetBox())) {
[859]887                  object->Mail();
888                  objects.push_back(object);
889                }
890      }
891    } else {
892      KdInterior *interior = (KdInterior *)node;
893
894          if ( box.Max()[interior->mAxis] > interior->mPosition )
895                nodeStack.push(interior->mFront);
896 
897          if (box.Min()[interior->mAxis] < interior->mPosition)
898                nodeStack.push(interior->mBack);
899    }
900  }
901}
902
903void
[372]904KdTree::CollectObjects(KdNode *n, ObjectContainer &objects)
905{
906  stack<KdNode *> nodeStack;
907
908  nodeStack.push(n);
909
910  while (!nodeStack.empty()) {
911    KdNode *node = nodeStack.top();
912    nodeStack.pop();
913    if (node->IsLeaf()) {
914      KdLeaf *leaf = (KdLeaf *)node;
915      for (int j=0; j < leaf->mObjects.size(); j++) {
[374]916                                Intersectable *object = leaf->mObjects[j];
917                                if (!object->Mailed()) {
918                                        object->Mail();
919                                        objects.push_back(object);
920                                }
[372]921      }
922    } else {
923      KdInterior *interior = (KdInterior *)node;
924      nodeStack.push(interior->mFront);
925      nodeStack.push(interior->mBack);
926    }
927  }
928}
929
930// Find random neighbor which was not mailed
931KdNode *
932KdTree::FindRandomNeighbor(KdNode *n,
[1286]933                                                   bool onlyUnmailed
934                                                   )
[372]935{
936  stack<KdNode *> nodeStack;
937 
938  nodeStack.push(mRoot);
939
940  AxisAlignedBox3 box = GetBox(n);
941  int mask = rand();
942
943  while (!nodeStack.empty()) {
944    KdNode *node = nodeStack.top();
945    nodeStack.pop();
946    if (node->IsLeaf()) {
947      if ( node != n && (!onlyUnmailed || !node->Mailed()) )
948        return node;
949    } else {
950      KdInterior *interior = (KdInterior *)node;
951      if (interior->mPosition > box.Max(interior->mAxis))
952        nodeStack.push(interior->mBack);
953      else
954        if (interior->mPosition < box.Min(interior->mAxis))
955          nodeStack.push(interior->mFront);
956        else {
957          // random decision
958          if (mask&1)
959            nodeStack.push(interior->mBack);
960          else
961            nodeStack.push(interior->mFront);
962          mask = mask>>1;
963        }
964    }
965  }
966 
967  return NULL;
968}
969
970int
971KdTree::FindNeighbors(KdNode *n,
972                      vector<KdNode *> &neighbors,
973                      bool onlyUnmailed
974                      )
975{
976  stack<KdNode *> nodeStack;
977 
978  nodeStack.push(mRoot);
979
980  AxisAlignedBox3 box = GetBox(n);
981
982  while (!nodeStack.empty()) {
983    KdNode *node = nodeStack.top();
984    nodeStack.pop();
985    if (node->IsLeaf()) {
986      if ( node != n && (!onlyUnmailed || !node->Mailed()) )
987        neighbors.push_back(node);
988    } else {
989      KdInterior *interior = (KdInterior *)node;
990      if (interior->mPosition > box.Max(interior->mAxis))
[374]991                                nodeStack.push(interior->mBack);
[372]992      else
[374]993                                if (interior->mPosition < box.Min(interior->mAxis))
994                                        nodeStack.push(interior->mFront);
995                                else {
996                                        // random decision
997                                        nodeStack.push(interior->mBack);
998                                        nodeStack.push(interior->mFront);
999                                }
[372]1000    }
1001  }
1002 
[469]1003  return (int)neighbors.size();
[372]1004}
1005
1006// Find random neighbor which was not mailed
1007KdNode *
1008KdTree::GetRandomLeaf(const Plane3 &plane)
1009{
1010  stack<KdNode *> nodeStack;
1011 
1012  nodeStack.push(mRoot);
1013 
1014  int mask = rand();
1015 
1016  while (!nodeStack.empty()) {
1017    KdNode *node = nodeStack.top();
1018    nodeStack.pop();
1019    if (node->IsLeaf()) {
1020      return node;
1021    } else {
1022      KdInterior *interior = (KdInterior *)node;
1023      KdNode *next;
1024        if (GetBox(interior->mBack).Side(plane) < 0)
1025          next = interior->mFront;
1026        else
1027          if (GetBox(interior->mFront).Side(plane) < 0)
1028            next = interior->mBack;
1029          else {
1030            // random decision
1031            if (mask&1)
1032              next = interior->mBack;
1033            else
1034              next = interior->mFront;
1035            mask = mask>>1;
1036          }
1037        nodeStack.push(next);
1038    }
1039  }
1040 
1041 
1042  return NULL;
1043}
1044
1045void
1046KdTree::CollectLeaves(vector<KdLeaf *> &leaves)
1047{
1048  stack<KdNode *> nodeStack;
1049  nodeStack.push(mRoot);
1050
1051  while (!nodeStack.empty()) {
1052    KdNode *node = nodeStack.top();
1053    nodeStack.pop();
1054    if (node->IsLeaf()) {
1055      KdLeaf *leaf = (KdLeaf *)node;
1056      leaves.push_back(leaf);
1057    } else {
1058      KdInterior *interior = (KdInterior *)node;
1059      nodeStack.push(interior->mBack);
1060      nodeStack.push(interior->mFront);
1061    }
1062  }
1063}
1064
[469]1065void
1066KdTree::CreateAndCollectViewCells(ViewCellContainer &vc) const
1067{
1068  stack<KdNode *> nodeStack;
1069  nodeStack.push(mRoot);
[372]1070
[469]1071  while (!nodeStack.empty()) {
1072    KdNode *node = nodeStack.top();
1073    nodeStack.pop();
1074    if (node->IsLeaf()) {
1075      KdLeaf *leaf = (KdLeaf *)node;
1076          // kdtree used as view cell container => create view cell
[471]1077          KdViewCell *viewCell = new KdViewCell();
1078          leaf->mViewCell = viewCell;
1079          // push back pointer to this leaf
[1551]1080          viewCell->mLeaves[0] = leaf;
[471]1081      vc.push_back(viewCell);
[469]1082    } else {
1083      KdInterior *interior = (KdInterior *)node;
1084      nodeStack.push(interior->mBack);
1085      nodeStack.push(interior->mFront);
1086    }
1087  }
1088}
1089
[372]1090int
1091KdTree::CollectLeafPvs()
1092{
[1736]1093
1094        // matt: no more kd pvs
1095    int totalPvsSize = 0;
1096        /*
[372]1097  stack<KdNode *> nodeStack;
1098 
1099  nodeStack.push(mRoot);
1100 
1101  while (!nodeStack.empty()) {
1102    KdNode *node = nodeStack.top();
1103    nodeStack.pop();
1104    if (node->IsLeaf()) {
1105      KdLeaf *leaf = (KdLeaf *)node;
1106      for (int j=0; j < leaf->mObjects.size(); j++) {
1107        Intersectable *object = leaf->mObjects[j];
1108        if (!object->Mailed()) {
1109          object->Mail();
1110          // add this node to pvs of all nodes it can see
1111          KdPvsMap::iterator ni = object->mKdPvs.mEntries.begin();
1112          for (; ni != object->mKdPvs.mEntries.end(); ni++) {
1113            KdNode *node = (*ni).first;
1114            // $$ JB TEMPORARY solution -> should add object PVS or explictly computed
1115            // kd tree PVS
[466]1116                float contribution;
[556]1117                if (leaf->mKdPvs.AddSample(node, 1.0f, contribution))
[372]1118              totalPvsSize++;
1119          }
1120        }
1121      }
1122    } else {
1123      KdInterior *interior = (KdInterior *)node;
1124      nodeStack.push(interior->mFront);
1125      nodeStack.push(interior->mBack);
1126    }
1127  }
[1736]1128*/
[372]1129  return totalPvsSize;
1130}
1131
1132
1133KdNode *
1134KdTree::GetRandomLeaf(const bool onlyUnmailed)
1135{
[507]1136  stack<KdNode *> nodeStack;
[372]1137  nodeStack.push(mRoot);
[507]1138 
1139  int mask = rand();
[372]1140       
1141  while (!nodeStack.empty()) {
1142    KdNode *node = nodeStack.top();
1143    nodeStack.pop();
1144    if (node->IsLeaf()) {
1145      if ( (!onlyUnmailed || !node->Mailed()) )
1146                                return node;
1147    } else {
1148      KdInterior *interior = (KdInterior *)node;
1149                        // random decision
1150                        if (mask&1)
1151                                nodeStack.push(interior->mBack);
1152                        else
1153                                nodeStack.push(interior->mFront);
1154                        mask = mask>>1;
1155                }
1156        }
1157  return NULL;
1158}
[504]1159
1160
1161int
[507]1162KdTree::CastBeam(
[512]1163                                 Beam &beam
[507]1164                                 )
[504]1165{
[507]1166  stack<KdNode *> nodeStack;
1167  nodeStack.push(mRoot);
[504]1168 
[507]1169  while (!nodeStack.empty()) {
1170    KdNode *node = nodeStack.top();
1171    nodeStack.pop();
1172       
1173        int side = beam.ComputeIntersection(GetBox(node));
1174        switch (side) {
1175        case -1:
1176          beam.mKdNodes.push_back(node);
1177          break;
1178        case 0:
1179          if (node->IsLeaf())
1180                beam.mKdNodes.push_back(node);
1181          else {
1182                KdInterior *interior = (KdInterior *)node;
1183                KdNode *first = interior->mBack;
1184                KdNode *second = interior->mFront;
1185               
1186                if (interior->mAxis < 3) {
1187                  // spatial split -> decide on the order of the nodes
1188                  if (beam.mPlanes[0].mNormal[interior->mAxis] > 0)
1189                        swap(first, second);
1190                }
[504]1191
[507]1192                nodeStack.push(first);
1193                nodeStack.push(second);
1194          }
1195          break;
1196          // default: cull
1197        }
1198  }
1199
[532]1200  if (beam.mFlags & Beam::STORE_OBJECTS)
1201  {
1202          vector<KdNode *>::const_iterator it, it_end = beam.mKdNodes.end();
[535]1203       
[532]1204          Intersectable::NewMail();
1205          for (it = beam.mKdNodes.begin(); it != it_end; ++ it)
1206          {
1207                  CollectObjects(*it, beam.mObjects);
1208          }
1209  }
1210
[837]1211  return (int)beam.mKdNodes.size();
[504]1212}
[860]1213
[1074]1214
[1196]1215#define TYPE_INTERIOR -2
1216#define TYPE_LEAF -3
[1194]1217
1218
[1201]1219void KdTree::ExportBinLeaf(OUT_STREAM &stream, KdLeaf *leaf)
[1194]1220{
1221        ObjectContainer::const_iterator it, it_end = leaf->mObjects.end();
1222       
[1196]1223        int type = TYPE_LEAF;
1224        int size = (int)leaf->mObjects.size();
1225
1226        stream.write(reinterpret_cast<char *>(&type), sizeof(int));
1227        stream.write(reinterpret_cast<char *>(&size), sizeof(int));
1228
[1194]1229        for (it = leaf->mObjects.begin(); it != it_end; ++ it)
1230        {       
1231                Intersectable *obj = *it;
1232                int id = obj->mId;             
[1196]1233       
[1194]1234                //stream.write(reinterpret_cast<char *>(&origin), sizeof(Vector3));
1235                stream.write(reinterpret_cast<char *>(&id), sizeof(int));
1236    }
[878]1237}
[1194]1238
1239
[1201]1240KdLeaf *KdTree::ImportBinLeaf(IN_STREAM &stream,
[1197]1241                                                          KdInterior *parent,
1242                                                          const ObjectContainer &objects)
[1194]1243{
[1196]1244        int leafId = TYPE_LEAF;
[1194]1245        int objId = leafId;
[1196]1246        int size;
1247
1248        stream.read(reinterpret_cast<char *>(&size), sizeof(int));
1249        KdLeaf *leaf = new KdLeaf(parent, size);
1250
[1197]1251        MeshInstance dummyInst(NULL);
[1633]1252       
[1196]1253        // read object ids
[1633]1254        // note: could also do this geometrically
[1196]1255        for (int i = 0; i < size; ++ i)
[1194]1256        {       
1257                stream.read(reinterpret_cast<char *>(&objId), sizeof(int));
[1197]1258                dummyInst.SetId(objId);
[1196]1259
[1197]1260                ObjectContainer::const_iterator oit =
1261                        lower_bound(objects.begin(), objects.end(), (Intersectable *)&dummyInst, ilt);
1262                                                               
1263                if ((oit != objects.end()) && ((*oit)->GetId() == objId))
1264                {
[2003]1265                        if (1) leaf->mObjects.push_back(*oit);
[1197]1266                }
1267                else
1268                {
1269                        Debug << "error: object with id " << objId << " does not exist" << endl;
1270                }
1271        }
1272
[1196]1273        return leaf;
[1194]1274}
1275
1276
[1201]1277void KdTree::ExportBinInterior(OUT_STREAM &stream, KdInterior *interior)
[1194]1278{
[1196]1279        int interiorid = TYPE_INTERIOR;
[1194]1280        stream.write(reinterpret_cast<char *>(&interiorid), sizeof(int));
1281
1282        int axis = interior->mAxis;
[1196]1283        float pos = interior->mPosition;
[1194]1284
1285        stream.write(reinterpret_cast<char *>(&axis), sizeof(int));
[1196]1286        stream.write(reinterpret_cast<char *>(&pos), sizeof(float));
[1194]1287}
1288
1289
[1201]1290KdInterior *KdTree::ImportBinInterior(IN_STREAM  &stream, KdInterior *parent)
[1194]1291{
[1196]1292        KdInterior *interior = new KdInterior(parent);
[1194]1293
1294        int axis = interior->mAxis;
[1196]1295        float pos = interior->mPosition;
[1194]1296
1297        stream.read(reinterpret_cast<char *>(&axis), sizeof(int));
[1196]1298        stream.read(reinterpret_cast<char *>(&pos), sizeof(float));
1299
1300        interior->mAxis = axis;
1301        interior->mPosition = pos;
1302
1303        return interior;
[1194]1304}
1305
1306
1307bool KdTree::ExportBinTree(const string &filename)
1308{
[1201]1309        OUT_STREAM stream(filename.c_str(), OUT_BIN_MODE);
[1194]1310       
[1201]1311        //if (!stream.is_open()) return false;
[1194]1312
1313        // export binary version of mesh
[1197]1314        queue<KdNode *> tStack;
[1194]1315        tStack.push(mRoot);
1316
1317        while(!tStack.empty())
1318        {
[1197]1319                KdNode *node = tStack.front();
[1196]1320                tStack.pop();
1321               
1322                if (node->IsLeaf())
1323                {
[1197]1324                        //Debug << "l";
[1196]1325                        ExportBinLeaf(stream, dynamic_cast<KdLeaf *>(node));
1326                }
1327                else
1328                {
[1197]1329                        //Debug << "i";
[1196]1330                        KdInterior *interior = dynamic_cast<KdInterior *>(node);
[1194]1331
[1196]1332                        ExportBinInterior(stream, interior);
1333                       
1334                        tStack.push(interior->mFront);
1335                        tStack.push(interior->mBack);
[1194]1336                }
1337        }
1338
1339        return true;
1340}
1341
1342
[1201]1343KdNode *KdTree::LoadNextNode(IN_STREAM &stream,
[1197]1344                                                         KdInterior *parent,
1345                                                         const ObjectContainer &objects)
[1194]1346{
[1196]1347        int nodeType;
1348        stream.read(reinterpret_cast<char *>(&nodeType), sizeof(int));
1349
1350        if (nodeType == TYPE_LEAF)
1351        {
[1197]1352                return ImportBinLeaf(stream, dynamic_cast<KdInterior *>(parent), objects);
[1196]1353        }
1354
1355        if (nodeType == TYPE_INTERIOR)
1356        {
1357                return ImportBinInterior(stream, dynamic_cast<KdInterior *>(parent));
1358        }
1359
1360        Debug << "error! loading failed!" << endl;
[1194]1361       
[1196]1362        return NULL;
1363}
1364
1365
[1197]1366bool KdTree::LoadBinTree(const string &filename, ObjectContainer &objects)
[1196]1367{
1368        // export binary version of mesh
[1197]1369        queue<TraversalData> tStack;
[1201]1370        IN_STREAM stream(filename.c_str(), IN_BIN_MODE);
[1197]1371
[1286]1372        if (!stream.is_open()) return false;
[1194]1373
[1414]1374        // sort objects by their id
[1197]1375        std::stable_sort(objects.begin(), objects.end(), ilt);
[1194]1376
[1197]1377        mBox.Initialize();
[1196]1378        ObjectContainer::const_iterator oit, oit_end = objects.end();
[1194]1379
[1414]1380        ///////////////////////////
1381        //-- compute bounding box of object space
[1633]1382
[1196]1383    for (oit = objects.begin(); oit != oit_end; ++ oit)
1384        {
[1414]1385                const AxisAlignedBox3 box = (*oit)->GetBox();
1386                mBox.Include(box);
[1196]1387        }
1388
[1414]1389        // hack: we make a new root
1390        DEL_PTR(mRoot);
[1197]1391 
1392        KdNode *node = LoadNextNode(stream, NULL, objects);
[1196]1393        mRoot = node;
1394
1395        tStack.push(TraversalData(node, mBox, 0));
1396        mStat.Reset();
1397        mStat.nodes = 1;
1398
[1194]1399        while(!tStack.empty())
1400        {
[1197]1401                TraversalData tData = tStack.front();
[1196]1402                tStack.pop();
[1194]1403
[1196]1404                KdNode *node = tData.mNode;
1405
1406                if (!node->IsLeaf())
[1194]1407                {
[1196]1408                        mStat.nodes += 2;
1409
[1197]1410                        //Debug << "i" ;
[1194]1411                        KdInterior *interior = dynamic_cast<KdInterior *>(node);
[1196]1412                        interior->mBox = tData.mBox;
[1194]1413
[1197]1414            KdNode *front = LoadNextNode(stream, interior, objects);
1415                        KdNode *back = LoadNextNode(stream, interior, objects);
[1196]1416       
1417                        interior->SetupChildLinks(back, front);
1418
1419                        ++ mStat.splits[interior->mAxis];
1420
1421                        // compute new bounding box
1422                        AxisAlignedBox3 frontBox, backBox;
[1194]1423                       
[1196]1424                        tData.mBox.Split(interior->mAxis,
1425                                                         interior->mPosition,
1426                                                         frontBox,
1427                                                         backBox);
1428
1429                        tStack.push(TraversalData(front, frontBox, tData.mDepth + 1));                 
[1197]1430                        tStack.push(TraversalData(back, backBox, tData.mDepth + 1));
[1194]1431                }
[1196]1432                else
1433                {
1434                        EvaluateLeafStats(tData);
[1415]1435                        //cout << "l";
[1196]1436                }
[1194]1437        }
[1415]1438
[1989]1439        float area = GetBox().SurfaceArea()*KD_PVS_AREA;
1440       
1441        SetPvsTerminationNodes(area);
1442
[1196]1443        Debug << mStat << endl;
1444
[1194]1445        return true;
1446}
1447
[1999]1448
[1594]1449KdIntersectable *
1450KdTree::GetOrCreateKdIntersectable(KdNode *node)
1451{
[1194]1452
[1594]1453  if (node == NULL)
1454        return NULL;
[1761]1455
1456  if (node->mIntersectable == NULL) {
1457        // not in map => create new entry
1458        node->mIntersectable = new KdIntersectable(node, GetBox(node));
1459        mKdIntersectables.push_back(node->mIntersectable);
1460  }
1461
1462  return node->mIntersectable;
[1387]1463}
[1594]1464
[1989]1465
1466void
1467KdTree::SetPvsTerminationNodes(
1468                                                           const float maxArea)
1469{
1470  stack<KdNode *> nodeStack;
1471 
1472  nodeStack.push(mRoot);
1473
[1995]1474  float area = 0.0f;
1475  float radius = 0.0f;
1476  int nodes = 0;
1477 
[1989]1478  while (!nodeStack.empty()) {
1479    KdNode *node = nodeStack.top();
1480        nodeStack.pop();
1481
1482        node->mPvsTermination = 0;
1483        if (node->IsLeaf() || (GetSurfaceArea(node) <= maxArea) ) {
[1995]1484          area += GetSurfaceArea(node);
1485          radius += GetBox(node).Radius();
1486          nodes++;
[1989]1487          node->mPvsTermination = 1;
1488          // create dummy kd intersectable
1489          Intersectable *object = GetOrCreateKdIntersectable(node);
1490        } else {
1491          KdInterior *interior = (KdInterior *)node;
1492          nodeStack.push(interior->mFront);
1493          nodeStack.push(interior->mBack);
1494    }
1495  }
[1995]1496
1497  if (nodes) {
1498        area /= nodes;
1499        radius /= nodes;
1500        cout<<"Number of nodes for storing in the PVS = "<<nodes<<endl;
1501        cout<<"Average rel. node area = "<<area/GetSurfaceArea(mRoot)<<endl;
1502        cout<<"Average rel. node radius = "<<radius/GetBox(mRoot).Radius()<<endl;
1503        cout<<"Avg node radius = "<<radius<<endl;
1504  }
1505 
[1989]1506}
1507
[1594]1508KdNode *
[1989]1509KdTree::GetPvsNode(const Vector3 &point) const
1510{
1511  KdNode *node = mRoot;
1512 
1513  while (node->mPvsTermination == 0 ) {
1514        KdInterior *inter = (KdInterior *)node;
1515        if (point[inter->mAxis] < inter->mPosition)
1516          node = inter->mBack;
1517        else
1518          node = inter->mFront;
1519  }
1520 
1521  return node;
1522}
1523
1524KdNode *
[1594]1525KdTree::GetNode(const Vector3 &point,
1526                                const float maxArea) const
1527{
1528  KdNode *node = mRoot;
1529 
1530  while (!node->IsLeaf() && (GetSurfaceArea(node) > maxArea) ) {
1531        KdInterior *inter = (KdInterior *)node;
1532        if (point[inter->mAxis] < inter->mPosition)
1533          node = inter->mBack;
1534        else
1535          node = inter->mFront;
1536  }
1537 
1538  return node;
1539}
1540
1541
[1999]1542void KdTree::GetBoxIntersections(const AxisAlignedBox3 &box,
1543                                                                 vector<KdLeaf *> &leaves)
1544{
1545        stack<KdNode *> tStack;
[1633]1546
[1999]1547        tStack.push(mRoot);
1548
[1633]1549        while (!tStack.empty())
1550        {
[1999]1551                KdNode *node = tStack.top();
1552                tStack.pop();
[1633]1553               
1554                if (node->IsLeaf())
1555                {
[1999]1556                        leaves.push_back(dynamic_cast<KdLeaf *>(node));
[1633]1557                }
1558                else // interior
1559                {
1560                        KdInterior *interior = dynamic_cast<KdInterior *>(node);
1561
[1999]1562                        if (box.Max(interior->mAxis) >= interior->mPosition)
[1633]1563                        {
[1999]1564                                tStack.push(interior->mFront);
[1633]1565                        }
1566
[1999]1567                        if (box.Min(interior->mAxis) < interior->mPosition)
1568                        {
1569                                tStack.push(interior->mBack);
1570                        }
[1633]1571                }
[1999]1572        }
[1594]1573}
[1633]1574
[1999]1575
1576
[1633]1577}
Note: See TracBrowser for help on using the repository browser.