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

Revision 2592, 27.5 KB checked in by bittner, 16 years ago (diff)

havran ray caster update

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