VR-Forces 4.7 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
DtNTree.h
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright (c) 2016 MAK Technologies, Inc.
3 ** All rights reserved.
4 ******************************************************************************/
5 
9 
10 #include <boost/shared_ptr.hpp>
11 #include <boost/weak_ptr.hpp>
12 #include <boost/enable_shared_from_this.hpp>
13 
14 #include <cassert>
15 
16 namespace makVrv
17 {
21  {
22  public:
24  {
25  public:
26  explicit scoped_lock(DtNTreeNullMutexPolicy&, bool=true) { }
27 
28  bool upgrade_to_writer() { return true; }
30  void release() { }
31  };
32  };
33 
35  template <typename Tree>
37  {
38  typedef boost::shared_ptr<Tree> Ptr;
39  typedef boost::weak_ptr<Tree> ParentPtr;
40  };
41 
43  template <typename Tree>
45  {
46  typedef boost::weak_ptr<Tree> Ptr;
47  typedef boost::shared_ptr<Tree> ParentPtr;
48  };
49 
65  template <
66  typename T,
67  unsigned int Dimensions = 3,
68  typename Mutex = DtNTreeNullMutexPolicy,
69  template <typename> class SubcellTraits = DtNTreeSharedPointerTraits,
70  typename BoundsType = double
71  >
72  class DtNTree
73  : public boost::enable_shared_from_this< DtNTree<T,Dimensions,Mutex,SubcellTraits,BoundsType> >
74  {
76 
77  template <unsigned int A, unsigned int B>
78  struct Power
79  {
80  static const unsigned int value = A * Power<A, B - 1>::value;
81  };
82  template <unsigned int A>
83  struct Power<A, 0>
84  {
85  static const unsigned int value = 1;
86  };
88 
91 
92  template <typename Z>
93  static boost::shared_ptr<Z> Get(const boost::shared_ptr<Z>& p) { return p ;}
94 
95  template <typename Z>
96  static boost::shared_ptr<Z> Get(const boost::weak_ptr<Z>& p) { return p.lock(); }
97 
98  template <typename Z>
99  static void Set(boost::shared_ptr<Z>& p, const boost::shared_ptr<Z>& to) { p = to; }
100 
101  template <typename Z>
102  static void Set(boost::shared_ptr<Z>& p, const boost::weak_ptr<Z>& to) { p = to.lock(); }
103 
104  template <typename Z>
105  static void Set(boost::weak_ptr<Z>& p, const boost::shared_ptr<Z>& to) { p = to; }
106 
107  template <typename Z>
108  static void Set(boost::weak_ptr<Z>& p, const boost::weak_ptr<Z>& to) { p = to; }
110 
111  typedef typename SubcellTraits<DtNTree>::Ptr Ptr;
112  typedef typename SubcellTraits<DtNTree>::ParentPtr ParentPtr;
113 
114  public:
115  class Query;
116  friend class Query;
117 
119  static const unsigned int NumberOfIndices = Power<2, Dimensions>::value;
120 
122  struct Range
123  {
126  : minimum(std::numeric_limits<BoundsType>::min())
127  , maximum(std::numeric_limits<BoundsType>::max()) { }
128 
130  Range(BoundsType min, BoundsType max)
131  : minimum(min), maximum(max) { }
132 
134  double size() const
135  {
136  return maximum - minimum;
137  }
138 
140  bool intersects(const Range& other) const
141  {
142  if (maximum < other.minimum) return false;
143 
144  if (other.maximum < minimum) return false;
145 
146  return true;
147  }
148 
149  BoundsType minimum, maximum;
150  };
151 
153  class Bounds
154  {
155  public:
157  Bounds makeSubBounds(unsigned int index) const
158  {
159  Bounds newBounds(*this);
160 
161  for (unsigned int bit=1, d=0; d < Dimensions; ++d, bit=bit<<1)
162  {
163  // compute center point of range for this dimension
164  Range r = range(d);
165  BoundsType middle = ((r.maximum - r.minimum)/2) + r.minimum;
166 
167  // if the bit for this dimension is 1 then it will be from
168  // the center to the max, otherwise from the min to the center
169  // min and max are set when myRanges is initialized
170  if (index & bit)
171  {
172  newBounds.range(d).minimum = middle;
173  }
174  else
175  {
176  newBounds.range(d).maximum = middle;
177  }
178  }
179 
180  return newBounds;
181  }
182 
184  double size() const
185  {
186  double value = 1;
187 
188  for (unsigned int d=0; d < Dimensions; ++d)
189  {
190  value *= range(d).size();
191  }
192 
193  return value;
194  }
195 
197  bool intersects(const Bounds& other) const
198  {
199  for (unsigned int d=0; d < Dimensions; ++d)
200  {
201  // if any of the dimensions don't overlap then the entire thing doesn't
202  if (!range(d).intersects(other.range(d)))
203  {
204  return false;
205  }
206  }
207 
208  return true;
209  }
210 
212 
213  Range& range(unsigned int i) { assert(i < Dimensions); return myRanges[i]; }
214  const Range& range(unsigned int i) const { assert(i < Dimensions); return myRanges[i]; }
216 
217  private:
218  Range myRanges[Dimensions];
219  };
220 
222  class Subcell
223  {
224  public:
226  const Bounds& bounds() const { return myBounds; }
227 
229  boost::shared_ptr<DtNTree> getPtr(DtNTree& tree, Query& query)
230  {
231  boost::shared_ptr<DtNTree> child;
232 
233  // see if there's already a child there
234  typename Mutex::scoped_lock lock(myMutex, false);
235  Set(child, myTree);
236 
237  // if not then we'll see if we need to create it
238  if (!child)
239  {
240  // if we're not going to create a subcell then return null
241  // the caller will have to deal with this case
242  if (!query.shouldCreateSubcell(*this))
243  {
244  return boost::shared_ptr<DtNTree>();
245  }
246 
247  // if this returns false then another lock got the write lock and might
248  // have created the child, have to check again
249  if (!lock.upgrade_to_writer())
250  {
251  Set(child, myTree);
252  }
253 
254  // now we have the write lock and we know there's no child
255  // create it and store it
256  // we have a shared pointer to it on the stack, don't need the mutex anymore
257  if (!child)
258  {
259  child = query.createSubcell(tree, *this);
260  Set(myTree, child);
261  }
262  }
263 
264  return child;
265  }
266 
267  private:
268  friend class DtNTree;
269 
271  void init(const Bounds& b) { myBounds = b; }
272 
275 
277  mutable Mutex myMutex;
278 
281  };
282 
284  static boost::shared_ptr<DtNTree> Create(const Bounds& bounds)
285  {
286  return boost::shared_ptr<DtNTree>(new DtNTree(bounds, 0));
287  }
288 
290  int getLevel() const { return myLevel; }
291 
293  const Bounds& getBounds() const { return myBounds; }
294 
296  boost::shared_ptr<DtNTree> getParent() const { return Get(myParent); }
297 
299 
300  T& getData() { return myData; }
301  const T& getData() const { return myData; }
303 
304  protected:
308  explicit DtNTree(DtNTree& parent, const Bounds& bounds)
309  : myParent(parent.shared_from_this())
310  , myLevel(parent.myLevel + 1)
311  , myBounds(bounds)
312  {
313  for (unsigned int i=0; i < NumberOfIndices; ++i)
314  {
315  mySubcells[i].init(bounds.makeSubBounds(i));
316  }
317  }
318 
320  explicit DtNTree(const Bounds& bounds, unsigned int level)
321  : myParent()
322  , myLevel(level)
323  , myBounds(bounds)
324  {
325  for (unsigned int i=0; i < NumberOfIndices; ++i)
326  {
327  mySubcells[i].init(bounds.makeSubBounds(i));
328  }
329  }
330 
333  virtual boost::shared_ptr<DtNTree> createSubcell(Subcell& cell)
334  {
335  return boost::shared_ptr<DtNTree>(new DtNTree(*this, cell.bounds()));
336  }
337 
339  virtual void visit(Query& query)
340  {
341  // search is split up into two phases so that the match function can see
342  // the entire set of subareas before any recursing is done
343 
344  // holds the results of the intersection checks
345  bool intersected[NumberOfIndices];
346 
347  // iterate over each subarea and check for matching
348  for (unsigned int i=0; i < NumberOfIndices; ++i)
349  {
350  intersected[i] = query.matches(mySubcells[i]);
351  }
352 
353  // iterate again over the subcells that were matched
354  for (unsigned int i=0; i < NumberOfIndices; ++i)
355  {
356  // skip any cells that didn't match
357  if (!intersected[i])
358  {
359  continue;
360  }
361 
362  // shared pointer to child on the stack guarantees it stays alive
363  boost::shared_ptr<DtNTree> child = mySubcells[i].getPtr(*this, query);
364 
365  // if we got through all the at and actually have a child, time to recurse
366  if (child)
367  {
368  query.visit(*child);
369  }
370  }
371  }
372 
375 
377  const int myLevel;
378 
381 
384 
387  };
388 
396  template <
397  typename T,
398  unsigned int Dimensions,
399  typename Mutex,
400  template <typename> class SubcellPolicy,
401  typename BoundsType
402  >
403  class DtNTree<T,Dimensions,Mutex,SubcellPolicy,BoundsType>::Query
404  {
405  public:
407  virtual ~Query() { }
408 
413  virtual bool matches(const Subcell& cell) = 0;
414 
418  virtual bool shouldCreateSubcell(const Subcell& cell) = 0;
419 
422  virtual boost::shared_ptr<DtNTree> createSubcell(DtNTree& tree, Subcell& cell)
423  {
424  return tree.createSubcell(cell);
425  }
426 
428  virtual void visit(DtNTree& tree)
429  {
430  tree.visit(*this);
431  }
432 
433  protected:
435  Subcell& getSubcell(DtNTree& tree, unsigned int i)
436  {
437  assert(i < sizeof(tree.mySubcells));
438  return tree.mySubcells[i];
439  }
440  };
441 }

Document ID: Generated on Fri Apr 26 21:53:14 EDT 2019 from SVN revision 197883
Copyright © 2005-2019 VT MAK. All Rights Reserved (www.mak.com)