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

Revision 434, 19.4 KB checked in by bittner, 19 years ago (diff)

vssbsp merge, tab change

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
146struct 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       
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="<<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        void SetPvsSize(const int s) {
449                mPvsSize = s;
450                mValidPvs = true;
451        }
452
453        void
454        UpdatePvsSize();
455
456  void Mail() { mailbox = mailID; }
457  static void NewMail() { mailID++; }
458  bool Mailed() const { return mailbox == mailID; }
459 
460  bool Mailed(const int mail) {
461    return mailbox >= mailID + mail;
462  }
463
464        float GetAvgRayContribution() const {
465                return GetPvsSize()/((float)rays.size() + Limits::Small);
466        }
467
468        float GetSqrRayContribution() const {
469                return sqr(GetPvsSize()/((float)rays.size() + Limits::Small));
470        }
471
472        // comparator for the
473        struct less_contribution : public
474        binary_function<const VssTreeLeaf *, const VssTreeLeaf *, bool> {
475               
476                bool operator()(const VssTreeLeaf * a, const VssTreeLeaf *b) {
477                        return a->GetAvgRayContribution() < b->GetAvgRayContribution();
478                }
479        };
480
481        struct greater_contribution : public
482        binary_function<const VssTreeLeaf *, const VssTreeLeaf *, bool> {
483               
484                bool operator()(const VssTreeLeaf * a, const VssTreeLeaf *b) {
485                        return a->GetAvgRayContribution() > b->GetAvgRayContribution();
486                }
487        };
488       
489        friend bool GreaterContribution(const VssTreeLeaf * a, const VssTreeLeaf *b) {
490                return a->GetAvgRayContribution() > b->GetAvgRayContribution();
491        }
492       
493};
494
495// Inline functions
496inline
497VssTreeNode::VssTreeNode(VssTreeInterior *p):
498  parent(p), axis(-1), depth(p ? p->depth + 1 : 0) {}
499
500
501
502// ---------------------------------------------------------------
503// Main LSDS search class
504// ---------------------------------------------------------------
505class VssTree
506{
507  struct TraversalData
508  { 
509    VssTreeNode *node;
510    AxisAlignedBox3 bbox;
511    int depth;
512    float priority;
513   
514    TraversalData() {}
515
516    TraversalData(VssTreeNode *n, const float p):
517      node(n), priority(p)
518    {}
519
520    TraversalData(VssTreeNode *n,
521                   const AxisAlignedBox3 &b,
522                   const int d):
523      node(n), bbox(b), depth(d) {}
524   
525               
526    // comparator for the
527    struct less_priority : public
528    binary_function<const TraversalData, const TraversalData, bool> {
529                       
530      bool operator()(const TraversalData a, const TraversalData b) {
531                                return a.priority < b.priority;
532      }
533     
534    };
535
536    //    ~TraversalData() {}
537    //    TraversalData(const TraversalData &s):node(s.node), bbox(s.bbox), depth(s.depth) {}
538   
539    friend bool operator<(const TraversalData &a,
540                                                                                                        const TraversalData &b) {
541      //      return a.node->queries.size() < b.node->queries.size();
542      VssTreeLeaf *leafa = (VssTreeLeaf *) a.node;
543      VssTreeLeaf *leafb = (VssTreeLeaf *) b.node;
544#if 0
545                        return
546                                leafa->rays.size()*a.bbox.GetVolume()
547                                <
548                                leafb->rays.size()*b.bbox.GetVolume();
549#endif
550#if 0
551                        return
552                                leafa->GetPvsSize()*a.bbox.GetVolume()
553                                <
554                                leafb->GetPvsSize()*b.bbox.GetVolume();
555#endif
556#if 0
557                        return
558                                leafa->GetPvsSize()
559                                <
560                                leafb->GetPvsSize();
561#endif
562#if 0
563                        return
564                                leafa->GetPvsSize()/(leafa->rays.size()+1)
565                                >
566                                leafb->GetPvsSize()/(leafb->rays.size()+1);
567#endif
568#if 1
569                        return
570                                leafa->GetPvsSize()*leafa->rays.size()
571                                <
572                                leafb->GetPvsSize()*leafb->rays.size();
573#endif
574    }
575  };
576 
577  // simplified data for ray traversal only...
578
579  struct RayTraversalData {
580   
581    VssTreeNode::RayInfo rayData;
582    VssTreeNode *node;
583   
584    RayTraversalData() {}
585    RayTraversalData(VssTreeNode *n,
586                                                                                 const VssTreeNode::RayInfo &data):
587      rayData(data), node(n) {}
588  };
589       
590public:
591  /////////////////////////////
592  // The core pointer
593  VssTreeNode *root;
594 
595  /////////////////////////////
596  // Basic properties
597
598  // total number of nodes of the tree
599  int nodes;
600  // axis aligned bounding box of the scene
601  AxisAlignedBox3 bbox;
602
603  // axis aligned bounding box of directions
604  AxisAlignedBox3 dirBBox;
605 
606  /////////////////////////////
607  // Construction parameters
608
609  // epsilon used for the construction
610  float epsilon;
611
612  // ratio between traversal and intersection costs
613  float ct_div_ci;
614  // max depth of the tree
615  int termMaxDepth;
616  // minimal ratio of the volume of the cell and the query volume
617  float termMinSize;
618
619        // minimal pvs per node to still get subdivided
620  int termMinPvs;
621
622        // minimal ray number per node to still get subdivided
623  int termMinRays;
624       
625  // maximal cost ration to subdivide a node
626  float termMaxCostRatio;
627       
628        // maximal contribution per ray to subdivide the node
629        float termMaxRayContribution;
630
631       
632  // randomized construction
633  bool randomize;
634
635  // type of the splitting to use fo rthe tree construction
636  enum {ESplitRegular, ESplitHeuristic, ESplitHybrid };
637  int splitType;
638
639        bool mSplitUseOnlyDrivingAxis;
640
641        // use ray space subdivision instead of view space subdivision
642        bool mUseRss;
643       
644  // maximal size of the box on which the refdir splitting can be performed
645  // (relative to the scene bbox
646  float refDirBoxMaxSize;
647 
648  // maximum alovable memory in MB
649  float maxTotalMemory;
650
651  // maximum alovable memory for static kd tree in MB
652  float maxStaticMemory;
653
654  // this is used during the construction depending
655  // on the type of the tree and queries...
656  float maxMemory;
657
658
659  // minimal acess time for collapse
660  int accessTimeThreshold;
661
662        // minimal depth at which to perform collapse
663  int minCollapseDepth;
664
665 
666  // reusable array of split candidates
667  vector<SortableEntry> *splitCandidates;
668  /////////////////////////////
669
670        VssStatistics stat;
671       
672 
673  VssTree();
674  virtual ~VssTree();
675
676  virtual void
677  Construct(
678                                                VssRayContainer &rays,
679                                                AxisAlignedBox3 *forcedBoundingBox = NULL
680                                                );
681       
682  // incemental construction
683  virtual void UpdateRays(VssRayContainer &remove,
684                                                                                                        VssRayContainer &add
685                                                                                                        );
686
687        virtual void AddRays(
688                                                                                         VssRayContainer &add
689                                                                                         )
690        {
691                VssRayContainer remove;
692                UpdateRays(remove, add);
693        }
694
695 
696       
697  VssTreeNode *
698  Locate(const Vector3 &v);
699       
700  VssTreeNode *
701  SubdivideNode(VssTreeLeaf *leaf,
702                                                                const AxisAlignedBox3 &box,
703                                                                AxisAlignedBox3 &backBox,
704                                                                AxisAlignedBox3 &frontBox
705                                                                );
706       
707  VssTreeNode *
708  Subdivide(const TraversalData &tdata);
709       
710  int
711  SelectPlane(VssTreeLeaf *leaf,
712                                                        const AxisAlignedBox3 &box,
713                                                        float &position,
714                                                        int &raysBack,
715                                                        int &raysFront,
716                                                        int &pvsBack,
717                                                        int &pvsFront
718                                                        );
719
720  void
721  SortSplitCandidates(
722                                                                                        VssTreeLeaf *node,
723                                                                                        const int axis
724                                                                                        );
725       
726 
727  // return memory usage in MB
728  float GetMemUsage() const {
729    return
730      (sizeof(VssTree) +
731       stat.Leaves()*sizeof(VssTreeLeaf) +
732       stat.Interior()*sizeof(VssTreeInterior) +
733       stat.rayRefs*sizeof(VssTreeNode::RayInfo))/(1024.0f*1024.0f);
734  }
735       
736  float GetRayMemUsage() const {
737    return
738      stat.rays*(sizeof(VssRay))/(1024.0f*1024.0f);
739  }
740 
741
742        float
743        BestCostRatio(
744                                                                VssTreeLeaf *node,
745                                                                int &axis,
746                                                                float &position,
747                                                                int &raysBack,
748                                                                int &raysFront,
749                                                                int &pvsBack,
750                                                                int &pvsFront
751                                                                );
752       
753        float
754        EvalCostRatio(
755                                                                VssTreeLeaf *node,
756                                                                const int axis,
757                                                                const float position,
758                                                                int &raysBack,
759                                                                int &raysFront,
760                                                                int &pvsBack,
761                                                                int &pvsFront
762                                                                );
763
764        float
765        EvalCostRatioHeuristic(
766                                                                                                 VssTreeLeaf *node,
767                                                                                                 const int axis,
768                                                                                                 float &position,
769                                                                                                 int &raysBack,
770                                                                                                 int &raysFront,
771                                                                                                 int &pvsBack,
772                                                                                                 int &pvsFront
773                                                                                                 );
774
775        float
776        GetCostRatio(
777                                                         VssTreeLeaf *leaf,
778                                                         const int axis,
779                                                         const float position,
780                                                         const int raysBack,
781                                                         const int raysFront,
782                                                         const int pvsBack,
783                                                         const int pvsFront
784                                                         );
785
786  AxisAlignedBox3 GetBBox(const VssTreeNode *node) const {
787    if (node->parent == NULL)
788      return bbox;
789
790    if (!node->IsLeaf())
791      return ((VssTreeInterior *)node)->bbox;
792
793    if (node->parent->axis >= 3)
794      return node->parent->bbox;
795     
796    AxisAlignedBox3 box(node->parent->bbox);
797    if (node->parent->front == node)
798      box.SetMin(node->parent->axis, node->parent->position);
799    else
800      box.SetMax(node->parent->axis, node->parent->position);
801    return box;
802  }
803
804  AxisAlignedBox3 GetDirBBox(const VssTreeNode *node) const {
805
806    if (node->parent == NULL)
807      return dirBBox;
808   
809    if (!node->IsLeaf() )
810      return ((VssTreeInterior *)node)->dirBBox;
811
812    if (node->parent->axis < 3)
813      return node->parent->dirBBox;
814   
815    AxisAlignedBox3 dBBox(node->parent->dirBBox);
816
817    if (node->parent->front == node)
818      dBBox.SetMin(node->parent->axis - 3, node->parent->position);
819    else
820      dBBox.SetMax(node->parent->axis - 3, node->parent->position);
821    return dBBox;
822  }
823 
824  int
825  ReleaseMemory(const int time);
826
827  int
828  CollapseSubtree(VssTreeNode *node, const int time);
829
830  void
831  CountAccess(VssTreeInterior *node, const long time) {
832    node->accesses++;
833    node->lastAccessTime = time;
834  }
835
836  VssTreeNode *
837  SubdivideLeaf(
838                                                                VssTreeLeaf *leaf
839                                                                );
840
841  void
842  RemoveRay(VssRay *ray,
843                                                vector<VssTreeLeaf *> *affectedLeaves,
844                                                const bool removeAllScheduledRays
845                                                );
846
847        //  void
848        //  AddRay(VssRay *ray);
849        void
850        AddRay(VssTreeNode::RayInfo &info);
851
852  void
853  TraverseInternalNode(
854                                                                                         RayTraversalData &data,
855                                                                                         stack<RayTraversalData> &tstack);
856
857        void
858  EvaluateLeafStats(const TraversalData &data);
859
860
861        int
862        GetRootPvsSize() const {
863                return GetPvsSize(bbox);
864        }
865       
866        int
867        GetPvsSize(const AxisAlignedBox3 &box) const;
868
869        void
870        GetRayContributionStatistics(
871                                                                                                                         float &minRayContribution,
872                                                                                                                         float &maxRayContribution,
873                                                                                                                         float &avgRayContribution
874                                                                                                                         );
875
876        int
877        GenerateRays(const float ratioPerLeaf,
878                                                         SimpleRayContainer &rays);
879
880        int
881        GenerateRays(const int numberOfRays,
882                                                         const int numberOfLeaves,
883                                                         SimpleRayContainer &rays);
884               
885        float
886        GetAvgPvsSize();
887
888        int
889        UpdateSubdivision();
890
891        bool
892        TerminationCriteriaSatisfied(VssTreeLeaf *leaf);
893
894        void
895        CollectLeaves(vector<VssTreeLeaf *> &leaves);
896
897        bool
898        ClipRay(
899                                        VssTreeNode::RayInfo &rayInfo,
900                                        const AxisAlignedBox3 &box
901                                        );
902
903        VssTreeNode *GetRoot() const { return root; }
904
905        bool
906        ValidLeaf(VssTreeLeaf *leaf) const;
907
908        void
909        GenerateLeafRays(VssTreeLeaf *leaf,
910                                                                         const int numberOfRays,
911                                                                         SimpleRayContainer &rays);
912
913
914};
915
916
917#endif // __LSDS_KDTREE_H__
918
Note: See TracBrowser for help on using the repository browser.