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

Revision 1974, 34.5 KB checked in by bittner, 17 years ago (diff)

mutation updates, ray sorting, merge

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