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

Revision 2638, 39.9 KB checked in by bittner, 16 years ago (diff)

siggraph submission

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