VR-Forces Developer's Guide
 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) 2024 MAK Technologies, Inc.
3 ** All rights reserved.
4 ******************************************************************************/
5 #pragma once
6 
10 
11 #include <memory>
12 #include <cassert>
13 
14 namespace makVrv
15 {
19  {
20  public:
22  {
23  public:
24  explicit scoped_lock(DtNTreeNullMutexPolicy&, bool=true) { }
25 
26  bool upgrade_to_writer() { return true; }
28  void release() { }
29  };
30  };
31 
33  template <typename Tree>
35  {
36  typedef std::shared_ptr<Tree> Ptr;
37  typedef std::weak_ptr<Tree> ParentPtr;
38  };
39 
41  template <typename Tree>
43  {
44  typedef std::weak_ptr<Tree> Ptr;
45  typedef std::shared_ptr<Tree> ParentPtr;
46  };
47 
63  template <
64  typename T,
65  unsigned int Dimensions = 3,
66  typename Mutex = DtNTreeNullMutexPolicy,
67  template <typename> class SubcellTraits = DtNTreeSharedPointerTraits,
68  typename BoundsType = double
69  >
70  class DtNTree
71  : public std::enable_shared_from_this< DtNTree<T,Dimensions,Mutex,SubcellTraits,BoundsType> >
72  {
74 
75  template <unsigned int A, unsigned int B>
76  struct Power
77  {
78  static const unsigned int value = A * Power<A, B - 1>::value;
79  };
80  template <unsigned int A>
81  struct Power<A, 0>
82  {
83  static const unsigned int value = 1;
84  };
86 
89 
90  template <typename Z>
91  static std::shared_ptr<Z> Get(const std::shared_ptr<Z>& p) { return p ;}
92 
93  template <typename Z>
94  static std::shared_ptr<Z> Get(const std::weak_ptr<Z>& p) { return p.lock(); }
95 
96  template <typename Z>
97  static void Set(std::shared_ptr<Z>& p, const std::shared_ptr<Z>& to) { p = to; }
98 
99  template <typename Z>
100  static void Set(std::shared_ptr<Z>& p, const std::weak_ptr<Z>& to) { p = to.lock(); }
101 
102  template <typename Z>
103  static void Set(std::weak_ptr<Z>& p, const std::shared_ptr<Z>& to) { p = to; }
104 
105  template <typename Z>
106  static void Set(std::weak_ptr<Z>& p, const std::weak_ptr<Z>& to) { p = to; }
108 
109  typedef typename SubcellTraits<DtNTree>::Ptr Ptr;
110  typedef typename SubcellTraits<DtNTree>::ParentPtr ParentPtr;
111 
112  public:
113  class Query;
114  friend class Query;
115 
117  static const unsigned int NumberOfIndices = Power<2, Dimensions>::value;
118 
120  struct Range
121  {
124  : minimum(std::numeric_limits<BoundsType>::min())
125  , maximum(std::numeric_limits<BoundsType>::max()) { }
126 
128  Range(BoundsType min, BoundsType max)
129  : minimum(min), maximum(max) { }
130 
132  double size() const
133  {
134  return maximum - minimum;
135  }
136 
138  bool intersects(const Range& other) const
139  {
140  if (maximum < other.minimum) return false;
141 
142  if (other.maximum < minimum) return false;
143 
144  return true;
145  }
146 
147  BoundsType minimum, maximum;
148  };
149 
151  class Bounds
152  {
153  public:
155  Bounds makeSubBounds(unsigned int index) const
156  {
157  Bounds newBounds(*this);
158 
159  for (unsigned int bit=1, d=0; d < Dimensions; ++d, bit=bit<<1)
160  {
161  // compute center point of range for this dimension
162  Range r = range(d);
163  BoundsType middle = ((r.maximum - r.minimum)/2) + r.minimum;
164 
165  // if the bit for this dimension is 1 then it will be from
166  // the center to the max, otherwise from the min to the center
167  // min and max are set when myRanges is initialized
168  if (index & bit)
169  {
170  newBounds.range(d).minimum = middle;
171  }
172  else
173  {
174  newBounds.range(d).maximum = middle;
175  }
176  }
177 
178  return newBounds;
179  }
180 
182  double size() const
183  {
184  double value = 1;
185 
186  for (unsigned int d=0; d < Dimensions; ++d)
187  {
188  value *= range(d).size();
189  }
190 
191  return value;
192  }
193 
195  bool intersects(const Bounds& other) const
196  {
197  for (unsigned int d=0; d < Dimensions; ++d)
198  {
199  // if any of the dimensions don't overlap then the entire thing doesn't
200  if (!range(d).intersects(other.range(d)))
201  {
202  return false;
203  }
204  }
205 
206  return true;
207  }
208 
210 
211  Range& range(unsigned int i) { assert(i < Dimensions); return myRanges[i]; }
212  const Range& range(unsigned int i) const { assert(i < Dimensions); return myRanges[i]; }
214 
215  private:
216  Range myRanges[Dimensions];
217  };
218 
220  class Subcell
221  {
222  public:
224  const Bounds& bounds() const { return myBounds; }
225 
227  std::shared_ptr<DtNTree> getPtr(DtNTree& tree, Query& query)
228  {
229  std::shared_ptr<DtNTree> child;
230 
231  // see if there's already a child there
232  typename Mutex::scoped_lock lock(myMutex, false);
233  Set(child, myTree);
234 
235  // if not then we'll see if we need to create it
236  if (!child)
237  {
238  // if we're not going to create a subcell then return null
239  // the caller will have to deal with this case
240  if (!query.shouldCreateSubcell(*this))
241  {
242  return std::shared_ptr<DtNTree>();
243  }
244 
245  // if this returns false then another lock got the write lock and might
246  // have created the child, have to check again
247  if (!lock.upgrade_to_writer())
248  {
249  Set(child, myTree);
250  }
251 
252  // now we have the write lock and we know there's no child
253  // create it and store it
254  // we have a shared pointer to it on the stack, don't need the mutex anymore
255  if (!child)
256  {
257  child = query.createSubcell(tree, *this);
258  Set(myTree, child);
259  }
260  }
261 
262  return child;
263  }
264 
265  private:
266  friend class DtNTree;
267 
269  void init(const Bounds& b) { myBounds = b; }
270 
273 
275  mutable Mutex myMutex;
276 
279  };
280 
282  static std::shared_ptr<DtNTree> Create(const Bounds& bounds)
283  {
284  return std::shared_ptr<DtNTree>(new DtNTree(bounds, 0));
285  }
286 
288  int getLevel() const { return myLevel; }
289 
291  const Bounds& getBounds() const { return myBounds; }
292 
294  std::shared_ptr<DtNTree> getParent() const { return Get(myParent); }
295 
297 
298  T& getData() { return myData; }
299  const T& getData() const { return myData; }
301 
302  protected:
306  explicit DtNTree(DtNTree& parent, const Bounds& bounds)
307  : myParent(parent.shared_from_this())
308  , myLevel(parent.myLevel + 1)
309  , myBounds(bounds)
310  {
311  for (unsigned int i=0; i < NumberOfIndices; ++i)
312  {
313  mySubcells[i].init(bounds.makeSubBounds(i));
314  }
315  }
316 
318  explicit DtNTree(const Bounds& bounds, unsigned int level)
319  : myParent()
320  , myLevel(level)
321  , myBounds(bounds)
322  {
323  for (unsigned int i=0; i < NumberOfIndices; ++i)
324  {
325  mySubcells[i].init(bounds.makeSubBounds(i));
326  }
327  }
328 
331  virtual std::shared_ptr<DtNTree> createSubcell(Subcell& cell)
332  {
333  return std::shared_ptr<DtNTree>(new DtNTree(*this, cell.bounds()));
334  }
335 
337  virtual void visit(Query& query)
338  {
339  // search is split up into two phases so that the match function can see
340  // the entire set of subareas before any recursing is done
341 
342  // holds the results of the intersection checks
343  bool intersected[NumberOfIndices];
344 
345  // iterate over each subarea and check for matching
346  for (unsigned int i=0; i < NumberOfIndices; ++i)
347  {
348  intersected[i] = query.matches(mySubcells[i]);
349  }
350 
351  // iterate again over the subcells that were matched
352  for (unsigned int i=0; i < NumberOfIndices; ++i)
353  {
354  // skip any cells that didn't match
355  if (!intersected[i])
356  {
357  continue;
358  }
359 
360  // shared pointer to child on the stack guarantees it stays alive
361  std::shared_ptr<DtNTree> child = mySubcells[i].getPtr(*this, query);
362 
363  // if we got through all the at and actually have a child, time to recurse
364  if (child)
365  {
366  query.visit(*child);
367  }
368  }
369  }
370 
373 
375  const int myLevel;
376 
379 
382 
385  };
386 
394  template <
395  typename T,
396  unsigned int Dimensions,
397  typename Mutex,
398  template <typename> class SubcellPolicy,
399  typename BoundsType
400  >
401  class DtNTree<T,Dimensions,Mutex,SubcellPolicy,BoundsType>::Query
402  {
403  public:
405  virtual ~Query() { }
406 
411  virtual bool matches(const Subcell& cell) = 0;
412 
416  virtual bool shouldCreateSubcell(const Subcell& cell) = 0;
417 
420  virtual std::shared_ptr<DtNTree> createSubcell(DtNTree& tree, Subcell& cell)
421  {
422  return tree.createSubcell(cell);
423  }
424 
426  virtual void visit(DtNTree& tree)
427  {
428  tree.visit(*this);
429  }
430 
431  protected:
433  Subcell& getSubcell(DtNTree& tree, unsigned int i)
434  {
435  assert(i < sizeof(tree.mySubcells));
436  return tree.mySubcells[i];
437  }
438  };
439 }
Represents the subcell in the parent cell.
Definition: DtNTree.h:220
static void Set(std::weak_ptr< Z > &p, const std::weak_ptr< Z > &to)
These functions allow shared and weak pointers to be treated the same. Weak pointers cannot be direct...
Definition: DtNTree.h:106
std::weak_ptr< Tree > Ptr
Definition: DtNTree.h:44
Range()
Default constructor.
Definition: DtNTree.h:123
std::shared_ptr< DtNTree > getParent() const
Return the parent of this tree, if it exists.
Definition: DtNTree.h:294
virtual bool matches(const Subcell &cell)=0
Search will ignore cells which return false. For a given tree, matches will be called on ALL the subc...
Query interface. Queries are templates of a general search on the tree. Users implement various parts...
Definition: DtNTree.h:401
virtual void visit(DtNTree &tree)
Entry point for search.
Definition: DtNTree.h:426
std::shared_ptr< Tree > Ptr
Definition: DtNTree.h:36
Generate NTree (binary tree, quadtree, octree, etc.) class. This consists of the tree itself and a qu...
Definition: DtNTree.h:70
virtual bool shouldCreateSubcell(const Subcell &cell)=0
Determine if an empty subcell should be created. This function will be called when the query is has d...
bool intersects(const Bounds &other) const
Returns true if the two bounds intersect each other.
Definition: DtNTree.h:195
static std::shared_ptr< DtNTree > Create(const Bounds &bounds)
Factory, create a top level root cell.
Definition: DtNTree.h:282
const T & getData() const
Accessors for user data.
Definition: DtNTree.h:299
DT_DLL_VRVCORE DtTaitBryan level(const DtCoordinateSystem &cs, const DtVector &localOrigin, double topoHeading)
Returns a level orientation with the topographic heading.
static const unsigned int value
Definition: DtNTree.h:78
virtual void visit(Query &query)
Default implementation of query visit.
Definition: DtNTree.h:337
T & getData()
Accessors for user data.
Definition: DtNTree.h:298
static void Set(std::shared_ptr< Z > &p, const std::shared_ptr< Z > &to)
These functions allow shared and weak pointers to be treated the same. Weak pointers cannot be direct...
Definition: DtNTree.h:97
Range(BoundsType min, BoundsType max)
Create from bounds of range.
Definition: DtNTree.h:128
virtual std::shared_ptr< DtNTree > createSubcell(DtNTree &tree, Subcell &cell)
Factory function for creating subcells. Reimplement this function to have this query create your own ...
Definition: DtNTree.h:420
Weak pointer policy.
Definition: DtNTree.h:42
static std::shared_ptr< Z > Get(const std::shared_ptr< Z > &p)
These functions allow shared and weak pointers to be treated the same. Weak pointers cannot be direct...
Definition: DtNTree.h:91
Set of ranges, one for each dimension.
Definition: DtNTree.h:151
bool upgrade_to_writer()
Definition: DtNTree.h:26
const Bounds & getBounds() const
Return the bounds of this tree.
Definition: DtNTree.h:291
T myData
User data stored in this tree.
Definition: DtNTree.h:384
static std::shared_ptr< Z > Get(const std::weak_ptr< Z > &p)
These functions allow shared and weak pointers to be treated the same. Weak pointers cannot be direct...
Definition: DtNTree.h:94
SubcellTraits< DtNTree >::Ptr Ptr
Definition: DtNTree.h:109
const int myLevel
Level of this cell.
Definition: DtNTree.h:375
virtual ~Query()
Virtual destructor.
Definition: DtNTree.h:405
BoundsType maximum
Definition: DtNTree.h:147
static void Set(std::weak_ptr< Z > &p, const std::shared_ptr< Z > &to)
These functions allow shared and weak pointers to be treated the same. Weak pointers cannot be direct...
Definition: DtNTree.h:103
std::shared_ptr< Tree > ParentPtr
Definition: DtNTree.h:45
DtNTree(DtNTree &parent, const Bounds &bounds)
Constructor for creating children trees.
Definition: DtNTree.h:306
virtual std::shared_ptr< DtNTree > createSubcell(Subcell &cell)
Default implementation of query createSubcell.
Definition: DtNTree.h:331
void downgrade_to_reader()
Definition: DtNTree.h:27
static void Set(std::shared_ptr< Z > &p, const std::weak_ptr< Z > &to)
These functions allow shared and weak pointers to be treated the same. Weak pointers cannot be direct...
Definition: DtNTree.h:100
double size() const
Compute the size (area, volume, etc. depending on number of dimensions).
Definition: DtNTree.h:182
static const unsigned int NumberOfIndices
Number of subcells.
Definition: DtNTree.h:117
Range & range(unsigned int i)
accessors
Definition: DtNTree.h:211
OpenThreads::Mutex Mutex
Definition: DtOsgThreadingUtils.h:12
Bounds makeSubBounds(unsigned int index) const
Compute the bounds of a subcell at a given index.
Definition: DtNTree.h:155
std::weak_ptr< Tree > ParentPtr
Definition: DtNTree.h:37
void init(const Bounds &b)
This class is created in an array so parameters are initialized after the constructor.
Definition: DtNTree.h:269
Null mutex default policy. Using this policy will result in no locking (i.e. tree is not threadsafe)...
Definition: DtNTree.h:18
Subcell & getSubcell(DtNTree &tree, unsigned int i)
Interface for subclasses to get at subcell objects.
Definition: DtNTree.h:433
const Range & range(unsigned int i) const
accessors
Definition: DtNTree.h:212
double size() const
Compute the length of the range.
Definition: DtNTree.h:132
int getLevel() const
Return level of this tree.
Definition: DtNTree.h:288
Subcell mySubcells[NumberOfIndices]
Subcells.
Definition: DtNTree.h:381
const Bounds & bounds() const
Accessor for bounds of this cell.
Definition: DtNTree.h:224
void release()
Definition: DtNTree.h:28
scoped_lock(DtNTreeNullMutexPolicy &, bool=true)
Definition: DtNTree.h:24
Bounds myBounds
Bounds of this subcell.
Definition: DtNTree.h:272
One dimensional range (i.e. min/max).
Definition: DtNTree.h:120
Shared pointer policy.
Definition: DtNTree.h:34
SubcellTraits< DtNTree >::ParentPtr ParentPtr
Definition: DtNTree.h:110
bool intersects(const Range &other) const
Returns true of these two ranges intersect.
Definition: DtNTree.h:138
const ParentPtr myParent
Pointer to parent node if it exists.
Definition: DtNTree.h:372
DtNTree(const Bounds &bounds, unsigned int level)
Constructor for creating root tree.
Definition: DtNTree.h:318
Compute exponents at compile time (for array length).
Definition: DtNTree.h:76
Ptr myTree
Pointer to child tree.
Definition: DtNTree.h:278
const Bounds myBounds
Bounds of this cell.
Definition: DtNTree.h:378
Mutex myMutex
Mutex which synchronizes only the pointer, not the object pointed to.
Definition: DtNTree.h:275
BoundsType minimum
Definition: DtNTree.h:147
std::shared_ptr< DtNTree > getPtr(DtNTree &tree, Query &query)
Get or create the tree for this subcell.
Definition: DtNTree.h:227
Range myRanges[Dimensions]
Definition: DtNTree.h:216

Document ID: Generated on Thu Oct 23 22:29:17 EDT 2025 from SVN revision 280951
Copyright © 2005-2024 MAK Technologies. All Rights Reserved (www.mak.com)