source: GTP/trunk/Lib/Vis/Preprocessing/src/havran/ktball.cpp @ 2608

Revision 2608, 27.6 KB checked in by bittner, 16 years ago (diff)

HR updates

Line 
1// ===================================================================
2// $Id: $
3//
4// ktball.cpp
5//     Implementation of interface functions for CKTB trees
6//
7// REPLACEMENT_STRING
8//
9// Copyright by Vlastimil Havran, 2007 - email to "vhavran AT seznam.cz"
10// Initial coding by Vlastimil Havran, February 2007
11
12// GOLEM library
13#include "ktbconf.h"
14#include "ktb.h"
15#include "ktbai.h"
16#include "ktball.h"
17#include "ktbtrav.h"
18#include "Environment.h"
19#include "raypack.h"
20#include "Mesh.h"
21
22// standard headers
23#include <fstream>
24#include <iomanip>
25#include <stack>
26
27namespace GtpVisibilityPreprocessor {
28
29// Static data structures fo CKTBTraversal class
30GALIGN16 CKTBTraversal::SStackElem
31CKTBTraversal::stack[CKTBTraversal::MAX_TRAVERSAL_HEIGHT];
32
33CKTBTraversal::SStackElem2
34CKTBTraversal::stack2[CKTBTraversal::MAX_TRAVERSAL_HEIGHT];
35
36CKTBTraversal::SStackElem3
37CKTBTraversal::stack3[CKTBTraversal::MAX_TRAVERSAL_HEIGHT];
38
39CKTBTraversal::SStackElem4
40CKTBTraversal::stack4[CKTBTraversal::MAX_TRAVERSAL_HEIGHT];
41
42 
43// ------------------------------------------------------------------
44// CKTB class
45//
46// Binary Space Partitioning Tree, that handles bounded objects only
47// during intersection computation other way
48
49// default constructor
50CKTB::CKTB():
51  builtUp(false),
52  buildClass(NULL), traversalClass(NULL), sizeBuffer(0),buffer(0),
53  indexRead(0), indexWrite(0)
54{
55
56}
57
58// only for creating building class of CKTB tree
59CKTBAllocManPredecessor*
60CKTB::AllocBuildClass()
61{
62  CKTBAllocManPredecessor *bc = 0;
63  bool useArray = true;
64 
65  // this should be already initialised, but we want to be sure
66  if (useArray) {
67    // the implementation based on arrays
68    bc = new CKTBABuildUp(); // file ktbai.cpp
69  }
70  else {
71    // the implementation based on lists
72    // bc = new CKTBBuildUp(); // file ktbi.cpp
73  }
74   
75  if (bc == NULL) {
76    cerr << "The building class for KTB cannot be allocated"<< endl;
77    exit(3);
78  }
79
80  return bc;
81}
82
83void
84CKTB::AllocTraversalClass()
85{
86  if (traversalClass != NULL)
87    delete traversalClass;
88
89  traversalClass = NULL;
90
91  // if we use min boxes idea in the tree
92
93  Environment::GetSingleton()->GetBoolValue("BSP.minBoxes.use",
94                                            makeMinBoxes);
95  Environment::GetSingleton()->GetBoolValue("BSP.minBoxes.tight",
96                                            makeTightMinBoxes);
97  // the number of cells along ray path
98  const int size1D = 150;
99
100  // cerr<<"th1"<<endl;
101  // $$JB tmp
102  size2D = 1;
103  // cerr<<"size2d="<<size2D<<endl;
104  // initial index
105  index2D = 0;
106  AllocBuffer(size2D, size1D);
107  //  cerr<<"th2"<<endl;
108
109#if 0 
110  // -------------------------------------------------------------------
111  if (makeMinBoxes) {
112    // This class uses information about the box
113    // inside from which the ray starts from
114    traversalClass = new CKTBMinBoxesTraversal(size1D);
115  }
116  else {
117    // normal traversal always from root
118    traversalClass = new CKTBTraversal;
119  }
120#else
121  // cerr<<"th3"<<endl;
122
123  traversalClass = new CKTBTraversal;
124#endif
125
126  assert(traversalClass);
127
128  return;
129}
130
131// default destructor
132CKTB::~CKTB()
133{
134  // Print the statistics
135  PrintStats();
136 
137  Remove();
138}
139
140void
141CKTB::Remove()
142{
143  if (buildClass) {
144    // DEBUG << "Deleting build class from CKTB" << endl;
145    buildClass->Remove();
146    delete buildClass;
147    buildClass = NULL;
148  }
149
150  if (traversalClass) {
151    delete traversalClass;
152    traversalClass = NULL;
153  }
154
155  return;
156}
157
158void
159CKTB::ProvideID(ostream& app)
160{
161  app << "#CASDS = CKTB - KD-tree for only bounded objects\n";
162  //app << (int)GetID() << "\n";
163 
164  //app << "#ActMaxDepth (Dreach)\tActual maximal depth of the KD-tree"
165  //    << " reached\n";
166  //app << world->_statistics->actMaxDepth << "\n";
167
168  ProvidePars(app);
169}
170
171void
172CKTB::ProvidePars(ostream& app)
173{
174  app << "#NumberOfObjects\t\tNumber of objects inside kd-tree\n";
175  app << countObjects << "\n";
176 
177  app << "#BBox\t\t\tSize of axis-aligned box of the whole scene\n"
178      << bbox.Max().x - bbox.Min().x << ","
179      << bbox.Max().y - bbox.Min().y << ","
180      << bbox.Max().z - bbox.Min().z << "\n";
181
182#if 0 
183  bool tempvar;
184  Environment::GetSingleton()->GetBoolValue("BSP.pruning", tempvar);
185  if (tempvar) {
186    app << "#BSP.pruning \t\tPruning of CKTB disabled/enabled\n";
187    app << tempvar << "\n";
188  }
189  app << "#BSP.constrMethod \tBuilding up method for KD-tree\n";
190#endif 
191
192  if (buildClass)
193    buildClass->ProvideID(app);
194
195  return;
196}
197
198void
199CKTB::PrintStats()
200{
201  if (traversalClass)
202    traversalClass->PrintStatsTR(cout);
203}
204
205// builds up CKTB tree
206void
207CKTB::BuildUp(const ObjectContainer &alist)
208{
209  cerr<<"KTB buildup\n";
210  Remove();
211
212  // Create the list of objects to be processed.
213  ObjectContainer *objlist = new ObjectContainer;
214
215  // The minimum size
216  bbox.Initialize();
217 
218  // Copy only finite (not invisible and bounded) objects from
219  // the original list to 'objlist'
220   
221  // copy the pointers to objects to the array
222  int i = 0;
223  AxisAlignedBox3 objbox; 
224  bool hasUnboundeds = false;
225  countObjects = 0;
226  for (ObjectContainer::iterator it = ((ObjectContainer*)&alist)->begin();
227       it != alist.end(); it++, i++) {
228    Intersectable* obj = *it;
229    objbox = (*it)->GetBox();
230    // invisible objects are not added - lights etc.
231    bbox.Include(objbox);
232    // This is a regular object, add it to the list
233    objlist->push_back(obj);
234  } // for
235   
236  // prepare building up for CKTB tree
237  //  BuildingUp(*objlist);
238  BuildingUp(*objlist, NULL, NULL, true);
239
240  cerr<<"KTB buildup3\n";
241
242  delete objlist;
243
244  return;
245}
246
247bool
248CKTB::CheckBoxes(ObjectContainer &objlist)
249{
250  // the minimum size of the box at any dimension
251  const float epsilon = Limits::Small * 5.0f;
252
253  for (ObjectContainer::iterator oi = objlist.begin();
254       oi != objlist.end(); oi++) {
255    AxisAlignedBox3 box = (*oi)->GetBox();
256    Vector3 diff = box.Diagonal();
257    for (int i = 0; i < 3; i++) {
258      float d = fabs(diff[i]);
259#if 0
260      if (d < epsilon) {
261        CObject3D &obj = **(oi);
262        cerr << "CKTB::CheckBoxes - the scene incorrectly prepared, "
263              << " the size of the box = " << d << " in dimension "
264              << i << " is" << " below threshold = " << epsilon << endl;
265        cerr << "object = " << (void*)(*oi) << " uniqueID = " <<
266          (*oi)->GetUniqueID() << " description = " << endl;
267        obj.Describe(cout, 1);
268        cerr << "----------" << endl;
269        abort();
270        return true; // error
271      }
272#else
273      if (d < epsilon) {
274        int size = objlist.size();
275        *oi = objlist[size-1];
276        objlist.resize(size-1);
277        oi--; // check this object as well
278      }     
279#endif
280    } // for i   
281  } // for all objecs
282
283  return false;
284}
285
286// builds up CKTB tree without unbounded objects. The 'boxToInclude
287// is a box that can be optionally given and the kd-tree constructed
288// must contain such a box. The 'boxToBoundObjects' when given, is
289// a box to which the objects boxes are bounded. This is used for special
290// cases such a multilevel kd-trees.
291void
292CKTB::BuildingUp(ObjectContainer& objlist,
293                 const AxisAlignedBox3 *boxToInclude,
294                 const AxisAlignedBox3 *boxToBoundObjects,
295                 bool verbose)
296{
297  // the number of objects for statistics purposes - it can be different
298  // from objlist->size() since objlist need not be initialized at all!
299  countObjects = objlist.size();
300
301  // compute the estimate for the kd-tree constructed this way
302  _expectedIntersectionCost = log((float)countObjects) / log(2.0f) + 2.0;
303 
304#ifdef _DEBUG
305  // check the flatness of the boxes for all objects
306  if (CheckBoxes(objlist)) {
307    cerr << "Problem with the size of the box for some object" << endl;
308    return;
309  }
310#endif // _DEBUG
311
312  // cerr<<"hh2"<<endl;
313  // possibly remove the old building class
314  // and allocate the class for CKTB building up
315  if (buildClass)
316    delete buildClass; 
317  buildClass = AllocBuildClass();
318
319  // cerr<<"hh3"<<endl;
320
321  // and for traversal
322  AllocTraversalClass();
323  // cerr<<"hh4"<<endl;
324
325  if (boxToBoundObjects) {
326    // maximum box of the scene is given in advance
327    bbox = Intersect(bbox, *boxToBoundObjects);
328  }
329
330  // we can additionally include the user box
331  if (boxToInclude)
332    bbox.Include(*boxToInclude); 
333
334  // cerr<<"hh5"<<endl;
335
336  // build up the CKTB tree and make setup for traversal
337  SKTBNodeT *rootNode =
338    buildClass->BuildUp(objlist, bbox, verbose);
339  // cerr<<"hh6"<<endl;
340
341  traversalClass->Setup(bbox, rootNode);
342  // cerr<<"hh7"<<endl;
343
344#ifdef _DEBUG
345  //traversalClass->AssignIDs();
346#endif
347  builtUp = true;
348
349#if 0 
350  // if to clean up the whole structure
351  bool pruning;
352  Environment::GetSingleton()->GetBoolValue("BSP.pruning", pruning);
353  if (pruning)
354    // only the objects whose surfaces intersects with the subdivision
355    PruneLeaves(); // cells are not pruned from the CKTB tree
356#endif
357}
358
359// functions that allows correctly traverse recursively allowing to have
360// the same traversal stack
361void
362CKTB::TraversalReset()
363{
364  assert(traversalClass);
365  traversalClass->ResetTraversalDepth();
366}
367
368// Allocate 2D buffer of pointers to the interior nodes
369void
370CKTB::AllocBuffer(int size2D, int size1Dv)
371{
372  int i, j;
373 
374  if (buffer) {
375    for (i=0; i < sizeBuffer; i++) {
376      delete [] buffer[i];
377    } // for
378    delete [] buffer;
379    buffer = 0;
380  }
381
382  sizeBuffer = size2D;
383  this->size1D = size1Dv;
384  buffer = new SKTBNodeT ** [sizeBuffer];
385  assert(buffer);
386  for (i=0; i < sizeBuffer; i++) {
387    buffer[i] = new SKTBNodeT* [size1D];
388    assert(buffer[i]);
389    // reset the array content
390    for (j = 0; j < size1D; j++) {
391      buffer[i][j] = 0;
392    }
393  } // for
394
395  return;
396}
397
398int
399CKTB::FindNearestI(const SimpleRay &ray)
400{
401  return traversalClass->FindNearestI(ray);     
402}
403
404int
405CKTB::FindNearestI(const SimpleRay &ray, const Vector3 &boxmin, const Vector3 &boxmax)
406{
407  const AxisAlignedBox3 localbox(boxmin, boxmax);
408  return traversalClass->FindNearestI(ray, localbox);     
409}
410
411 
412#ifdef _USE_HAVRAN_SSE 
413
414#ifdef __SSE__
415// --------------------------------------------------------------
416// Ray packets
417void
418CKTB::FindNearestI(RayPacket2x2 &raypack)
419{
420  if (!makeMinBoxes)
421    raypack.SetOrigin(0); // min boxes are not used, we cannot use them here !
422  traversalClass->FindNearestI(raypack);
423}
424
425void
426CKTB::FindNearestI(RayPacket2x2 &raypack,
427                                   const Vector3 &boxmin,
428                                   const Vector3 &boxmax)
429{
430  if (!makeMinBoxes)
431    raypack.SetOrigin(0); // min boxes are not used, we cannot use them here !
432  traversalClass->FindNearestI(raypack, boxmin, boxmax);
433}
434
435#endif // __SSE__
436
437#endif // _USE_HAVRAN_SSE 
438
439 
440void
441CKTB::DeleteBuildClass()
442{
443  if (buildClass)
444    delete buildClass;
445  buildClass = NULL;
446}
447
448void
449CKTB::GatherStats(bool itself)
450{
451  // DEBUG << "CKTB::GatherStats called" << endl;
452  struct EDir {
453    SKTBNodeT *node;
454    int depth;
455    AxisAlignedBox3 bbox;
456  };
457  EDir stack[CKTBTraversal::MAX_TRAVERSAL_HEIGHT];
458  int stackTop = 0; // pointer to the stack
459  stack[stackTop].node = 0;
460  stack[stackTop].depth = 0;
461  stack[stackTop].bbox = bbox;
462  int tmpdir;
463#ifdef __TAGGED_KDR
464  int taggedLists = 0;
465#endif // __TAGGED_KDR
466 
467  /*
468  if (!BuiltUp) {
469    cerr << "Internal error: CASDS not built up. Giving up.\n" << flush;
470    abort();
471  }
472  */
473 
474  // average depth for all leaves
475  long avgLeafDepth = 0;
476  // for full leaves
477  long avgFullLeafDepth = 0;
478  // for empty leaves
479  long avgEmptyLeafDepth = 0;
480
481  // Surface areas  (divided by the area of the box)
482  // Surface area of leaves (empty + full)
483  double saLeaves = 0.f;
484  // Surface area of interior nodes
485  double saInteriorNodes = 0.f;
486  // Sum of surface area of (full) leaves multiplied by
487  // the number of objects in leaves
488  double sa_cntLeaves = 0.f;
489  // number of boxes enclosing tightly the objects
490  long int boxesMin = 0;
491  long int boxesMinX = 0;
492  long int boxesMinY = 0;
493  long int boxesMinZ = 0;
494  // the sum of depth of tight boxes
495  long int boxesMinDepth = 0;
496
497  // start from the root node
498  SKTBNodeT *curr = buildClass->GetRootNode();
499  // copy the box over the scene objects
500  AxisAlignedBox3 wbox = this->bbox;
501  int currDepth = 0;
502
503  if (buildClass->IsLeaf_(curr)) {
504    this->numElemCells++;
505    if (buildClass->IsEmptyLeaf_(curr)) {
506      this->numEmptyElemCells++;
507      AxisAlignedBox3 bwbox = this->bbox;
508      // Surface area for empty leaf
509      this->emptyVolume += bwbox.GetVolume();
510      saLeaves += bwbox.SurfaceArea();
511    }
512    else { // CKTB tree is single non-empty leaf
513      AxisAlignedBox3 bwbox = this->bbox;
514      this->nonEmptyVolume += bwbox.GetVolume();
515      ObjectContainer *olist = curr->objlist;
516      saLeaves += bwbox.SurfaceArea();
517      if (!olist) {
518        this->numSolidsInElemCells += olist->size();
519        this->actMaxListLen = olist->size();
520        // surface area for full leaf
521        sa_cntLeaves = bwbox.SurfaceArea() * (float)(olist->size());
522      }
523    }
524  }
525  else { // CKTB tree is not a single leaf
526    // now we access the interior node
527
528    // surface area for interior node
529    AxisAlignedBox3 bwbox = this->bbox;
530    // surface area for interior node
531    saInteriorNodes += bwbox.SurfaceArea();
532    this->numHierCells++;
533       
534    // traverse through whole CKTB tree
535    do {
536      CKTBAxes::Axes nodeType = buildClass->GetNodeType(curr);
537      if (nodeType == CKTBAxes::EE_Link) {
538        // just relink
539        curr = buildClass->GetLinkNode(curr);
540        // cout << "Link node was accessed" << endl;
541        continue;       
542      }
543     
544      if ( (nodeType == CKTBAxes::EE_X_axis)||
545           (nodeType == CKTBAxes::EE_Y_axis)||
546           (nodeType == CKTBAxes::EE_Z_axis)||
547           (nodeType == CKTBAxes::EE_X_axisBox)||
548           (nodeType == CKTBAxes::EE_Y_axisBox)||
549           (nodeType == CKTBAxes::EE_Z_axisBox)
550         ) {
551
552        // push onto the stack
553        AxisAlignedBox3 rightBox = bwbox;
554        float value = curr->splitPlane;
555        switch(nodeType) {
556          case CKTBAxes:: EE_X_axisBox: {
557            rightBox.SetMin(0, value);
558            bwbox.SetMax(0, value);
559            boxesMin++;
560            boxesMinX++;
561            boxesMinDepth += currDepth;
562            break;       
563          }
564          case CKTBAxes:: EE_X_axis: {
565            rightBox.SetMin(0, value);
566            bwbox.SetMax(0, value);
567            break;       
568          }
569          case CKTBAxes:: EE_Y_axisBox: {
570            rightBox.SetMin(0, value);
571            bwbox.SetMax(0, value);
572            boxesMin++;
573            boxesMinY++;
574            boxesMinDepth += currDepth;
575            break;       
576          }
577          case CKTBAxes:: EE_Y_axis: {
578            rightBox.SetMin(1, value);
579            bwbox.SetMax(1, value);
580            break;       
581          }
582          case CKTBAxes:: EE_Z_axisBox: {
583            rightBox.SetMin(0, value);
584            bwbox.SetMax(0, value);
585            boxesMin++;
586            boxesMinZ++;
587            boxesMinDepth += currDepth;
588            break;       
589          }
590          case CKTBAxes:: EE_Z_axis: {
591            rightBox.SetMin(2, value);
592            bwbox.SetMax(2, value);
593            break;       
594          }
595        } // switch
596     
597        stack[stackTop].node = buildClass->GetRight(curr);
598        stack[stackTop].depth = currDepth+1;
599        stack[stackTop].bbox = rightBox;
600        stackTop++;
601        // where to go
602        if ( (nodeType == CKTBAxes:: EE_X_axisBox)||
603             (nodeType == CKTBAxes:: EE_Y_axisBox)||
604             (nodeType == CKTBAxes:: EE_Z_axisBox) )
605          curr = buildClass->GetLeftMinBox(curr);
606        else
607          curr = buildClass->GetLeft(curr);
608        // the box was already set     
609        currDepth++;
610     
611        if (this->actMaxDepth < currDepth)
612          this->actMaxDepth = currDepth;
613
614        // surface area for interior node
615        saInteriorNodes += bwbox.SurfaceArea();
616        this->numHierCells++;
617
618        continue;
619      } // interior nodes
620
621      assert(nodeType == CKTBAxes::EE_Leaf);
622     
623      while ( (nodeType == CKTBAxes::EE_Leaf) && currDepth) {
624        this->numElemCells++;
625        avgLeafDepth += currDepth;
626
627        ObjectContainer *olist = buildClass->GetObjList(curr);
628       
629        // test to empty leaf
630        if (!olist) {
631          this->numEmptyElemCells++;
632          avgEmptyLeafDepth += currDepth;
633          this->emptyVolume += bwbox.GetVolume();
634          // Surface area for empty leaf
635          saLeaves += bwbox.SurfaceArea();
636        }
637        else {
638          // full leaf
639          this->nonEmptyVolume += bwbox.GetVolume();
640          avgFullLeafDepth += currDepth;
641          int length = olist->size();
642          this->numSolidsInElemCells += length;
643          // surface area for full leaf
644          saLeaves += bwbox.SurfaceArea();
645          sa_cntLeaves += bwbox.SurfaceArea() * (float)(olist->size());
646          if (this->actMaxListLen < length)
647            this->actMaxListLen = length;
648        }
649       
650        // traverse up the tree
651        stackTop--;
652        if (stackTop < 0)
653          goto FINISH;
654        // pop the node from the stack
655        curr = stack[stackTop].node;
656        currDepth = stack[stackTop].depth;
657
658        nodeType = buildClass->GetNodeType(curr);
659       
660      } // while is a leaf
661    }
662    while (stackTop >= 0);
663  } // either single leaf or tree
664
665FINISH:
666
667  cout << "BBox " << this->bbox << "\n";
668 
669#ifdef __TAGGED_KDR
670  DEBUGW << "Tagged lists = " << taggedLists << "\n";
671#endif // __TAGGED_KDR
672
673  cout << "#CntLeaves = \n" << this->numElemCells << "\n";
674  cout << "#AverageLeafDepth = \n"
675       << (float)avgLeafDepth/(float)this->numElemCells << "\n";
676  cout << "#CntFullLeaves = \n" << (this->numElemCells-this->numEmptyElemCells)
677        << "\n";
678  cout << "#AverageFullLeafDepth = \n"
679        << (float)avgFullLeafDepth/
680            (float)(this->numElemCells - this->numEmptyElemCells) << "\n";
681  cout << "#AverageEmptyLeafDepth = \n";
682  if (this->numEmptyElemCells)
683    cout << (float)avgEmptyLeafDepth / (float)this->numEmptyElemCells<<"\n";
684  else
685    cout << "undefined\n";
686
687  // Normalized the surface area
688  this->sumSurfaceAreaLeaves = saLeaves / wbox.SurfaceArea();
689  this->sumSurfaceAreaMULcntLeaves = sa_cntLeaves / wbox.SurfaceArea();
690  this->sumSurfaceAreaInteriorNodes = saInteriorNodes / wbox.SurfaceArea();
691
692  cout << "#SumSurfaceLeafArea = \n" << saLeaves << "\n";
693  cout << "#SumSurfaceLeafAreaMulCNT = \n" << sa_cntLeaves << "\n";
694  cout << "#NormSurfaceLeafArea = \n" << this->sumSurfaceAreaLeaves << "\n";
695  cout << "#NormSurfaceLeafAreaMulCNT = \n" << this->sumSurfaceAreaMULcntLeaves << "\n";
696  cout << "#SurfaceAreaInteriorNodes = \n" << this->sumSurfaceAreaInteriorNodes<<"\n"; 
697  cout << "#MinBoxesCount = \n" << boxesMin << "\n";
698  cout << "#MinBoxesXCount = \n" << boxesMinX << "\n";
699  cout << "#MinBoxesYCount = \n" << boxesMinY << "\n";
700  cout << "#MinBoxesZCount = \n" << boxesMinZ << "\n";
701  if (boxesMin)
702    cout << "#AverageMinBoxesDepth = \n"
703          << (float)boxesMinDepth/(float)boxesMin << "\n";
704
705  long int memUsed = 0;
706#ifdef _KTB8Bytes
707  memUsed += this->numHierCells*8;
708  memUsed += (this->numElemCells-this->numEmptyElemCells)*8;
709#ifdef _SHORT_FORM_MINBOX
710  memUsed += boxesMin * (sizeof(SBBox) + 2*8);
711#else
712  memUsed += boxesMin * (5*8);
713#endif
714#else // _KTB8Bytes
715  memUsed += this->numHierCells*12;
716  memUsed += (this->numElemCells-this->numEmptyElemCells)*12;
717#ifdef _SHORT_FORM_MINBOX
718  memUsed += boxesMin * (sizeof(SBBox) + 2*12);
719#else
720  memUsed += boxesMin * (4*12);
721#endif
722#endif // _KTB8Bytes
723
724  // The references to objects
725  memUsed += this->numSolidsInElemCells * sizeof(Intersectable*);
726  memUsed += (this->numElemCells-this->numEmptyElemCells) *
727    sizeof(ObjectContainer);
728  cout << "#MemUsedKBB = \n" << memUsed << "\n";
729   
730  return;
731}
732
733
734void CKTB::ExportBinLeaf(OUT_STREAM &stream, SKTBNodeT *leaf)
735{
736#define TYPE_LEAF -3
737  int type = TYPE_LEAF;
738  if (leaf->objlist == 0) {
739    // empty leaf
740    int size = 0;
741    stream.write(reinterpret_cast<char *>(&type), sizeof(int));
742    stream.write(reinterpret_cast<char *>(&size), sizeof(int));   
743    return;
744  }
745 
746  ObjectContainer::const_iterator it, it_end = leaf->objlist->end(); 
747  int size = (int)leaf->objlist->size();
748 
749  stream.write(reinterpret_cast<char *>(&type), sizeof(int));
750  stream.write(reinterpret_cast<char *>(&size), sizeof(int));
751 
752  for (it = leaf->objlist->begin(); it != it_end; ++ it)
753  {     
754    Intersectable *obj = *it;
755    int id = obj->mId;         
756     
757    //stream.write(reinterpret_cast<char *>(&origin), sizeof(Vector3));
758    stream.write(reinterpret_cast<char *>(&id), sizeof(int));
759  }
760}
761
762
763inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
764{
765  return obj1->mId < obj2->mId;
766}
767
768 
769SKTBNodeT*
770CKTB::ImportBinLeaf(IN_STREAM &stream,
771                    SKTBNodeT **nodeToLink,
772                    const ObjectContainer &objects)
773{
774  int leafId = TYPE_LEAF;
775  int objId = leafId;
776  int size;
777 
778  stream.read(reinterpret_cast<char *>(&size), sizeof(int));
779  if (size == 0) {
780    // alloc empty leaf -- ?????????? I am not sure if this works !!!
781    // since for
782    SKTBNodeT* leaf = buildClass->AllocLeaf(0);
783    *nodeToLink = buildClass->nodeToLink;
784    return leaf;
785  }
786 
787  MeshInstance dummyInst(NULL);
788  SKTBNodeT* leaf = buildClass->AllocLeaf(size);
789  *nodeToLink = buildClass->nodeToLink;
790
791  ObjectContainer *newobjlist = new ObjectContainer;
792 
793  // read object ids
794  // note: this can also be done geometrically
795  for (int i = 0; i < size; ++ i)
796  {     
797    stream.read(reinterpret_cast<char *>(&objId), sizeof(int));
798    dummyInst.SetId(objId);
799     
800    ObjectContainer::const_iterator oit =
801      lower_bound(objects.begin(), objects.end(), (Intersectable *)&dummyInst, ilt);
802     
803    if ((oit != objects.end()) && ((*oit)->GetId() == objId))
804      newobjlist->push_back(*oit);
805    else
806      Debug << "error: object with id " << objId << " does not exist" << endl;
807  } // for
808
809  buildClass->SetFullLeaf(leaf, newobjlist);
810 
811  return leaf;
812}
813
814
815void CKTB::ExportBinInterior(OUT_STREAM &stream, SKTBNodeT *interior)
816{
817#define TYPE_INTERIOR -2
818  int interiorid = TYPE_INTERIOR;
819  stream.write(reinterpret_cast<char *>(&interiorid), sizeof(int));
820
821  int axis = (int)(buildClass->GetNodeType(interior));
822  float pos = buildClass->GetSplitValue(interior);
823
824  stream.write(reinterpret_cast<char *>(&axis), sizeof(int));
825  stream.write(reinterpret_cast<char *>(&pos), sizeof(float));
826}
827
828
829SKTBNodeT *
830CKTB::ImportBinInterior(IN_STREAM  &stream, SKTBNodeT **nodeToLink)
831{
832  int axis;
833  float pos;
834
835  stream.read(reinterpret_cast<char *>(&axis), sizeof(int));
836  stream.read(reinterpret_cast<char *>(&pos), sizeof(float));
837
838  SKTBNodeT *interiorNode =
839    buildClass->AllocInteriorNode(axis, pos, 0, 0);
840  *nodeToLink = buildClass->nodeToLink;
841       
842  return interiorNode;
843}
844
845
846bool CKTB::ExportBinTree(const string &filename)
847{
848  OUT_STREAM stream(filename.c_str(), OUT_BIN_MODE);
849       
850  if (!stream.is_open()) return false;
851
852  int startMark = 0xf0f0;
853  stream.write(reinterpret_cast<char *>(&startMark), sizeof(int)); 
854 
855  // export binary version of mesh
856  std::stack<SKTBNodeT *> tStack;
857  tStack.push(buildClass->GetRootNode());
858  int cntSaves = 0, cntSavesLeaf = 0, cntSavesIN = 0;
859
860  while(!tStack.empty())
861  {
862    SKTBNodeT *node = tStack.top();
863    tStack.pop();   
864
865    int nodeType = buildClass->GetNodeType(node);
866   
867    if (nodeType == CKTBAxes::EE_Link)
868    {
869      tStack.push(buildClass->GetLinkNode(node));
870    }
871    else
872    if (nodeType == CKTBAxes::EE_Leaf)
873    {
874      //Debug << "l";
875      ExportBinLeaf(stream, node);
876      cntSavesLeaf++; cntSaves++;     
877    }
878    else
879    { // interior node
880      //Debug << "i";
881      ExportBinInterior(stream, node);
882      cntSavesIN++; cntSaves++;     
883
884      tStack.push(buildClass->GetRight(node));
885      if (nodeType >= CKTBAxes::EE_X_axisBox)
886        tStack.push(buildClass->GetLeftLong(node));
887      else
888        tStack.push(buildClass->GetLeft(node));
889    }
890  } // while
891
892  int endMark = 0xf0ff;
893  stream.write(reinterpret_cast<char *>(&endMark), sizeof(int)); 
894
895  cout << "Writes " << cntSaves << " cntLeafs "
896       << cntSavesLeaf << " cntIN " << cntSavesIN << endl;
897 
898  stream.close();
899  return true; // saved
900}
901
902
903SKTBNodeT *
904CKTB::ImportNextNode(IN_STREAM &stream,
905                     SKTBNodeT **nodeToLink,
906                     const ObjectContainer &objects)
907{
908  int nodeType;
909  stream.read(reinterpret_cast<char *>(&nodeType), sizeof(int));
910
911  if (nodeType == TYPE_LEAF)
912    return ImportBinLeaf(stream, nodeToLink, objects);
913
914  if (nodeType == TYPE_INTERIOR)
915    return ImportBinInterior(stream, nodeToLink);
916
917  Debug << "error! loading failed!" << endl;
918  return NULL;
919}
920
921
922// creates the ASDS according to the file description
923bool
924CKTB::ImportBinTree(const string &filename, ObjectContainer &objects)
925{
926  // open the stream in text mode
927  IN_STREAM stream(filename.c_str(), IN_BIN_MODE);
928
929  if (!stream.is_open()) {
930    cerr << "Kd-tree description file (.kdh) cannot be opened for reading\n";
931    return true; // error
932  }
933
934  int mark;
935  stream.read(reinterpret_cast<char *>(&mark), sizeof(int));
936  if (mark != 0xf0f0) {
937    cout << "Something wrong with the tree - heading" << endl;
938    abort();
939  }
940 
941  // sort objects by their id to allow list creation in kd-tree leaves
942  //    if (!is_sorted(objects.begin(), objects.end(), ilt))
943  sort(objects.begin(), objects.end(), ilt);
944 
945  // remove all the data in the current data structure
946  CKTBAllocManPredecessor *bc = GetBuildClass();
947  if (!bc)
948    bc = buildClass = AllocBuildClass();
949  else
950    bc->Remove();
951
952  // How many items can be allocated at once
953  int maxItemsAtOnce = 1;
954  if (makeMinBoxes) {
955#ifdef _KTB8Bytes   
956    // We need to allocate for boxes the memory in a row
957    maxItemsAtOnce = 5; // 8x5=40 = 16+24;
958#else
959    maxItemsAtOnce = 4; // 12x4=48 = 24+24;
960#endif // _KTB8Bytes
961  }
962 
963  bc->InitAux(0, CKTBNodeAbstract::MAX_HEIGHT - 1, maxItemsAtOnce); 
964
965  // Compute the box from all objects
966  bbox.Initialize();
967  for (ObjectContainer::iterator sc = objects.begin();
968       sc != objects.end(); sc++) {
969    AxisAlignedBox3 abox = (*sc)->GetBox();
970    bbox.Include(abox);
971  } // for
972   
973  // initialize the root node
974  SKTBNodeT *node;
975
976  bc->root = ImportNextNode(stream, &node, objects);
977  assert(bc->root == node);
978
979  std::stack<STraversalData> tStack;
980  tStack.push(STraversalData(bc->root, 1, 0));
981  tStack.push(STraversalData(bc->root, 0, 0));
982  int depth, lastDepth;
983 
984  //int cntReads = 1, cntReadsLeaf = 0, cntReadsIN = 1;
985  while(!tStack.empty())
986  {   
987    STraversalData tData = tStack.top();
988    tStack.pop();
989   
990    node = tData.mNode;
991    lastDepth = depth = tData.depth;
992    //int nodeType = bc->GetNodeType(node);
993    //cout << "nodeType = " << nodeType << " adr = " << (void*)node << endl;
994
995    SKTBNodeT *childNodeLink = 0;
996    SKTBNodeT *childNode = ImportNextNode(stream, &childNodeLink, objects);
997    //    cout << "childNode = " << (void*)childNode
998    // << " linkNode = " << (void*)childNodeLink << endl;
999
1000    if (tData.dir)
1001      bc->SetInteriorNodeRight(node, childNodeLink);
1002    else
1003      bc->SetInteriorNodeLeft(node, childNodeLink);
1004   
1005    //cntReads++;
1006    if (!bc->IsLeaf_(childNode))
1007    {
1008      //cntReadsIN++;
1009      tStack.push(STraversalData(childNode, 1, depth+1));
1010      tStack.push(STraversalData(childNode, 0, depth+1));
1011    }
1012    //else {
1013    //  cntReadsLeaf++;
1014    //  //cout << "leaf" << endl;
1015    // }
1016  } // while
1017
1018  //cout << "Last depth = " << lastDepth << endl;
1019  //cout << "Reads " << cntReads << " cntLeafs "
1020  //   << cntReadsLeaf << " cntIN " << cntReadsIN << endl;
1021 
1022  stream.read(reinterpret_cast<char *>(&mark), sizeof(int));
1023  if (mark != 0xf0ff) {
1024    cout << "Something wrong with the kd-tree in the file"
1025         << endl;
1026    abort();
1027  }
1028 
1029  if (!traversalClass)
1030    AllocTraversalClass();
1031   
1032  // Make setup for traversal
1033  traversalClass->Setup(bbox, bc->GetRootNode());
1034  // Handles unbounded objects in traversal class
1035  // traversalClass->Setup2(0);
1036 
1037  stream.close();
1038
1039  // now the tree is surely well constructed
1040  builtUp = true; 
1041
1042  return false; // OK
1043}
1044
1045void
1046CKTB::GatherPostStats()
1047{
1048
1049}
1050
1051void*
1052CKTB::Locate(const Vector3 &loc)
1053{
1054  return (void*)(traversalClass->Locate(loc));
1055}
1056
1057
1058} // namespace
Note: See TracBrowser for help on using the repository browser.