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

Revision 2066, 35.5 KB checked in by mattausch, 17 years ago (diff)

worked on integration manual

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