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

Revision 1989, 35.6 KB checked in by bittner, 17 years ago (diff)

mutation updates

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