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

Revision 2575, 35.4 KB checked in by bittner, 17 years ago (diff)

big merge: preparation for havran ray caster, check if everything works

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