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

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