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

Revision 1176, 12.5 KB checked in by mattausch, 18 years ago (diff)

corrected errors in the object space partition, but still buggy!

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