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

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