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

Revision 2017, 35.5 KB checked in by mattausch, 17 years ago (diff)

changed to static cast

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