source: GTP/trunk/Lib/Vis/Preprocessing/src/KdTree.h @ 2690

Revision 2690, 15.5 KB checked in by mattausch, 16 years ago (diff)

strange errors!!

Line 
1#ifndef _KdTree_H__
2#define _KdTree_H__
3
4#include <functional>
5//
6
7#include "Containers.h"
8#include "AxisAlignedBox3.h"
9#include "Ray.h"
10//#include "ObjectPvs.h"
11#include "ViewCell.h"
12#include "VssRay.h"
13//#include "IntersectableWrapper.h"
14#include "gzstream.h"
15
16namespace GtpVisibilityPreprocessor {
17
18class KdNode;
19class KdLeaf;
20class KdInterior;
21class Intersectable;
22class KdIntersectable;
23class Beam;
24class KdTree;
25//class KdViewCell;
26 
27  //  KdTree *SceneKdTree;
28
29// --------------------------------------------------------------
30// Static statistics for kd-tree search
31// --------------------------------------------------------------
32class KdTreeStatistics
33{
34public: 
35  // total number of nodes
36  int nodes;
37  // number of splits along each of the axes
38  int splits[7];
39  // totals number of rays
40  int rays;
41  // total number of query domains
42  int queryDomains;
43  // total number of ray references
44  int rayRefs;
45  // refs in non empty leafs
46  int rayRefsNonZeroQuery;
47  // total number of query references
48  int objectRefs;
49  // nodes with zero queries
50  int zeroQueryNodes;
51  // max depth nodes
52  int maxDepthNodes;
53  // max depth nodes
54  int minCostNodes;
55  // max number of rays per node
56  int maxObjectRefs;
57  // number of dynamically added ray refs
58  int addedRayRefs;
59  // number of dynamically removed ray refs
60  int removedRayRefs;
61 
62  // Constructor
63  KdTreeStatistics() {
64    Reset();
65  }
66
67  int Nodes() const {return nodes;}
68  int Interior() const { return nodes / 2; }
69  int Leaves() const { return (nodes / 2) + 1; }
70
71  void Reset()
72  {
73          nodes = 0;
74          for (int i=0; i<7; i++)
75                  splits[i] = 0;
76          rays = queryDomains = 0;
77          rayRefs = rayRefsNonZeroQuery = objectRefs = 0;
78          zeroQueryNodes = 0;
79          maxDepthNodes = 0;
80          minCostNodes = 0;
81          maxObjectRefs = 0;
82          addedRayRefs = removedRayRefs = 0;
83  }
84
85  void
86  Print(std::ostream &app) const;
87
88  friend std::ostream &operator<<(std::ostream &s, const KdTreeStatistics &stat) {
89    stat.Print(s);
90    return s;
91  }
92 
93};
94
95 
96class KdInterior;
97
98/** Abstract class for kd-tree node
99*/
100class KdNode
101{
102
103public: 
104  static int sMailId;
105  static int sReservedMailboxes;
106  int mMailbox;
107
108  static int sMailId2;
109  static int sReservedMailboxes2;
110  int mMailbox2;
111
112  KdIntersectable *mIntersectable;
113 
114  void Mail() { mMailbox = sMailId; }
115  //static void NewMail() { sMailId ++; }
116  bool Mailed() const { return mMailbox == sMailId; }
117 
118  static void NewMail(const int reserve = 1)
119  {
120          sMailId += sReservedMailboxes;
121          sReservedMailboxes = reserve;
122  }
123
124  void Mail(const int mailbox) { mMailbox = sMailId + mailbox; }
125  bool Mailed(const int mailbox) const { return mMailbox == sMailId + mailbox; }
126
127
128  ////////////
129  //-- hack!!: second mail for a machine with 2 cores
130
131  static void NewMail2(const int reserve = 1)
132  {
133          sMailId2 += sReservedMailboxes;
134          sReservedMailboxes2 = reserve;
135  }
136
137  void Mail2() { mMailbox2 = sMailId2; }
138  bool Mailed2() const { return mMailbox2 == sMailId2; }
139 
140  void Mail2(const int mailbox) { mMailbox2 = sMailId2 + mailbox; }
141  bool Mailed2(const int mailbox) const { return mMailbox2 == sMailId2 + mailbox; }
142
143  /////////////////////////////////////
144
145
146  virtual ~KdNode(){};
147  KdNode(KdInterior *parent);
148
149  /** Determines whether this node is a leaf or interior node
150      @return true if leaf
151  */
152  virtual bool IsLeaf() const = 0;
153
154  /** Determines whether this node is the root of the tree
155      @return true if root
156  */
157  virtual bool IsRoot() const {
158    return mParent == NULL;
159  }
160
161  /** Parent of the node - the parent is a little overhead for maintanance of the tree,
162      but allows various optimizations of tree traversal algorithms */
163  KdInterior *mParent;
164  short mDepth;
165  short mPvsTermination;
166};
167
168
169/** Implementation of the kd-tree interior node.
170*/
171class KdInterior : public KdNode {
172
173public:
174   
175  KdInterior(KdInterior *parent):KdNode(parent), mBack(NULL), mFront(NULL) {}
176
177  ~KdInterior();
178
179  /** \sa KdNode::IsLeaf() */
180  virtual bool IsLeaf() const { return false; }
181
182  /** splitting axis */
183  int mAxis;
184  /** splitting position, absolute position within the bounding box of this node */
185  float mPosition;
186  /** bounding box of interior node */
187  AxisAlignedBox3 mBox;
188
189  /** back node */
190  KdNode *mBack;
191  /** front node */
192  KdNode *mFront;
193
194  void SetupChildLinks(KdNode *b, KdNode *f) {
195    mBack = b;
196    mFront = f;
197    b->mParent = f->mParent = this;
198  }
199 
200  void ReplaceChildLink(KdNode *oldChild, KdNode *newChild) {
201    if (mBack == oldChild)
202      mBack = newChild;
203    else
204      mFront = newChild;
205  }
206 
207 
208};
209 
210class SubdivisionCandidate;
211 
212/** Implementation of the kd-tree leaf node */
213class KdLeaf : public KdNode {
214public:
215  KdLeaf(KdInterior *parent, const int objects):
216          KdNode(parent), mViewCell(NULL), mVboId(-1),
217          mIndexBufferStart(0), mIndexBufferSize(0) {
218    mObjects.reserve(objects);
219  }
220 
221  void AddPassingRay(const Ray &ray, const int contributions) {
222    mPassingRays.AddRay(ray, contributions);
223                //              Debug << "adding passing ray" << endl;
224  }
225
226  ~KdLeaf();
227       
228  void AddPassingRay2(const Ray &ray,
229                      const int objects,
230                      const int viewcells
231                      ) {
232    mPassingRays.AddRay2(ray, objects, viewcells);
233                //              Debug << "adding passing ray" << endl;
234  }
235
236  /** \sa KdNode::IsLeaf()
237  */
238  virtual bool IsLeaf() const { return true; }
239
240
241  /// pointers to occluders contained in this node
242  ObjectContainer mObjects;
243  /// Ray set description of the rays passing through this node
244  PassingRaySet mPassingRays;
245  /// pointer to view cell.
246  KdViewCell *mViewCell;
247  /// rays intersecting this leaf
248  VssRayContainer mVssRays;
249   /// Objects that are referenced in more than one leaf.
250  ObjectContainer mMultipleObjects;
251  /// universal counter
252  int mCounter;
253
254  /// hack
255  unsigned int mVboId;
256
257  unsigned int mIndexBufferStart;
258  unsigned int mIndexBufferSize;
259};
260
261
262/** KdTree for indexing scene entities - occluders/occludees/viewcells */
263class KdTree {
264 
265protected:
266  struct TraversalData
267  { 
268    KdNode *mNode;
269    AxisAlignedBox3 mBox;
270    int mDepth;
271    float mPriority;
272   
273    TraversalData() {}
274
275    TraversalData(KdNode *n, const float p):
276      mNode(n), mPriority(p)
277    {}
278   
279    TraversalData(KdNode *n,
280                  const AxisAlignedBox3 &b,
281                  const int d):
282      mNode(n), mBox(b), mDepth(d) {}
283   
284
285    bool operator<(const TraversalData &b) const {
286      KdLeaf *leafa = (KdLeaf *) mNode;
287      KdLeaf *leafb = (KdLeaf *) b.mNode;
288      return
289        leafa->mObjects.size()*mBox.SurfaceArea()
290        <
291        leafb->mObjects.size()*b.mBox.SurfaceArea();
292    }
293
294
295    // comparator for the
296    struct less_priority : public
297    std::binary_function<const TraversalData, const TraversalData, bool> {
298     
299      bool operator()(const TraversalData a, const TraversalData b) {
300        return a.mPriority < b.mPriority;
301      }
302     
303    };
304
305  };
306
307 
308
309public:
310
311  enum {SPLIT_OBJECT_MEDIAN,
312        SPLIT_SPATIAL_MEDIAN,
313        SPLIT_SAH};
314 
315  KdTree();
316
317  ~KdTree();
318   
319  /** Insert view cell into the tree */
320  virtual void InsertViewCell(ViewCell *viewCell) {
321    //      mRoot->mViewcells.push_back(viewCell);
322  }
323
324  virtual bool Construct();
325
326  /** Check whether subdivision criteria are met for the given subtree.
327      If not subdivide the leafs of the subtree. The criteria are specified in
328      the environment as well as the subdivision method. By default surface area
329      heuristics is used.
330       
331      @param subtree root of the subtree
332
333      @return true if subdivision was performed, false if subdivision criteria
334      were already met
335  */
336  virtual KdNode *Subdivide(const TraversalData &tdata);
337
338  /** Get the root of the tree */
339  KdNode *GetRoot() const {
340    return mRoot;
341  }
342
343
344  AxisAlignedBox3 GetBox() const { return mBox; }
345
346  int
347  CastRay(
348                  Ray &ray
349                  );
350 
351
352  int
353  CastBeam(
354                   Beam &beam
355                   );
356 
357 
358  /** Casts line segment into tree.
359          @returns intersected view cells.
360  */
361  int CastLineSegment(const Vector3 &origin,
362                      const Vector3 &termination,
363                      vector<ViewCell *> &viewcells);
364
365  // old version
366  int CastLineSegment2(const Vector3 &origin,
367                                           const Vector3 &termination,
368                                           vector<ViewCell *> &viewcells);
369
370  const KdTreeStatistics &GetStatistics() const {
371    return mStat;
372  }
373
374  /** Returns or creates a new intersectable for use in a kd based pvs.
375  */
376  KdIntersectable *GetOrCreateKdIntersectable(KdNode *node);
377
378
379  void
380  SetPvsTerminationNodes(const float maxArea);
381
382  float
383  GetPvsArea() const;
384 
385  KdNode *
386  GetPvsNode(const Vector3 &point) const;
387 
388
389  void
390  CollectKdObjects(const AxisAlignedBox3 &box,
391                   ObjectContainer &objects
392                   );
393
394  // colect objects which are in the bounding box by explictly specifying the
395  // allowed size of the boxes. If this size is smaller than size used for pvs entries
396  // filtering will be more precise
397  void
398  CollectSmallKdObjects(const AxisAlignedBox3 &box,
399                                                ObjectContainer &objects,
400                                                const float maxArea
401                                                );
402
403  void
404  CollectObjects(KdNode *n, ObjectContainer &objects);
405 
406  /** Collects objects with dublicates (no mailing going on)
407  */
408  void CollectObjectsWithDublicates(KdNode *n, ObjectContainer &objects);
409  void CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects);
410
411  void
412  CollectLeaves(vector<KdLeaf *> &leaves);
413       
414  /** If the kd tree is used as view cell container, this
415          methods creates the view cells.
416          @returns the newly created view cells in a view cell container
417  */
418  void
419  CreateAndCollectViewCells(ViewCellContainer &viewCells) const;
420
421  AxisAlignedBox3 GetBox(const KdNode *node) const {
422    KdInterior *parent = node->mParent;
423    if (parent == NULL)
424      return mBox;
425   
426    if (!node->IsLeaf())
427      return ((KdInterior *)node)->mBox;
428   
429    AxisAlignedBox3 box(parent->mBox);
430    if (parent->mFront == node)
431      box.SetMin(parent->mAxis, parent->mPosition);
432    else
433      box.SetMax(parent->mAxis, parent->mPosition);
434    return box;
435  }
436
437  float GetSurfaceArea(const KdNode *node) const {
438    return GetBox(node).SurfaceArea();
439  }
440
441 
442  KdNode *
443  FindRandomNeighbor(KdNode *n,
444                     bool onlyUnmailed
445                     );
446 
447  KdNode *
448  GetRandomLeaf(const Plane3 &halfspace);
449
450  KdNode *
451  GetRandomLeaf(const bool onlyUnmailed = false);
452
453
454  KdNode *
455  GetNode(const Vector3 &point, const float maxArea) const;
456
457  void GetBoxIntersections(const AxisAlignedBox3 &box,
458                           vector<KdLeaf *> &leaves);
459
460  int
461  FindNeighbors(KdNode *n,
462                vector<KdNode *> &neighbors,
463                bool onlyUnmailed
464                );
465
466  bool ExportBinTree(const std::string &filename);
467  /** loads kd tree from disk. note: sorts objects by id
468  */
469  bool ImportBinTree(const std::string &filename, ObjectContainer &object);
470
471protected:
472
473  struct RayData {
474    // pointer to the actual ray
475    Ray *ray;
476   
477    // endpoints  - do we need them?
478#if USE_FIXEDPOINT_T
479    short tmin, tmax;
480#else
481    float tmin, tmax;
482#endif
483
484    RayData():ray(NULL) {}
485    RayData(Ray *r):ray(r), tmin(0),
486
487#if USE_FIXEDPOINT_T
488#define FIXEDPOINT_ONE 0x7FFE
489                    //                    tmax(0xFFFF)
490                    tmax(FIXEDPOINT_ONE)
491#else
492      tmax(1.0f)
493#endif
494    {}
495
496    RayData(Ray *r,
497            const float _min,
498            const float _max
499            ):ray(r) {
500      SetTMin(_min);
501      SetTMax(_max);
502    }
503
504    RayData(Ray *r,
505            const short _min,
506            const float _max
507            ):ray(r), tmin(_min) {
508      SetTMax(_max);
509    }
510
511    RayData(Ray *r,
512            const float _min,
513            const short _max
514            ):ray(r), tmax(_max) {
515      SetTMin(_min);
516    }
517
518    friend bool operator<(const RayData &a, const RayData &b) {
519      return a.ray < b.ray;
520    }
521   
522   
523    float ExtrapOrigin(const int axis) const {
524      return ray->GetLoc(axis) + GetTMin()*ray->GetDir(axis);
525    }
526   
527    float ExtrapTermination(const int axis) const {
528      return ray->GetLoc(axis) + GetTMax()*ray->GetDir(axis);
529    }
530   
531#if USE_FIXEDPOINT_T
532    float GetTMin () const { return tmin/(float)(FIXEDPOINT_ONE); }
533    float GetTMax () const { return tmax/(float)(FIXEDPOINT_ONE); }
534
535    void SetTMin (const float t) {
536      tmin = (short) (t*(float)(FIXEDPOINT_ONE));
537    }
538   
539    void SetTMax (const float t) {
540      tmax = (short) (t*(float)(FIXEDPOINT_ONE));
541      tmax++;
542      //      if (tmax!=0xFFFF)
543      //        tmax++;
544    }
545#else
546    float GetTMin () const { return tmin; }
547    float GetTMax () const { return tmax; }
548
549    void SetTMin (const float t) { tmin = t; }
550    void SetTMax (const float t) { tmax = t; }
551#endif
552  };
553
554  struct RayTraversalData {
555    KdNode *mNode;
556    Vector3 mExitPoint;
557    float mMaxT;
558   
559    RayTraversalData() {}
560    RayTraversalData(KdNode *n,
561                     const Vector3 &p,
562                     const float maxt):
563      mNode(n), mExitPoint(p), mMaxT(maxt) {}
564  };
565
566  // --------------------------------------------------------------
567  // For sorting objects
568  // --------------------------------------------------------------
569  struct  SortableEntry
570  {
571    enum {
572      BOX_MIN,
573      BOX_MAX
574    };
575   
576    int type;
577    float value;
578    Intersectable *intersectable;
579   
580    SortableEntry() {}
581    SortableEntry(const int t, const float v, Intersectable *i):
582      type(t), value(v), intersectable(i)
583    { }
584   
585    bool operator<(const SortableEntry &b) const {
586      return value < b.value;
587    }
588   
589  };
590
591  inline static bool iltS(SortableEntry *a, SortableEntry *b)
592  {
593          return a->value < b->value;
594  }
595
596  // reusable array of split candidates
597  vector<SortableEntry *> *splitCandidates;
598
599  float
600  BestCostRatio(
601                KdLeaf *node,
602                const AxisAlignedBox3 &box,
603                const int axis,
604                float &position,
605                int &objectsBack,
606                int &objectsFront
607                );
608
609  void
610  SortSubdivisionCandidates(
611                            KdLeaf *node,
612                            const int axis
613                           );
614
615  void
616  EvaluateLeafStats(const TraversalData &data);
617
618  KdNode *
619  SubdivideNode(
620                KdLeaf *leaf,
621                const AxisAlignedBox3 &box,
622                AxisAlignedBox3 &backBBox,
623                AxisAlignedBox3 &frontBBox
624                );
625
626  bool
627  TerminationCriteriaMet(const KdLeaf *leaf);
628 
629  int
630  SelectPlane(KdLeaf *leaf,
631              const AxisAlignedBox3 &box,
632              float &position
633              );
634
635  /** does some post processing on the objects in the new child leaves.
636   */
637  void ProcessMultipleRefs(KdLeaf *leaf) const;
638
639
640  //////////
641  // binary import / export
642 
643  void ExportBinLeaf(OUT_STREAM  &stream, KdLeaf *leaf);
644       
645  void ExportBinInterior(OUT_STREAM &stream, KdInterior *interior);
646 
647  KdLeaf *ImportBinLeaf(IN_STREAM &stream, KdInterior *parent,
648                        const ObjectContainer &objects);
649       
650  KdInterior *ImportBinInterior(IN_STREAM  &stream, KdInterior *parent);
651 
652  KdNode *ImportNextNode(IN_STREAM  &stream, KdInterior *parent,
653                         const ObjectContainer &objects);
654       
655  /** Adds this objects to the kd leaf objects.
656      @warning: Can corrupt the tree
657  */
658  void InsertObjects(KdNode *node, const ObjectContainer &objects);
659
660  int mTermMaxNodes;
661  float mSplitBorder;
662  int mTermMaxDepth;
663  int mTermMinCost;
664  float mMaxCostRatio;
665  float mCt_div_ci;
666  int mSplitMethod;
667  bool mSahUseFaces;
668  float mKdPvsArea;
669  /// root of the tree
670  KdNode *mRoot;
671  /// bounding box of the tree root
672  AxisAlignedBox3 mBox;
673  KdTreeStatistics mStat;
674
675public:
676  /// stores the kd node intersectables used for pvs
677  vector<KdIntersectable *> mKdIntersectables;
678 
679};
680
681
682}
683
684#endif
Note: See TracBrowser for help on using the repository browser.