source: trunk/VUT/GtpVisibilityPreprocessor/src/VssTree.h @ 444

Revision 444, 19.6 KB checked in by mattausch, 19 years ago (diff)

fixed error in ray to vssray conversion

Line 
1// ================================================================
2// $Id$
3// ****************************************************************
4//
5// Initial coding by
6/**
7   @author Jiri Bittner
8*/
9
10#ifndef __VSSTREE_H__
11#define __VSSTREE_H__
12
13// Standard headers
14#include <iomanip>
15#include <vector>
16#include <functional>
17#include <stack>
18
19
20// User headers
21#include "VssRay.h"
22#include "AxisAlignedBox3.h"
23
24
25#define USE_KDNODE_VECTORS 1
26#define _RSS_STATISTICS
27#define _RSS_TRAVERSAL_STATISTICS
28
29
30#include "Statistics.h"
31#include "Ray.h"
32
33// --------------------------------------------------------------
34// Static statistics for kd-tree search
35// --------------------------------------------------------------
36class VssStatistics :
37  public StatisticsBase
38{
39public: 
40  // total number of nodes
41  int nodes;
42  // number of splits along each of the axes
43  int splits[7];
44  // totals number of rays
45  int rays;
46  // initial size of the pvs
47  int initialPvsSize;
48  // total number of query domains
49  int queryDomains;
50  // total number of ray references
51  int rayRefs;
52
53  // max depth nodes
54  int maxDepthNodes;
55  // max depth nodes
56  int minPvsNodes;
57  int minRaysNodes;
58  // max ray contribution nodes
59  int maxRayContribNodes;
60  // max depth nodes
61  int minSizeNodes;
62  int maxCostRatioNodes;
63
64  // max number of rays per node
65  int maxRayRefs;
66  // number of dynamically added ray refs
67  int addedRayRefs;
68  // number of dynamically removed ray refs
69  int removedRayRefs;
70 
71  // Constructor
72  VssStatistics() {
73    Reset();
74  }
75
76  int Nodes() const {return nodes;}
77  int Interior() const { return nodes/2; }
78  int Leaves() const { return (nodes/2) + 1; }
79
80  void Reset() {
81    nodes = 0;
82    for (int i=0; i<7; i++)
83      splits[i] = 0;
84    rays = queryDomains = 0;
85    rayRefs = 0;
86    maxDepthNodes = 0;
87    minPvsNodes = 0;
88    minRaysNodes = 0;
89    maxRayRefs = 0;
90    addedRayRefs = removedRayRefs = 0;
91        initialPvsSize = 0;
92        maxRayContribNodes = 0;
93        minSizeNodes = 0;
94        maxCostRatioNodes = 0;
95  }
96
97 
98  void
99  Print(ostream &app) const;
100
101  friend ostream &operator<<(ostream &s, const VssStatistics &stat) {
102    stat.Print(s);
103    return s;
104  }
105 
106};
107
108
109// --------------------------------------------------------------
110// For sorting rays
111// --------------------------------------------------------------
112struct  SortableEntry
113{
114  enum EType {
115    ERayMin,
116    ERayMax
117  };
118
119  int type;
120  float value;
121  void *data;
122 
123  SortableEntry() {}
124  SortableEntry(const int t, const float v, void *d):type(t),
125                                                                                                         value(v),
126                                                                                                         data(d) {}
127       
128  friend bool operator<(const SortableEntry &a, const SortableEntry &b) {
129    return a.value < b.value;
130  }
131};
132
133
134class VssTreeInterior;
135
136
137// --------------------------------------------------------------
138// KD-tree node - abstract class
139// --------------------------------------------------------------
140class VssTreeNode
141{
142public:
143
144#define USE_FIXEDPOINT_T 0
145
146  struct RayInfo
147  {
148        // pointer to the actual ray
149        VssRay *mRay;
150       
151        // endpoints  - do we need them?
152#if USE_FIXEDPOINT_T
153        short mMinT, mMaxT;
154#else
155        float mMinT, mMaxT;
156#endif
157       
158        RayInfo():mRay(NULL) {}
159       
160        RayInfo(VssRay *r):mRay(r), mMinT(0),
161#if USE_FIXEDPOINT_T
162#define FIXEDPOINT_ONE 0x7FFE
163                                           //                     mMaxT(0xFFFF)
164                                           mMaxT(FIXEDPOINT_ONE)
165#else
166          mMaxT(1.0f)
167#endif
168        {}
169       
170        RayInfo(VssRay *r,
171                        const float _min,
172                        const float _max
173                        ):mRay(r) {
174          SetMinT(_min);
175          SetMaxT(_max);
176        }
177       
178        RayInfo(VssRay *r,
179                        const short _min,
180                        const float _max
181                        ):mRay(r), mMinT(_min) {
182          SetMaxT(_max);
183        }
184       
185        RayInfo(VssRay *r,
186                        const float _min,
187                        const short _max
188                        ):mRay(r), mMaxT(_max) {
189          SetMinT(_min);
190        }
191
192        enum {
193          SOURCE_RAY = 0,
194          TERMINATION_RAY,
195          PASSING_RAY,
196          CONTAINED_RAY
197        };
198       
199        int GetRayClass() const {
200               
201          bool startsBefore = GetMinT() > 0.0f;
202          bool terminatesAfter = GetMaxT() < 1.0f;
203               
204          if (startsBefore && terminatesAfter)
205                return PASSING_RAY;
206
207          if (!startsBefore && !terminatesAfter)
208                return CONTAINED_RAY;
209               
210          if (!startsBefore)
211                return SOURCE_RAY;
212               
213          return TERMINATION_RAY;
214        }
215       
216        friend bool operator<(const RayInfo &a, const RayInfo &b) {
217          return a.mRay < b.mRay;
218        }
219 
220       
221        float ExtrapOrigin(const int axis) const {
222          return mRay->GetOrigin(axis) + GetMinT()*mRay->GetDir(axis);
223        }
224       
225        float ExtrapTermination(const int axis) const {
226          return mRay->GetOrigin(axis) + GetMaxT()*mRay->GetDir(axis);
227        }
228
229        Vector3 Extrap(const float t) const {
230          return mRay->Extrap(t);
231        }
232       
233#if USE_FIXEDPOINT_T
234        float GetMinT () const { return mMinT/(float)(FIXEDPOINT_ONE); }
235        float GetMaxT () const { return mMaxT/(float)(FIXEDPOINT_ONE); }
236       
237        void SetMinT (const float t) {
238          mMinT = (short) (t*(float)(FIXEDPOINT_ONE));
239        }
240       
241        void SetMaxT (const float t) {
242          mMaxT = (short) (t*(float)(FIXEDPOINT_ONE));
243          mMaxT++;
244          //      if (mMaxT!=0xFFFF)
245          //    mMaxT++;
246        }
247#else
248        float GetMinT () const { return mMinT; }
249        float GetMaxT () const { return mMaxT; }
250       
251        void SetMinT (const float t) { mMinT = t; }
252        void SetMaxT (const float t) { mMaxT = t; }
253#endif
254
255
256        int ComputeRayIntersection(const int axis,
257                                                           const float position,
258                                                           float &t
259                                                           ) const {
260               
261          // intersect the ray with the plane
262          float denom = mRay->GetDir(axis);
263   
264          if (fabs(denom) < 1e-20)
265                //if (denom == 0.0f)
266                return (mRay->GetOrigin(axis) > position) ? 1 : -1;
267   
268          t = (position - mRay->GetOrigin(axis))/denom;
269
270          if (t < GetMinT())
271                return (denom > 0) ? 1 : -1;
272
273          if (t > GetMaxT())
274                return (denom > 0) ? -1 : 1;
275
276          return 0;
277        }
278
279
280  };
281
282
283  typedef vector<RayInfo> RayInfoContainer;
284       
285  enum { EInterior, ELeaf };
286
287  /////////////////////////////////
288  // The actual data goes here
289 
290  // link to the parent
291  VssTreeInterior *parent;
292
293  enum {SPLIT_X=0, SPLIT_Y, SPLIT_Z, SPLIT_DIRX, SPLIT_DIRY, SPLIT_DIRZ};
294 
295  // splitting axis
296  char axis;
297       
298  // depth
299  unsigned char depth;
300 
301  //  short depth;
302  //
303  /////////////////////////////////
304 
305  inline VssTreeNode(VssTreeInterior *p);
306
307 
308  virtual ~VssTreeNode() {};
309  virtual int Type() const  = 0;
310 
311
312  bool IsLeaf() const { return axis == -1; }
313 
314  virtual void Print(ostream &s) const = 0;
315
316  virtual int GetAccessTime() {
317    return 0x7FFFFFF;
318  }
319
320 
321       
322};
323
324// --------------------------------------------------------------
325// KD-tree node - interior node
326// --------------------------------------------------------------
327class VssTreeInterior :
328  public VssTreeNode
329{
330public:
331  // plane in local modelling coordinates
332  float position;
333
334  // pointers to children
335  VssTreeNode *back, *front;
336
337  // the bbox of the node
338  AxisAlignedBox3 bbox;
339
340  // the bbox of the node
341  AxisAlignedBox3 dirBBox;
342 
343  // data for caching
344  long accesses;
345  long lastAccessTime;
346 
347  VssTreeInterior(VssTreeInterior *p):VssTreeNode(p),
348                                                                          back(NULL),
349                                                                          front(NULL),
350                                                                          accesses(0),
351                                                                          lastAccessTime(-1)
352  { }
353
354  virtual int GetAccessTime() {
355    return lastAccessTime;
356  }
357
358  void SetupChildLinks(VssTreeNode *b, VssTreeNode *f) {
359    back = b;
360    front = f;
361    b->parent = f->parent = this;
362  }
363
364  void ReplaceChildLink(VssTreeNode *oldChild, VssTreeNode *newChild) {
365    if (back == oldChild)
366      back = newChild;
367    else
368      front = newChild;
369  }
370
371  virtual int Type() const  { return EInterior; }
372 
373  virtual ~VssTreeInterior() {
374    if (back)
375      delete back;
376    if (front)
377      delete front;
378  }
379 
380  virtual void Print(ostream &s) const {
381    if (axis == 0)
382      s<<"x ";
383    else
384      if (axis == 1)
385                s<<"y ";
386      else
387                s<<"z ";
388    s<<position<<" ";
389    back->Print(s);
390    front->Print(s);
391  }
392
393 
394       
395  int ComputeRayIntersection(const RayInfo &rayData,
396                                                         float &t
397                                                         ) {
398        return rayData.ComputeRayIntersection(axis, position, t);
399  }
400
401};
402
403
404// --------------------------------------------------------------
405// KD-tree node - leaf node
406// --------------------------------------------------------------
407class VssTreeLeaf :
408  public VssTreeNode
409{
410private:
411  int mPvsSize;
412public:
413  static int mailID;
414  int mailbox;
415 
416  RayInfoContainer rays;
417  int mPassingRays;
418       
419  bool mValidPvs;
420  float mEntropyImportance;
421 
422       
423  VssTreeLeaf(VssTreeInterior *p,
424                          const int nRays
425                          ):VssTreeNode(p), rays(), mPvsSize(0), mPassingRays(0), mValidPvs(false) {
426    rays.reserve(nRays);
427  }
428 
429  virtual ~VssTreeLeaf() { }
430
431  virtual int Type() const  { return ELeaf; }
432
433  virtual void Print(ostream &s) const {
434    s<<endl<<"L: r="<<(int)rays.size()<<endl;
435  };
436 
437  void AddRay(const RayInfo &data) {
438        mValidPvs = false;
439    rays.push_back(data);
440    data.mRay->Ref();
441        if (data.GetRayClass() == RayInfo::PASSING_RAY)
442          mPassingRays++;
443  }
444       
445  int GetPvsSize() const {
446        return mPvsSize;
447  }
448
449  void SetPvsSize(const int s) {
450        mPvsSize = s;
451        mValidPvs = true;
452  }
453
454  void
455  UpdatePvsSize();
456
457  float
458  ComputePvsEntropy();
459 
460  float
461  ComputeRayLengthEntropy();
462 
463  float
464  ComputeRayTerminationEntropy();
465 
466  void
467  ComputeEntropyImportance();
468
469  void Mail() { mailbox = mailID; }
470  static void NewMail() { mailID++; }
471  bool Mailed() const { return mailbox == mailID; }
472 
473  bool Mailed(const int mail) {
474    return mailbox >= mailID + mail;
475  }
476
477  float GetAvgRayContribution() const {
478        return GetPvsSize()/((float)rays.size() + Limits::Small);
479  }
480
481  float GetImportance() const;
482 
483  float GetSqrRayContribution() const {
484        return sqr(GetPvsSize()/((float)rays.size() + Limits::Small));
485  }
486 
487  // comparator for the
488  struct less_contribution : public
489  binary_function<const VssTreeLeaf *, const VssTreeLeaf *, bool> {
490       
491        bool operator()(const VssTreeLeaf * a, const VssTreeLeaf *b) {
492          return a->GetAvgRayContribution() < b->GetAvgRayContribution();
493        }
494  };
495 
496  struct greater_contribution : public
497  binary_function<const VssTreeLeaf *, const VssTreeLeaf *, bool> {
498       
499        bool operator()(const VssTreeLeaf * a, const VssTreeLeaf *b) {
500          return a->GetAvgRayContribution() > b->GetAvgRayContribution();
501        }
502  };
503 
504  friend bool GreaterContribution(const VssTreeLeaf * a, const VssTreeLeaf *b) {
505        return a->GetAvgRayContribution() > b->GetAvgRayContribution();
506  }
507 
508};
509
510// Inline functions
511inline
512VssTreeNode::VssTreeNode(VssTreeInterior *p):
513  parent(p), axis(-1), depth(p ? p->depth + 1 : 0) {}
514
515
516
517// ---------------------------------------------------------------
518// Main LSDS search class
519// ---------------------------------------------------------------
520class VssTree
521{
522  struct TraversalData
523  { 
524    VssTreeNode *node;
525    AxisAlignedBox3 bbox;
526    int depth;
527    float priority;
528   
529    TraversalData() {}
530
531    TraversalData(VssTreeNode *n, const float p):
532      node(n), priority(p)
533    {}
534
535    TraversalData(VssTreeNode *n,
536                                  const AxisAlignedBox3 &b,
537                                  const int d):
538      node(n), bbox(b), depth(d) {}
539   
540               
541    // comparator for the
542    struct less_priority : public
543    binary_function<const TraversalData, const TraversalData, bool> {
544                       
545      bool operator()(const TraversalData a, const TraversalData b) {
546                return a.priority < b.priority;
547      }
548     
549    };
550
551    //    ~TraversalData() {}
552    //    TraversalData(const TraversalData &s):node(s.node), bbox(s.bbox), depth(s.depth) {}
553   
554    friend bool operator<(const TraversalData &a,
555                                                  const TraversalData &b) {
556      //      return a.node->queries.size() < b.node->queries.size();
557      VssTreeLeaf *leafa = (VssTreeLeaf *) a.node;
558      VssTreeLeaf *leafb = (VssTreeLeaf *) b.node;
559#if 0
560          return
561                leafa->rays.size()*a.bbox.GetVolume()
562                <
563                leafb->rays.size()*b.bbox.GetVolume();
564#endif
565#if 0
566          return
567                leafa->GetPvsSize()*a.bbox.GetVolume()
568                <
569                leafb->GetPvsSize()*b.bbox.GetVolume();
570#endif
571#if 0
572          return
573                leafa->GetPvsSize()
574                <
575                leafb->GetPvsSize();
576#endif
577#if 0
578          return
579                leafa->GetPvsSize()/(leafa->rays.size()+1)
580                >
581                leafb->GetPvsSize()/(leafb->rays.size()+1);
582#endif
583#if 1
584          return
585                leafa->GetPvsSize()*leafa->rays.size()
586                <
587                leafb->GetPvsSize()*leafb->rays.size();
588#endif
589    }
590  };
591 
592  // simplified data for ray traversal only...
593
594  struct RayTraversalData {
595   
596    VssTreeNode::RayInfo rayData;
597    VssTreeNode *node;
598   
599    RayTraversalData() {}
600    RayTraversalData(VssTreeNode *n,
601                                         const VssTreeNode::RayInfo &data):
602      rayData(data), node(n) {}
603  };
604       
605public:
606  /////////////////////////////
607  // The core pointer
608  VssTreeNode *root;
609 
610  /////////////////////////////
611  // Basic properties
612
613  // total number of nodes of the tree
614  int nodes;
615  // axis aligned bounding box of the scene
616  AxisAlignedBox3 bbox;
617
618  // axis aligned bounding box of directions
619  AxisAlignedBox3 dirBBox;
620 
621  /////////////////////////////
622  // Construction parameters
623
624  // epsilon used for the construction
625  float epsilon;
626
627  // ratio between traversal and intersection costs
628  float ct_div_ci;
629  // max depth of the tree
630  int termMaxDepth;
631  // minimal ratio of the volume of the cell and the query volume
632  float termMinSize;
633
634  // minimal pvs per node to still get subdivided
635  int termMinPvs;
636
637  // minimal ray number per node to still get subdivided
638  int termMinRays;
639       
640  // maximal cost ration to subdivide a node
641  float termMaxCostRatio;
642       
643  // maximal contribution per ray to subdivide the node
644  float termMaxRayContribution;
645
646       
647  // randomized construction
648  bool randomize;
649 
650  // type of the splitting to use fo rthe tree construction
651  enum {ESplitRegular, ESplitHeuristic, ESplitHybrid };
652  int splitType;
653
654  bool mSplitUseOnlyDrivingAxis;
655 
656  // use ray space subdivision instead of view space subdivision
657  bool mUseRss;
658
659  // interleave directional and spatial splits based on their costs
660  // if false directional splits are only performed after spatial splits
661  bool mInterleaveDirSplits;
662
663  // depth at which directional splits are performed if mInterleaveDirSplits is false
664  int mDirSplitDepth;
665 
666  // maximal size of the box on which the refdir splitting can be performed
667  // (relative to the scene bbox
668  float refDirBoxMaxSize;
669 
670  // maximum alovable memory in MB
671  float maxTotalMemory;
672
673  // maximum alovable memory for static kd tree in MB
674  float maxStaticMemory;
675
676  // this is used during the construction depending
677  // on the type of the tree and queries...
678  float maxMemory;
679
680
681  // minimal acess time for collapse
682  int accessTimeThreshold;
683
684  // minimal depth at which to perform collapse
685  int minCollapseDepth;
686
687 
688  // reusable array of split candidates
689  vector<SortableEntry> *splitCandidates;
690  /////////////////////////////
691
692  VssStatistics stat;
693       
694 
695  VssTree();
696  virtual ~VssTree();
697
698  virtual void
699  Construct(
700                        VssRayContainer &rays,
701                        AxisAlignedBox3 *forcedBoundingBox = NULL
702                        );
703       
704  // incemental construction
705  virtual void UpdateRays(VssRayContainer &remove,
706                                                  VssRayContainer &add
707                                                  );
708
709  virtual void AddRays(
710                                           VssRayContainer &add
711                                           )
712  {
713        VssRayContainer remove;
714        UpdateRays(remove, add);
715  }
716
717 
718       
719  VssTreeNode *
720  Locate(const Vector3 &v);
721       
722  VssTreeNode *
723  SubdivideNode(VssTreeLeaf *leaf,
724                                const AxisAlignedBox3 &box,
725                                AxisAlignedBox3 &backBox,
726                                AxisAlignedBox3 &frontBox
727                                );
728       
729  VssTreeNode *
730  Subdivide(const TraversalData &tdata);
731       
732  int
733  SelectPlane(VssTreeLeaf *leaf,
734                          const AxisAlignedBox3 &box,
735                          float &position,
736                          int &raysBack,
737                          int &raysFront,
738                          int &pvsBack,
739                          int &pvsFront
740                          );
741
742  void
743  SortSplitCandidates(
744                                          VssTreeLeaf *node,
745                                          const int axis
746                                          );
747       
748 
749  // return memory usage in MB
750  float GetMemUsage() const {
751    return
752      (sizeof(VssTree) +
753       stat.Leaves()*sizeof(VssTreeLeaf) +
754       stat.Interior()*sizeof(VssTreeInterior) +
755       stat.rayRefs*sizeof(VssTreeNode::RayInfo))/(1024.0f*1024.0f);
756  }
757       
758  float GetRayMemUsage() const {
759    return
760      stat.rays*(sizeof(VssRay))/(1024.0f*1024.0f);
761  }
762 
763
764  float
765  BestCostRatio(
766                                VssTreeLeaf *node,
767                                int &axis,
768                                float &position,
769                                int &raysBack,
770                                int &raysFront,
771                                int &pvsBack,
772                                int &pvsFront
773                                );
774       
775  float
776  EvalCostRatio(
777                                VssTreeLeaf *node,
778                                const int axis,
779                                const float position,
780                                int &raysBack,
781                                int &raysFront,
782                                int &pvsBack,
783                                int &pvsFront
784                                );
785
786  float
787  EvalCostRatioHeuristic(
788                                                 VssTreeLeaf *node,
789                                                 const int axis,
790                                                 float &position,
791                                                 int &raysBack,
792                                                 int &raysFront,
793                                                 int &pvsBack,
794                                                 int &pvsFront
795                                                 );
796
797  float
798  GetCostRatio(
799                           VssTreeLeaf *leaf,
800                           const int axis,
801                           const float position,
802                           const int raysBack,
803                           const int raysFront,
804                           const int pvsBack,
805                           const int pvsFront
806                           );
807
808  AxisAlignedBox3 GetBBox(const VssTreeNode *node) const {
809    if (node->parent == NULL)
810      return bbox;
811
812    if (!node->IsLeaf())
813      return ((VssTreeInterior *)node)->bbox;
814
815    if (node->parent->axis >= 3)
816      return node->parent->bbox;
817     
818    AxisAlignedBox3 box(node->parent->bbox);
819    if (node->parent->front == node)
820      box.SetMin(node->parent->axis, node->parent->position);
821    else
822      box.SetMax(node->parent->axis, node->parent->position);
823    return box;
824  }
825
826  AxisAlignedBox3 GetDirBBox(const VssTreeNode *node) const {
827
828    if (node->parent == NULL)
829      return dirBBox;
830   
831    if (!node->IsLeaf() )
832      return ((VssTreeInterior *)node)->dirBBox;
833
834    if (node->parent->axis < 3)
835      return node->parent->dirBBox;
836   
837    AxisAlignedBox3 dBBox(node->parent->dirBBox);
838
839    if (node->parent->front == node)
840      dBBox.SetMin(node->parent->axis - 3, node->parent->position);
841    else
842      dBBox.SetMax(node->parent->axis - 3, node->parent->position);
843    return dBBox;
844  }
845 
846  int
847  ReleaseMemory(const int time);
848
849  int
850  CollapseSubtree(VssTreeNode *node, const int time);
851
852  void
853  CountAccess(VssTreeInterior *node, const long time) {
854    node->accesses++;
855    node->lastAccessTime = time;
856  }
857
858  VssTreeNode *
859  SubdivideLeaf(
860                                VssTreeLeaf *leaf
861                                );
862
863  void
864  RemoveRay(VssRay *ray,
865                        vector<VssTreeLeaf *> *affectedLeaves,
866                        const bool removeAllScheduledRays
867                        );
868
869  //  void
870  //  AddRay(VssRay *ray);
871  void
872  AddRay(VssTreeNode::RayInfo &info);
873 
874  void
875  TraverseInternalNode(
876                                           RayTraversalData &data,
877                                           stack<RayTraversalData> &tstack);
878
879  void
880  EvaluateLeafStats(const TraversalData &data);
881
882
883  int
884  GetRootPvsSize() const {
885        return GetPvsSize(bbox);
886  }
887 
888  int
889  GetPvsSize(const AxisAlignedBox3 &box) const;
890
891  void
892  GetRayContributionStatistics(
893                                                           float &minRayContribution,
894                                                           float &maxRayContribution,
895                                                           float &avgRayContribution
896                                                           );
897
898  int
899  GenerateRays(const float ratioPerLeaf,
900                           SimpleRayContainer &rays);
901
902  int
903  GenerateRays(const int numberOfRays,
904                           const int numberOfLeaves,
905                           SimpleRayContainer &rays);
906               
907  float
908  GetAvgPvsSize();
909
910  int
911  UpdateSubdivision();
912
913  bool
914  TerminationCriteriaSatisfied(VssTreeLeaf *leaf);
915
916  void
917  CollectLeaves(vector<VssTreeLeaf *> &leaves);
918
919  bool
920  ClipRay(
921                  VssTreeNode::RayInfo &rayInfo,
922                  const AxisAlignedBox3 &box
923                  );
924
925  VssTreeNode *GetRoot() const { return root; }
926
927  bool
928  ValidLeaf(VssTreeLeaf *leaf) const;
929
930  void
931  GenerateLeafRays(VssTreeLeaf *leaf,
932                                   const int numberOfRays,
933                                   SimpleRayContainer &rays);
934
935
936};
937
938
939#endif // __LSDS_KDTREE_H__
940
Note: See TracBrowser for help on using the repository browser.