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

Revision 2705, 15.9 KB checked in by mattausch, 17 years ago (diff)

enabled view cell visualization

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