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

Revision 2705, 42.0 KB checked in by mattausch, 16 years ago (diff)

enabled view cell visualization

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