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

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

skip cast line segment for consequent line segments with oposite dirs

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