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

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