source: trunk/VUT/GtpVisibilityPreprocessor/src/KdTree.h @ 177

Revision 177, 9.7 KB checked in by bittner, 19 years ago (diff)
Line 
1#ifndef _KdTree_H__
2#define _KdTree_H__
3
4#include <functional>
5using namespace std;
6
7#include "Containers.h"
8#include "AxisAlignedBox3.h"
9#include "Ray.h"
10
11 
12class KdNode;
13class KdLeaf;
14class KdInterior;
15class Intersectable;
16
17
18// --------------------------------------------------------------
19// Static statistics for kd-tree search
20// --------------------------------------------------------------
21class KdTreeStatistics
22{
23public: 
24  // total number of nodes
25  int nodes;
26  // number of splits along each of the axes
27  int splits[7];
28  // totals number of rays
29  int rays;
30  // total number of query domains
31  int queryDomains;
32  // total number of ray references
33  int rayRefs;
34  // refs in non empty leafs
35  int rayRefsNonZeroQuery;
36  // total number of query references
37  int objectRefs;
38  // nodes with zero queries
39  int zeroQueryNodes;
40  // max depth nodes
41  int maxDepthNodes;
42  // max depth nodes
43  int minCostNodes;
44  // max number of rays per node
45  int maxObjectRefs;
46  // number of dynamically added ray refs
47  int addedRayRefs;
48  // number of dynamically removed ray refs
49  int removedRayRefs;
50 
51  // Constructor
52  KdTreeStatistics() {
53    Reset();
54  }
55
56  int Nodes() const {return nodes;}
57  int Interior() const { return nodes/2; }
58  int Leaves() const { return (nodes/2) + 1; }
59
60  void Reset() {
61    nodes = 0;
62    for (int i=0; i<7; i++)
63      splits[i] = 0;
64    rays = queryDomains = 0;
65    rayRefs = rayRefsNonZeroQuery = objectRefs = 0;
66    zeroQueryNodes = 0;
67    maxDepthNodes = 0;
68    minCostNodes = 0;
69    maxObjectRefs = 0;
70    addedRayRefs = removedRayRefs = 0;
71  }
72
73  void
74  Print(ostream &app) const;
75
76  friend ostream &operator<<(ostream &s, const KdTreeStatistics &stat) {
77    stat.Print(s);
78    return s;
79  }
80 
81};
82
83 
84class KdInterior;
85/** Abstract class for kd-tree node */
86class KdNode {
87public:
88  static int mailID;
89  int mailbox;
90 
91  void Mail() { mailbox = mailID; }
92  static void NewMail() { mailID++; }
93  bool Mailed() const { return mailbox == mailID; }
94
95
96  KdNode(KdInterior *parent);
97
98  /** Determines whether this node is a leaf or interior node
99      @return true if leaf
100  */
101  virtual bool IsLeaf() const = 0;
102
103  /** Determines whether this node is the root of the tree
104      @return true if root
105  */
106  virtual bool IsRoot() const {
107    return mParent == NULL;
108  }
109
110  /** Parent of the node - the parent is a little overhead for maintanance of the tree,
111      but allows various optimizations of tree traversal algorithms */
112  KdInterior *mParent;
113  int mDepth;
114};
115
116/** Implementation of the kd-tree interior node */
117class KdInterior : public KdNode {
118
119public:
120   
121  KdInterior(KdInterior *parent):KdNode(parent), mBack(NULL), mFront(NULL) {}
122
123  /** \sa KdNode::IsLeaf() */
124  virtual bool IsLeaf() const { return false; }
125
126  /** splitting axis */
127  int mAxis;
128  /** splitting position, absolute position within the bounding box of this node */
129  float mPosition;
130  /** bounding box of interior node */
131  AxisAlignedBox3 mBox;
132
133  /** back node */
134  KdNode *mBack;
135  /** front node */
136  KdNode *mFront;
137
138  void SetupChildLinks(KdNode *b, KdNode *f) {
139    mBack = b;
140    mFront = f;
141    b->mParent = f->mParent = this;
142  }
143 
144  void ReplaceChildLink(KdNode *oldChild, KdNode *newChild) {
145    if (mBack == oldChild)
146      mBack = newChild;
147    else
148      mFront = newChild;
149  }
150 
151 
152};
153 
154 
155/** Implementation of the kd-tree leaf node */
156class KdLeaf : public KdNode {
157public:
158  KdLeaf(KdInterior *parent, const int objects):KdNode(parent) {
159    mObjects.reserve(objects);
160  }
161
162 
163  /** \sa KdNode::IsLeaf() */
164  virtual bool IsLeaf() const { return true; }
165
166  /** pointers to occluders contained in this node */
167  ObjectContainer mObjects;
168 
169  /** pointers to viewcells contained in this node */
170  //  ViewCellContainer mViewCells;
171};
172 
173 
174
175/** KdTree for indexing scene entities - occluders/occludees/viewcells */
176class KdTree {
177
178protected:
179  struct TraversalData
180  { 
181    KdNode *mNode;
182    AxisAlignedBox3 mBox;
183    int mDepth;
184    float mPriority;
185   
186    TraversalData() {}
187
188    TraversalData(KdNode *n, const float p):
189      mNode(n), mPriority(p)
190    {}
191   
192    TraversalData(KdNode *n,
193                   const AxisAlignedBox3 &b,
194                   const int d):
195      mNode(n), mBox(b), mDepth(d) {}
196   
197
198    bool operator<(
199                   const TraversalData &b) const {
200      KdLeaf *leafa = (KdLeaf *) mNode;
201      KdLeaf *leafb = (KdLeaf *) b.mNode;
202      return
203        leafa->mObjects.size()*mBox.SurfaceArea()
204        <
205        leafb->mObjects.size()*b.mBox.SurfaceArea();
206    }
207
208
209    // comparator for the
210    struct less_priority : public
211    binary_function<const TraversalData, const TraversalData, bool> {
212     
213      bool operator()(const TraversalData a, const TraversalData b) {
214        return a.mPriority < b.mPriority;
215      }
216     
217    };
218
219  };
220
221 
222
223public:
224
225  enum {SPLIT_OBJECT_MEDIAN,
226        SPLIT_SPATIAL_MEDIAN,
227        SPLIT_SAH};
228 
229  KdTree();
230 
231   
232  /** Insert view cell into the tree */
233  virtual void InsertViewCell(ViewCell *viewCell) {
234    //      mRoot->mViewcells.push_back(viewCell);
235  }
236
237  virtual bool Construct();
238
239  /** Check whether subdivision criteria are met for the given subtree.
240      If not subdivide the leafs of the subtree. The criteria are specified in
241      the environment as well as the subdivision method. By default surface area
242      heuristics is used.
243       
244      @param subtree root of the subtree
245
246      @return true if subdivision was performed, false if subdivision criteria
247      were already met
248  */
249  virtual KdNode *Subdivide(const TraversalData &tdata);
250
251  /** Get the root of the tree */
252  KdNode *GetRoot() const {
253    return mRoot;
254  }
255
256
257  AxisAlignedBox3 GetBox() const { return mBox; }
258
259  int
260  CastRay(
261          Ray &ray
262          );
263
264  const KdTreeStatistics &GetStatistics() const {
265    return mStat;
266  }
267
268  void
269  CollectObjects(KdNode *n, ObjectContainer &objects);
270 
271    AxisAlignedBox3 GetBox(const KdNode *node) const {
272    KdInterior *parent = node->mParent;
273    if (parent == NULL)
274      return mBox;
275   
276    if (!node->IsLeaf())
277      return ((KdInterior *)node)->mBox;
278   
279    AxisAlignedBox3 box(parent->mBox);
280    if (parent->mFront == node)
281      box.SetMin(parent->mAxis, parent->mPosition);
282    else
283      box.SetMax(parent->mAxis, parent->mPosition);
284    return box;
285  }
286
287  KdNode *
288  FindRandomNeighbor(KdNode *n,
289                     bool onlyUnmailed
290                     );
291
292  int
293  FindNeighbors(KdNode *n,
294                vector<KdNode *> &neighbors,
295                bool onlyUnmailed
296                );
297 
298protected:
299
300  struct RayData {
301    // pointer to the actual ray
302    Ray *ray;
303   
304    // endpoints  - do we need them?
305#if USE_FIXEDPOINT_T
306    short tmin, tmax;
307#else
308    float tmin, tmax;
309#endif
310
311    RayData():ray(NULL) {}
312    RayData(Ray *r):ray(r), tmin(0),
313
314#if USE_FIXEDPOINT_T
315#define FIXEDPOINT_ONE 0x7FFE
316                          //                      tmax(0xFFFF)
317                          tmax(FIXEDPOINT_ONE)
318#else
319      tmax(1.0f)
320#endif
321    {}
322
323    RayData(Ray *r,
324            const float _min,
325            const float _max
326            ):ray(r) {
327      SetTMin(_min);
328      SetTMax(_max);
329    }
330
331    RayData(Ray *r,
332            const short _min,
333            const float _max
334            ):ray(r), tmin(_min) {
335      SetTMax(_max);
336    }
337
338    RayData(Ray *r,
339            const float _min,
340            const short _max
341            ):ray(r), tmax(_max) {
342      SetTMin(_min);
343    }
344
345    friend bool operator<(const RayData &a, const RayData &b) {
346      return a.ray < b.ray;
347    }
348   
349   
350    float ExtrapOrigin(const int axis) const {
351      return ray->GetLoc(axis) + GetTMin()*ray->GetDir(axis);
352    }
353   
354    float ExtrapTermination(const int axis) const {
355      return ray->GetLoc(axis) + GetTMax()*ray->GetDir(axis);
356    }
357   
358#if USE_FIXEDPOINT_T
359    float GetTMin () const { return tmin/(float)(FIXEDPOINT_ONE); }
360    float GetTMax () const { return tmax/(float)(FIXEDPOINT_ONE); }
361
362    void SetTMin (const float t) {
363      tmin = (short) (t*(float)(FIXEDPOINT_ONE));
364    }
365   
366    void SetTMax (const float t) {
367      tmax = (short) (t*(float)(FIXEDPOINT_ONE));
368      tmax++;
369      //      if (tmax!=0xFFFF)
370      //        tmax++;
371    }
372#else
373    float GetTMin () const { return tmin; }
374    float GetTMax () const { return tmax; }
375
376    void SetTMin (const float t) { tmin = t; }
377    void SetTMax (const float t) { tmax = t; }
378#endif
379  };
380
381  struct RayTraversalData {
382    KdNode *mNode;
383    Vector3 mExitPoint;
384    float mMaxT;
385   
386    RayTraversalData() {}
387    RayTraversalData(KdNode *n,
388                     const Vector3 &p,
389                     const float maxt):
390      mNode(n), mExitPoint(p), mMaxT(maxt) {}
391  };
392
393  // --------------------------------------------------------------
394  // For sorting objects
395  // --------------------------------------------------------------
396  struct  SortableEntry
397  {
398    enum {
399      BOX_MIN,
400      BOX_MAX
401    };
402   
403    int type;
404    float value;
405    Intersectable *intersectable;
406   
407    SortableEntry() {}
408    SortableEntry(const int t, const float v, Intersectable *i):type(t),
409                                                                value(v),
410                                                                intersectable(i) {}
411   
412    bool operator<(const SortableEntry &b) const {
413      return value < b.value;
414    }
415   
416  };
417 
418  // reusable array of split candidates
419  vector<SortableEntry> *splitCandidates;
420
421  float
422  BestCostRatio(
423                KdLeaf *node,
424                const AxisAlignedBox3 &box,
425                const int axis,
426                float &position,
427                int &objectsBack,
428                int &objectsFront
429                );
430
431  void
432  SortSplitCandidates(
433                      KdLeaf *node,
434                      const int axis
435                      );
436
437  void
438  EvaluateLeafStats(const TraversalData &data);
439
440  KdNode *
441  SubdivideNode(
442                KdLeaf *leaf,
443                const AxisAlignedBox3 &box,
444                AxisAlignedBox3 &backBBox,
445                AxisAlignedBox3 &frontBBox
446                );
447
448  bool
449  TerminationCriteriaMet(const KdLeaf *leaf);
450 
451  int
452  SelectPlane(KdLeaf *leaf,
453              const AxisAlignedBox3 &box,
454              float &position
455              );
456
457
458
459  float mSplitBorder;
460  int mTermMaxDepth;
461  int mTermMinCost;
462  float mMaxCostRatio;
463  float mCt_div_ci;
464  int mSplitMethod;
465  bool mSahUseFaces;
466  /// root of the tree
467  KdNode *mRoot;
468  /// bounding box of the tree root
469  AxisAlignedBox3 mBox;
470  KdTreeStatistics mStat;
471
472};
473 
474
475
476
477
478
479#endif
Note: See TracBrowser for help on using the repository browser.