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

Revision 329, 10.2 KB checked in by mattausch, 19 years ago (diff)

worked on ray based subdivision

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, const int contributions) {
164    mPassingRays.AddRay(ray, contributions);
165        Debug << "adding passing ray" << endl;
166  }
167 
168  /** \sa KdNode::IsLeaf() */
169  virtual bool IsLeaf() const { return true; }
170 
171
172 
173
174  /** pointers to occluders contained in this node */
175  ObjectContainer mObjects;
176 
177  /** pointers to viewcells contained in this node */
178  //  ViewCellContainer mViewCells;
179
180  /** Ray set description of the rays passing through this node */
181  PassingRaySet mPassingRays;
182
183  /** PVS consisting of visible KdTree nodes */
184  KdPvs mKdPvs;
185 
186};
187 
188 
189
190/** KdTree for indexing scene entities - occluders/occludees/viewcells */
191class KdTree {
192
193protected:
194  struct TraversalData
195  { 
196    KdNode *mNode;
197    AxisAlignedBox3 mBox;
198    int mDepth;
199    float mPriority;
200   
201    TraversalData() {}
202
203    TraversalData(KdNode *n, const float p):
204      mNode(n), mPriority(p)
205    {}
206   
207    TraversalData(KdNode *n,
208                   const AxisAlignedBox3 &b,
209                   const int d):
210      mNode(n), mBox(b), mDepth(d) {}
211   
212
213    bool operator<(
214                   const TraversalData &b) const {
215      KdLeaf *leafa = (KdLeaf *) mNode;
216      KdLeaf *leafb = (KdLeaf *) b.mNode;
217      return
218        leafa->mObjects.size()*mBox.SurfaceArea()
219        <
220        leafb->mObjects.size()*b.mBox.SurfaceArea();
221    }
222
223
224    // comparator for the
225    struct less_priority : public
226    binary_function<const TraversalData, const TraversalData, bool> {
227     
228      bool operator()(const TraversalData a, const TraversalData b) {
229        return a.mPriority < b.mPriority;
230      }
231     
232    };
233
234  };
235
236 
237
238public:
239
240  enum {SPLIT_OBJECT_MEDIAN,
241        SPLIT_SPATIAL_MEDIAN,
242        SPLIT_SAH};
243 
244  KdTree();
245 
246   
247  /** Insert view cell into the tree */
248  virtual void InsertViewCell(ViewCell *viewCell) {
249    //      mRoot->mViewcells.push_back(viewCell);
250  }
251
252  virtual bool Construct();
253
254  /** Check whether subdivision criteria are met for the given subtree.
255      If not subdivide the leafs of the subtree. The criteria are specified in
256      the environment as well as the subdivision method. By default surface area
257      heuristics is used.
258       
259      @param subtree root of the subtree
260
261      @return true if subdivision was performed, false if subdivision criteria
262      were already met
263  */
264  virtual KdNode *Subdivide(const TraversalData &tdata);
265
266  /** Get the root of the tree */
267  KdNode *GetRoot() const {
268    return mRoot;
269  }
270
271
272  AxisAlignedBox3 GetBox() const { return mBox; }
273
274  int
275  CastRay(
276          Ray &ray
277          );
278
279  const KdTreeStatistics &GetStatistics() const {
280    return mStat;
281  }
282
283  void
284  CollectObjects(KdNode *n, ObjectContainer &objects);
285
286  void
287  CollectLeaves(vector<KdLeaf *> &leaves);
288
289  AxisAlignedBox3 GetBox(const KdNode *node) const {
290    KdInterior *parent = node->mParent;
291    if (parent == NULL)
292      return mBox;
293   
294    if (!node->IsLeaf())
295      return ((KdInterior *)node)->mBox;
296   
297    AxisAlignedBox3 box(parent->mBox);
298    if (parent->mFront == node)
299      box.SetMin(parent->mAxis, parent->mPosition);
300    else
301      box.SetMax(parent->mAxis, parent->mPosition);
302    return box;
303  }
304
305  KdNode *
306  FindRandomNeighbor(KdNode *n,
307                     bool onlyUnmailed
308                     );
309
310 
311  KdNode *
312  KdTree::GetRandomLeaf(const Plane3 &halfspace);
313 
314  int
315  FindNeighbors(KdNode *n,
316                vector<KdNode *> &neighbors,
317                bool onlyUnmailed
318                );
319
320  int
321  CollectLeafPvs();
322
323protected:
324
325  struct RayData {
326    // pointer to the actual ray
327    Ray *ray;
328   
329    // endpoints  - do we need them?
330#if USE_FIXEDPOINT_T
331    short tmin, tmax;
332#else
333    float tmin, tmax;
334#endif
335
336    RayData():ray(NULL) {}
337    RayData(Ray *r):ray(r), tmin(0),
338
339#if USE_FIXEDPOINT_T
340#define FIXEDPOINT_ONE 0x7FFE
341                          //                      tmax(0xFFFF)
342                          tmax(FIXEDPOINT_ONE)
343#else
344      tmax(1.0f)
345#endif
346    {}
347
348    RayData(Ray *r,
349            const float _min,
350            const float _max
351            ):ray(r) {
352      SetTMin(_min);
353      SetTMax(_max);
354    }
355
356    RayData(Ray *r,
357            const short _min,
358            const float _max
359            ):ray(r), tmin(_min) {
360      SetTMax(_max);
361    }
362
363    RayData(Ray *r,
364            const float _min,
365            const short _max
366            ):ray(r), tmax(_max) {
367      SetTMin(_min);
368    }
369
370    friend bool operator<(const RayData &a, const RayData &b) {
371      return a.ray < b.ray;
372    }
373   
374   
375    float ExtrapOrigin(const int axis) const {
376      return ray->GetLoc(axis) + GetTMin()*ray->GetDir(axis);
377    }
378   
379    float ExtrapTermination(const int axis) const {
380      return ray->GetLoc(axis) + GetTMax()*ray->GetDir(axis);
381    }
382   
383#if USE_FIXEDPOINT_T
384    float GetTMin () const { return tmin/(float)(FIXEDPOINT_ONE); }
385    float GetTMax () const { return tmax/(float)(FIXEDPOINT_ONE); }
386
387    void SetTMin (const float t) {
388      tmin = (short) (t*(float)(FIXEDPOINT_ONE));
389    }
390   
391    void SetTMax (const float t) {
392      tmax = (short) (t*(float)(FIXEDPOINT_ONE));
393      tmax++;
394      //      if (tmax!=0xFFFF)
395      //        tmax++;
396    }
397#else
398    float GetTMin () const { return tmin; }
399    float GetTMax () const { return tmax; }
400
401    void SetTMin (const float t) { tmin = t; }
402    void SetTMax (const float t) { tmax = t; }
403#endif
404  };
405
406  struct RayTraversalData {
407    KdNode *mNode;
408    Vector3 mExitPoint;
409    float mMaxT;
410   
411    RayTraversalData() {}
412    RayTraversalData(KdNode *n,
413                     const Vector3 &p,
414                     const float maxt):
415      mNode(n), mExitPoint(p), mMaxT(maxt) {}
416  };
417
418  // --------------------------------------------------------------
419  // For sorting objects
420  // --------------------------------------------------------------
421  struct  SortableEntry
422  {
423    enum {
424      BOX_MIN,
425      BOX_MAX
426    };
427   
428    int type;
429    float value;
430    Intersectable *intersectable;
431   
432    SortableEntry() {}
433    SortableEntry(const int t, const float v, Intersectable *i):type(t),
434                                                                value(v),
435                                                                intersectable(i) {}
436   
437    bool operator<(const SortableEntry &b) const {
438      return value < b.value;
439    }
440   
441  };
442 
443  // reusable array of split candidates
444  vector<SortableEntry> *splitCandidates;
445
446  float
447  BestCostRatio(
448                KdLeaf *node,
449                const AxisAlignedBox3 &box,
450                const int axis,
451                float &position,
452                int &objectsBack,
453                int &objectsFront
454                );
455
456  void
457  SortSplitCandidates(
458                      KdLeaf *node,
459                      const int axis
460                      );
461
462  void
463  EvaluateLeafStats(const TraversalData &data);
464
465  KdNode *
466  SubdivideNode(
467                KdLeaf *leaf,
468                const AxisAlignedBox3 &box,
469                AxisAlignedBox3 &backBBox,
470                AxisAlignedBox3 &frontBBox
471                );
472
473  bool
474  TerminationCriteriaMet(const KdLeaf *leaf);
475 
476  int
477  SelectPlane(KdLeaf *leaf,
478              const AxisAlignedBox3 &box,
479              float &position
480              );
481
482
483
484  float mSplitBorder;
485  int mTermMaxDepth;
486  int mTermMinCost;
487  float mMaxCostRatio;
488  float mCt_div_ci;
489  int mSplitMethod;
490  bool mSahUseFaces;
491  /// root of the tree
492  KdNode *mRoot;
493  /// bounding box of the tree root
494  AxisAlignedBox3 mBox;
495  KdTreeStatistics mStat;
496 
497};
498 
499
500
501
502
503
504#endif
Note: See TracBrowser for help on using the repository browser.