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

Revision 2606, 14.6 KB checked in by bittner, 16 years ago (diff)

merge on nemo

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