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

Revision 2524, 34.8 KB checked in by bittner, 17 years ago (diff)

demo updates

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