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

Revision 2606, 36.3 KB checked in by bittner, 16 years ago (diff)

merge on nemo

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