OpenVDB  11.0.0
FindActiveValues.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 ///////////////////////////////////////////////////////////////////////////
5 //
6 /// @file FindActiveValues.h
7 ///
8 /// @author Ken Museth
9 ///
10 /// @brief Finds the active values and tiles in a tree that intersects a bounding box.
11 /// Methods are provided that count the number of active values and tiles,
12 /// test for the existence of active values and tiles, and return a list of
13 /// the active tiles that intersect a bbox.
14 ///
15 /// @warning For repeated calls to the free-standing functions defined below
16 /// consider instead creating an instance of FindActiveValues
17 /// and then repeatedly call its member methods. This assumes the tree
18 /// to be constant between calls but is sightly faster.
19 ///
20 ///////////////////////////////////////////////////////////////////////////
21 
22 #ifndef OPENVDB_TOOLS_FINDACTIVEVALUES_HAS_BEEN_INCLUDED
23 #define OPENVDB_TOOLS_FINDACTIVEVALUES_HAS_BEEN_INCLUDED
24 
25 #include <vector>
26 #include <openvdb/version.h> // for OPENVDB_VERSION_NAME
27 #include <openvdb/Types.h>
29 #include <openvdb/openvdb.h>
30 
31 #include "Count.h" // tools::countActiveVoxels()
32 
33 #include <tbb/blocked_range.h>
34 #include <tbb/parallel_for.h>
35 #include <tbb/parallel_reduce.h>
36 
37 namespace openvdb {
39 namespace OPENVDB_VERSION_NAME {
40 namespace tools {
41 
42 /// @brief Struct that encodes a bounding box, value and level of a tile
43 ///
44 /// @details The bbox of a tiles is trimmed to the bounding box that probed it.
45 /// The level is typically defined as: 1 is 8^3, 2 is 128^3, and 3 is 4096^3.
46 template<typename ValueType>
47 struct TileData;
48 
49 /// @brief Returns true if the bounding box intersects any of the active
50 /// values in a tree, i.e. either active voxels or active tiles.
51 ///
52 /// @warning For repeated calls to this method consider instead creating an instance of
53 /// FindActiveValues and then repeatedly call anyActiveValues(). This assumes the tree
54 /// to be constant between calls but is slightly faster.
55 ///
56 /// @param tree const tree to be tested for active values.
57 /// @param bbox index bounding box which is intersected against the active values.
58 template<typename TreeT>
59 bool
60 anyActiveValues(const TreeT& tree, const CoordBBox &bbox);
61 
62 /// @brief Returns true if the bounding box intersects any of the active
63 /// voxels in a tree, i.e. ignores active tile values.
64 ///
65 /// @note In VDB voxels by definition reside in the leaf nodes ONLY. So this method
66 /// ignores active tile values that reside higher up in the VDB tree structure.
67 ///
68 /// @warning For repeated calls to this method consider instead creating an instance of
69 /// FindActiveValues and then repeatedly call anyActiveVoxels(). This assumes the tree
70 /// to be constant between calls but is slightly faster.
71 ///
72 /// @param tree const tree to be tested for active voxels.
73 /// @param bbox index bounding box which is intersected against the active voxels.
74 template<typename TreeT>
75 bool
76 anyActiveVoxels(const TreeT& tree, const CoordBBox &bbox);
77 
78 /// @brief Returns true if the bounding box intersects any of the active
79 /// tiles in a tree, i.e. ignores active leaf values.
80 ///
81 /// @warning For repeated calls to this method consider instead creating an instance of
82 /// FindActiveValues and then repeatedly call anyActiveTiles(). This assumes the tree
83 /// to be constant between calls but is slightly faster.
84 ///
85 /// @param tree const tree to be tested for active tiles.
86 /// @param bbox index bounding box which is intersected against the active tiles.
87 template<typename TreeT>
88 bool
89 anyActiveTiles(const TreeT& tree, const CoordBBox &bbox);
90 
91 /// @brief Returns true if the bounding box intersects none of the active
92 /// values in a tree, i.e. neither active voxels or active tiles.
93 ///
94 /// @warning For repeated calls to this method consider instead creating an instance of
95 /// FindActiveValues and then repeatedly call noActiveValues(). This assumes the tree
96 /// to be constant between calls but is slightly faster.
97 ///
98 /// @param tree const tree to be tested for active values.
99 /// @param bbox index bounding box which is intersected against the active values.
100 template<typename TreeT>
101 bool
102 noActiveValues(const TreeT& tree, const CoordBBox &bbox);
103 
104 /// @brief Returns the number of active values that intersects a bounding box intersects,
105 /// i.e. the count includes both active voxels and virtual voxels in active tiles.
106 ///
107 /// @warning For repeated calls to this method consider instead creating an instance of
108 /// FindActiveValues and then repeatedly call count(). This assumes the tree
109 /// to be constant between calls but is slightly faster.
110 ///
111 /// @param tree const tree to be tested for active values.
112 /// @param bbox index bounding box which is intersected against the active values.
113 template<typename TreeT>
114 Index64
115 countActiveValues(const TreeT& tree, const CoordBBox &bbox);
116 
117 /// @brief Return a vector with bounding boxes that represents all the intersections
118 /// between active tiles in the tree and the specified bounding box.
119 ///
120 /// @warning For repeated calls to this method consider instead creating an instance of
121 /// FindActiveValues and then repeatedly call count(). This assumes the tree
122 /// to be constant between calls but is slightly faster.
123 ///
124 /// @param tree const tree to be tested for active tiles.
125 /// @param bbox index bounding box which is intersected against the active tiles.
126 template<typename TreeT>
127 std::vector<TileData<typename TreeT::ValueType>>
128 activeTiles(const TreeT& tree, const CoordBBox &bbox);
129 
130 //////////////////////////////////////////////////////////////////////////////////////////
131 
132 /// @brief Finds the active values in a tree which intersects a bounding box.
133 ///
134 /// @details Two methods are provided, one that count the number of active values
135 /// and one that simply tests if any active values intersect the bbox.
136 ///
137 /// @warning Tree nodes are cached by this class so it's important that the tree is not
138 /// modified after this class is instantiated and before its methods are called.
139 template<typename TreeT>
141 {
142 public:
143 
145 
146  /// @brief Constructor from a const tree, which is assumed not to be modified after construction.
147  FindActiveValues(const TreeT& tree);
148 
149  /// @brief Default destructor
150  ~FindActiveValues();
151 
152  /// @brief Initiate this class with a new (or modified) tree.
153  void update(const TreeT& tree);
154 
155  /// @brief Returns true if the specified bounding box intersects any active values.
156  ///
157  /// @warning Using a ValueAccessor (i.e. useAccessor = true) can improve performance for especially
158  /// small bounding boxes, but at the cost of no thread-safety. So if multiple threads are
159  /// calling this method concurrently use the default setting, useAccessor = false.
160  bool anyActiveValues(const CoordBBox &bbox, bool useAccessor = false) const;
161 
162  /// @brief Returns true if the specified bounding box intersects any active tiles only.
163  bool anyActiveVoxels(const CoordBBox &bbox) const;
164 
165  /// @brief Returns true if the specified bounding box intersects any active tiles only.
166  bool anyActiveTiles(const CoordBBox &bbox) const;
167 
168  /// @brief Returns true if the specified bounding box does not intersect any active values.
169  ///
170  /// @warning Using a ValueAccessor (i.e. useAccessor = true) can improve performance for especially
171  /// small bounding boxes, but at the cost of no thread-safety. So if multiple threads are
172  /// calling this method concurrently use the default setting, useAccessor = false.
173  bool noActiveValues(const CoordBBox &bbox, bool useAccessor = false) const { return !this->anyActiveValues(bbox, useAccessor); }
174 
175  /// @brief Returns the number of active voxels intersected by the specified bounding box.
176  Index64 count(const CoordBBox &bbox) const;
177 
178  /// @brief Return a vector with bounding boxes that represents all the intersections
179  /// between active tiles in the tree and the specified bounding box.
180  std::vector<TileDataT> activeTiles(const CoordBBox &bbox) const;
181 
182 private:
183 
184  // Cleans up internal data structures
185  void clear();
186 
187  // builds internal data structures
188  void init(const TreeT &tree);
189 
190  template<typename NodeT>
191  typename NodeT::NodeMaskType getBBoxMask(const CoordBBox &bbox, const NodeT* node) const;
192 
193  // process leaf nodes
194  inline bool anyActiveValues(const typename TreeT::LeafNodeType* leaf, const CoordBBox &bbox ) const { return this->anyActiveVoxels(leaf, bbox); }
195  inline bool anyActiveVoxels(const typename TreeT::LeafNodeType* leaf, const CoordBBox &bbox ) const;
196  static bool anyActiveTiles( const typename TreeT::LeafNodeType*, const CoordBBox& ) {return false;}
197  void activeTiles(const typename TreeT::LeafNodeType*, const CoordBBox&, std::vector<TileDataT>&) const {;}// no-op
198  inline Index64 count(const typename TreeT::LeafNodeType* leaf, const CoordBBox &bbox ) const;
199 
200  // process internal nodes
201  template<typename NodeT>
202  bool anyActiveValues(const NodeT* node, const CoordBBox &bbox) const;
203  template<typename NodeT>
204  bool anyActiveVoxels(const NodeT* node, const CoordBBox &bbox) const;
205  template<typename NodeT>
206  bool anyActiveTiles(const NodeT* node, const CoordBBox &bbox) const;
207  template<typename NodeT>
208  void activeTiles(const NodeT* node, const CoordBBox &bbox, std::vector<TileDataT> &tiles) const;
209  template<typename NodeT>
210  Index64 count(const NodeT* node, const CoordBBox &bbox) const;
211 
212  using AccT = tree::ValueAccessor<const TreeT, false/* IsSafe */>;
213  using RootChildType = typename TreeT::RootNodeType::ChildNodeType;
214 
215  struct RootChild;
216 
217  AccT mAcc;
218  std::vector<TileDataT> mRootTiles;// cache bbox of child nodes (faster to cache than access RootNode)
219  std::vector<RootChild> mRootNodes;// cache bbox of active tiles (faster to cache than access RootNode)
220 
221 };// FindActiveValues class
222 
223 //////////////////////////////////////////////////////////////////////////////////////////
224 
225 template<typename TreeT>
226 FindActiveValues<TreeT>::FindActiveValues(const TreeT& tree) : mAcc(tree), mRootTiles(), mRootNodes()
227 {
228  this->init(tree);
229 }
230 
231 template<typename TreeT>
233 {
234  this->clear();
235 }
236 
237 template<typename TreeT>
238 void FindActiveValues<TreeT>::update(const TreeT& tree)
239 {
240  this->clear();
241  mAcc = AccT(tree);
242  this->init(tree);
243 }
244 
245 template<typename TreeT>
247 {
248  mRootNodes.clear();
249  mRootTiles.clear();
250 }
251 
252 template<typename TreeT>
253 void FindActiveValues<TreeT>::init(const TreeT& tree)
254 {
255  const auto &root = tree.root();
256  for (auto i = root.cbeginChildOn(); i; ++i) {
257  mRootNodes.emplace_back(i.getCoord(), &*i);
258  }
259  for (auto i = root.cbeginValueOn(); i; ++i) {
260  mRootTiles.emplace_back(root, i.getCoord(), *i);
261  }
262 }
263 
264 template<typename TreeT>
265 bool FindActiveValues<TreeT>::anyActiveValues(const CoordBBox &bbox, bool useAccessor) const
266 {
267  // test early-out: the center of the bbox is active
268  if (useAccessor) {
269  if (mAcc.isValueOn( (bbox.min() + bbox.max())>>1 )) return true;
270  } else {
271  if (mAcc.tree().isValueOn( (bbox.min() + bbox.max())>>1 )) return true;
272  }
273 
274  for (auto& tile : mRootTiles) {
275  if (tile.bbox.hasOverlap(bbox)) return true;
276  }
277  for (auto& node : mRootNodes) {
278  if (!node.bbox.hasOverlap(bbox)) {// no overlap
279  continue;
280  } else if (node.bbox.isInside(bbox)) {// bbox is inside the child node
281  return this->anyActiveValues(node.child, bbox);
282  } else if (this->anyActiveValues(node.child, bbox)) {// bbox overlaps the child node
283  return true;
284  }
285  }
286  return false;
287 }
288 
289 template<typename TreeT>
291 {
292  for (auto& node : mRootNodes) {
293  if (!node.bbox.hasOverlap(bbox)) {// no overlap
294  continue;
295  } else if (node.bbox.isInside(bbox)) {// bbox is inside the child node
296  return this->anyActiveVoxels(node.child, bbox);
297  } else if (this->anyActiveVoxels(node.child, bbox)) {// bbox overlaps the child node
298  return true;
299  }
300  }
301  return false;
302 }
303 
304 template<typename TreeT>
306 {
307  for (auto& tile : mRootTiles) {
308  if (tile.bbox.hasOverlap(bbox)) return true;
309  }
310  for (auto& node : mRootNodes) {
311  if (!node.bbox.hasOverlap(bbox)) {// no overlap
312  continue;
313  } else if (node.bbox.isInside(bbox)) {// bbox is inside the child node
314  return this->anyActiveTiles(node.child, bbox);
315  } else if (this->anyActiveTiles(node.child, bbox)) {// bbox overlaps the child node
316  return true;
317  }
318  }
319  return false;
320 }
321 
322 template<typename TreeT>
324 {
325  Index64 count = 0;
326  for (auto& tile : mRootTiles) {//loop over active tiles only
327  if (!tile.bbox.hasOverlap(bbox)) {
328  continue;//ignore non-overlapping tiles
329  } else if (tile.bbox.isInside(bbox)) {
330  return bbox.volume();// bbox is completely inside the active tile
331  } else if (bbox.isInside(tile.bbox)) {
332  count += RootChildType::NUM_VOXELS;
333  } else {// partial overlap between tile and bbox
334  auto tmp = tile.bbox;
335  tmp.intersect(bbox);
336  count += tmp.volume();
337  }
338  }
339  for (auto &node : mRootNodes) {//loop over child nodes of the root node only
340  if ( !node.bbox.hasOverlap(bbox) ) {
341  continue;//ignore non-overlapping child nodes
342  } else if ( node.bbox.isInside(bbox) ) {
343  return this->count(node.child, bbox);// bbox is completely inside the child node
344  } else {
345  count += this->count(node.child, bbox);
346  }
347  }
348  return count;
349 }
350 
351 template<typename TreeT>
352 std::vector<TileData<typename TreeT::ValueType> >
354 {
355  std::vector<TileDataT> tiles;
356  for (auto& tile : mRootTiles) {//loop over active tiles only
357  if (!tile.bbox.hasOverlap(bbox)) {
358  continue;//ignore non-overlapping tiles
359  } else if (tile.bbox.isInside(bbox)) {// bbox is completely inside the active tile
360  tiles.emplace_back(bbox, tile.value, tile.level);
361  return tiles;
362  } else if (bbox.isInside(tile.bbox)) {// active tile is completely inside the bbox
363  tiles.push_back(tile);
364  } else {// partial overlap between tile and bbox
365  auto tmp = tile.bbox;
366  tmp.intersect(bbox);
367  tiles.emplace_back(tmp, tile.value, tile.level);
368  }
369  }
370  for (auto &node : mRootNodes) {//loop over child nodes of the root node only
371  if ( !node.bbox.hasOverlap(bbox) ) {
372  continue;//ignore non-overlapping child nodes
373  } else if ( node.bbox.isInside(bbox) ) {// bbox is completely inside the child node
374  this->activeTiles(node.child, bbox, tiles);
375  return tiles;
376  } else {// partial overlap between tile and child node
377  this->activeTiles(node.child, bbox, tiles);
378  }
379  }
380  return tiles;
381 }
382 
383 template<typename TreeT>
384 template<typename NodeT>
385 typename NodeT::NodeMaskType FindActiveValues<TreeT>::getBBoxMask(const CoordBBox &bbox, const NodeT* node) const
386 {
387  typename NodeT::NodeMaskType mask;// typically 32^3 or 16^3 bit mask
388  auto b = node->getNodeBoundingBox();
389  assert( bbox.hasOverlap(b) );
390  if ( bbox.isInside(b) ) {
391  mask.setOn();//node is completely inside the bbox so early out
392  } else {
393  b.intersect(bbox);// trim bounding box
394  // transform bounding box from global to local coordinates
395  b.min() &= NodeT::DIM-1u;
396  b.min() >>= NodeT::ChildNodeType::TOTAL;
397  b.max() &= NodeT::DIM-1u;
398  b.max() >>= NodeT::ChildNodeType::TOTAL;
399  assert( b.hasVolume() );
400  auto it = b.begin();// iterates over all the child nodes or tiles that intersects bbox
401  for (const Coord& ijk = *it; it; ++it) {
402  mask.setOn(ijk[2] + (ijk[1] << NodeT::LOG2DIM) + (ijk[0] << 2*NodeT::LOG2DIM));
403  }
404  }
405  return mask;
406 }
407 
408 template<typename TreeT>
409 template<typename NodeT>
410 bool FindActiveValues<TreeT>::anyActiveValues(const NodeT* node, const CoordBBox &bbox) const
411 {
412  // Generate a bit mask of the bbox coverage
413  auto mask = this->getBBoxMask(bbox, node);
414 
415  // Check active tiles
416  const auto tmp = mask & node->getValueMask();// prune active the tile mask with the bbox mask
417  if (!tmp.isOff()) return true;
418 
419  // Check child nodes
420  mask &= node->getChildMask();// prune the child mask with the bbox mask
421  const auto* table = node->getTable();
422  bool active = false;
423  for (auto i = mask.beginOn(); !active && i; ++i) {
424  active = this->anyActiveValues(table[i.pos()].getChild(), bbox);
425  }
426  return active;
427 }
428 
429 template<typename TreeT>
430 template<typename NodeT>
431 bool FindActiveValues<TreeT>::anyActiveVoxels(const NodeT* node, const CoordBBox &bbox) const
432 {
433  // Generate a bit mask of the bbox coverage
434  auto mask = this->getBBoxMask(bbox, node);
435 
436  // Check child nodes
437  mask &= node->getChildMask();// prune the child mask with the bbox mask
438  const auto* table = node->getTable();
439  bool active = false;
440  for (auto i = mask.beginOn(); !active && i; ++i) {
441  active = this->anyActiveVoxels(table[i.pos()].getChild(), bbox);
442  }
443  return active;
444 }
445 
446 template<typename TreeT>
447 inline bool FindActiveValues<TreeT>::anyActiveVoxels(const typename TreeT::LeafNodeType* leaf, const CoordBBox &bbox ) const
448 {
449  const auto &mask = leaf->getValueMask();
450 
451  // check for two common cases that leads to early-out
452  if (bbox.isInside(leaf->getNodeBoundingBox())) return !mask.isOff();// leaf in inside the bbox
453  if (mask.isOn()) return true;// all values are active
454 
455  bool active = false;
456  for (auto i = leaf->cbeginValueOn(); !active && i; ++i) {
457  active = bbox.isInside(i.getCoord());
458  }
459  return active;
460 }
461 
462 template<typename TreeT>
463 template<typename NodeT>
464 bool FindActiveValues<TreeT>::anyActiveTiles(const NodeT* node, const CoordBBox &bbox) const
465 {
466  // Generate a bit mask of the bbox coverage
467  auto mask = this->getBBoxMask(bbox, node);
468 
469  // Check active tiles
470  const auto tmp = mask & node->getValueMask();// prune active the tile mask with the bbox mask
471  if (!tmp.isOff()) return true;
472 
473  bool active = false;
474  if (NodeT::LEVEL>1) {// Only check child nodes if they are NOT leaf nodes
475  mask &= node->getChildMask();// prune the child mask with the bbox mask
476  const auto* table = node->getTable();
477  for (auto i = mask.beginOn(); !active && i; ++i) {
478  active = this->anyActiveTiles(table[i.pos()].getChild(), bbox);
479  }
480  }
481  return active;
482 }
483 
484 template<typename TreeT>
485 inline Index64 FindActiveValues<TreeT>::count(const typename TreeT::LeafNodeType* leaf, const CoordBBox &bbox ) const
486 {
487  Index64 count = 0;
488  auto b = leaf->getNodeBoundingBox();
489  if (b.isInside(bbox)) { // leaf node is completely inside bbox
490  count = leaf->onVoxelCount();
491  } else if (leaf->isDense()) {
492  b.intersect(bbox);
493  count = b.volume();
494  } else if (b.hasOverlap(bbox)) {
495  for (auto i = leaf->cbeginValueOn(); i; ++i) {
496  if (bbox.isInside(i.getCoord())) ++count;
497  }
498  }
499  return count;
500 }
501 
502 template<typename TreeT>
503 template<typename NodeT>
504 Index64 FindActiveValues<TreeT>::count(const NodeT* node, const CoordBBox &bbox) const
505 {
506  Index64 count = 0;
507 
508  // Generate a bit masks
509  auto mask = this->getBBoxMask(bbox, node);
510  const auto childMask = mask & node->getChildMask();// prune the child mask with the bbox mask
511  mask &= node->getValueMask();// prune active tile mask with the bbox mask
512  const auto* table = node->getTable();
513 
514  {// Check child nodes
515  using ChildT = typename NodeT::ChildNodeType;
516  using RangeT = tbb::blocked_range<typename std::vector<const ChildT*>::iterator>;
517  std::vector<const ChildT*> childNodes(childMask.countOn());
518  int j=0;
519  for (auto i = childMask.beginOn(); i; ++i, ++j) childNodes[j] = table[i.pos()].getChild();
520  count += tbb::parallel_reduce( RangeT(childNodes.begin(), childNodes.end()), 0,
521  [&](const RangeT& r, Index64 sum)->Index64 {
522  for ( auto i = r.begin(); i != r.end(); ++i ) sum += this->count(*i, bbox);
523  return sum;
524  }, []( Index64 a, Index64 b )->Index64 { return a+b; }
525  );
526  }
527 
528  {// Check active tiles
529  std::vector<Coord> coords(mask.countOn());
530  using RangeT = tbb::blocked_range<typename std::vector<Coord>::iterator>;
531  int j=0;
532  for (auto i = mask.beginOn(); i; ++i, ++j) coords[j] = node->offsetToGlobalCoord(i.pos());
533  count += tbb::parallel_reduce( RangeT(coords.begin(), coords.end()), 0,
534  [&bbox](const RangeT& r, Index64 sum)->Index64 {
535  for ( auto i = r.begin(); i != r.end(); ++i ) {
536  auto b = CoordBBox::createCube(*i, NodeT::ChildNodeType::DIM);
537  b.intersect(bbox);
538  sum += b.volume();
539  }
540  return sum;
541  }, []( Index64 a, Index64 b )->Index64 { return a+b; }
542  );
543  }
544 
545  return count;
546 }
547 
548 // process internal node
549 template<typename TreeT>
550 template<typename NodeT>
551 void FindActiveValues<TreeT>::activeTiles(const NodeT* node, const CoordBBox &bbox, std::vector<TileDataT> &tiles) const
552 {
553  // Generate a bit masks
554  auto mask = this->getBBoxMask(bbox, node);
555  const auto childMask = mask & node->getChildMask();// prune the child mask with the bbox mask
556  mask &= node->getValueMask();// prune active tile mask with the bbox mask
557 
558  if (NodeT::LEVEL > 1) {// Only check child nodes if they are NOT leaf nodes
559  const auto* table = node->getTable();
560  for (auto i = childMask.beginOn(); i; ++i) this->activeTiles(table[i.pos()].getChild(), bbox, tiles);
561  }
562 
563  const size_t tileCount = mask.countOn();
564  if (tileCount < 8) {// Serial processing of active tiles
565  for (auto iter = mask.beginOn(); iter; ++iter) {
566  tiles.emplace_back(*node, iter.pos());
567  tiles.back().bbox.intersect(bbox);
568  }
569  } else {// Parallel processing of active tiles
570  std::vector<TileDataT> tmp( tileCount );// for temporary thread-safe processing
571  int n = 0;
572  for (auto iter = mask.beginOn(); iter; ++iter) tmp[n++].level = iter.pos();// placeholder to support multi-threading
573  tbb::parallel_for(tbb::blocked_range<size_t>(0, tileCount, 8), [&](const tbb::blocked_range<size_t>& r) {
574  for ( size_t i = r.begin(); i != r.end(); ++i ) {
575  tmp[i] = TileDataT(*node, tmp[i].level);
576  tmp[i].bbox.intersect(bbox);
577  }
578  });
579  tiles.insert(tiles.end(), tmp.begin(), tmp.end());
580  }
581 }
582 
583 template<typename TreeT>
585 {
587  const RootChildType* child;
588  RootChild(const Coord& ijk = Coord(), const RootChildType* ptr = nullptr)
589  : bbox(CoordBBox::createCube(ijk, RootChildType::DIM)), child(ptr)
590  {
591  }
592 };// RootChild struct
593 
594 //////////////////////////////////////////////////////////////////////////////////////////
595 
596 template<typename ValueType>
597 struct TileData
598 {
600  ValueType value;
602  bool state;
603 
604  /// @brief Default constructor
605  TileData() = default;
606 
607  /// @brief Member data constructor
608  TileData(const CoordBBox &b, const ValueType &v, Index l, bool active = true)
609  : bbox(b), value(v), level(l), state(active) {}
610 
611  /// @brief Constructor from a parent node and the linear offset to one of its tiles
612  ///
613  /// @warning This is an expert-only method since it assumes the linear offset to be valid,
614  /// i.e. within the rand of the dimension of the parent node and NOT corresponding
615  /// to a child node.
616  template <typename ParentNodeT>
617  TileData(const ParentNodeT &parent, Index childIdx)
618  : bbox(CoordBBox::createCube(parent.offsetToGlobalCoord(childIdx), parent.getChildDim()))
619  , level(parent.getLevel())
620  , state(true)
621  {
622  assert(childIdx < ParentNodeT::NUM_VALUES);
623  assert(parent.isChildMaskOff(childIdx));
624  assert(parent.isValueMaskOn(childIdx));
625  value = parent.getTable()[childIdx].getValue();
626  }
627 
628  /// @brief Constructor form a parent node, the coordinate of the origin of one of its tiles,
629  /// and said tiles value.
630  template <typename ParentNodeT>
631  TileData(const ParentNodeT &parent, const Coord &ijk, const ValueType &v)
632  : bbox(CoordBBox::createCube(ijk, parent.getChildDim()))
633  , value(v)
634  , level(parent.getLevel())
635  , state(true)
636  {
637  }
638 };// TileData struct
639 
640 //////////////////////////////////////////////////////////////////////////////////////////
641 
642 // Implementation of stand-alone function
643 template<typename TreeT>
644 bool
645 anyActiveValues(const TreeT& tree, const CoordBBox &bbox)
646 {
647  FindActiveValues<TreeT> op(tree);
648  return op.anyActiveValues(bbox);
649 }
650 
651 // Implementation of stand-alone function
652 template<typename TreeT>
653 bool
654 anyActiveVoxels(const TreeT& tree, const CoordBBox &bbox)
655 {
656  FindActiveValues<TreeT> op(tree);
657  return op.anyActiveVoxels(bbox);
658 }
659 
660 // Implementation of stand-alone function
661 template<typename TreeT>
662 bool
663 anyActiveTiles(const TreeT& tree, const CoordBBox &bbox)
664 {
665  FindActiveValues<TreeT> op(tree);
666  return op.anyActiveTiles(bbox);
667 }
668 
669 // Implementation of stand-alone function
670 template<typename TreeT>
671 bool
672 noActiveValues(const TreeT& tree, const CoordBBox &bbox)
673 {
674  FindActiveValues<TreeT> op(tree);
675  return op.noActiveValues(bbox);
676 }
677 
678 // Implementation of stand-alone function
679 template<typename TreeT>
680 Index64
681 countActiveValues(const TreeT& tree, const CoordBBox &bbox)
682 {
683  return tools::countActiveVoxels(tree, bbox);
684 }
685 
686 // Implementation of stand-alone function
687 template<typename TreeT>
688 std::vector<TileData<typename TreeT::ValueType>>
689 activeTiles(const TreeT& tree, const CoordBBox &bbox)
690 {
691  FindActiveValues<TreeT> op(tree);
692  return op.activeTiles(bbox);
693 }
694 
695 
696 ////////////////////////////////////////
697 
698 
699 // Explicit Template Instantiation
700 
701 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
702 
703 #ifdef OPENVDB_INSTANTIATE_FINDACTIVEVALUES
705 #endif
706 
707 #define _FUNCTION(TreeT) \
708  bool anyActiveValues(const TreeT&, const CoordBBox&)
710 #undef _FUNCTION
711 
712 #define _FUNCTION(TreeT) \
713  bool anyActiveVoxels(const TreeT&, const CoordBBox&)
715 #undef _FUNCTION
716 
717 #define _FUNCTION(TreeT) \
718  bool anyActiveTiles(const TreeT&, const CoordBBox&)
720 #undef _FUNCTION
721 
722 #define _FUNCTION(TreeT) \
723  bool noActiveValues(const TreeT&, const CoordBBox&)
725 #undef _FUNCTION
726 
727 #define _FUNCTION(TreeT) \
728  Index64 countActiveValues(const TreeT&, const CoordBBox&)
730 #undef _FUNCTION
731 
732 #define _FUNCTION(TreeT) \
733  std::vector<TileData<TreeT::ValueType>> activeTiles(const TreeT&, const CoordBBox&)
735 #undef _FUNCTION
736 
737 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
738 
739 
740 } // namespace tools
741 } // namespace OPENVDB_VERSION_NAME
742 } // namespace openvdb
743 
744 #endif // OPENVDB_TOOLS_FINDACTIVEVALUES_HAS_BEEN_INCLUDED
bool anyActiveValues(const TreeT &tree, const CoordBBox &bbox)
Returns true if the bounding box intersects any of the active values in a tree, i.e. either active voxels or active tiles.
Definition: FindActiveValues.h:645
Index64 count(const CoordBBox &bbox) const
Returns the number of active voxels intersected by the specified bounding box.
Definition: FindActiveValues.h:323
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h.in:160
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition: ValueAccessor.h:68
TileData(const ParentNodeT &parent, Index childIdx)
Constructor from a parent node and the linear offset to one of its tiles.
Definition: FindActiveValues.h:617
bool anyActiveVoxels(const CoordBBox &bbox) const
Returns true if the specified bounding box intersects any active tiles only.
Definition: FindActiveValues.h:290
TreeType & tree() const
Return a reference to the tree associated with this accessor.
Definition: ValueAccessor.h:201
Struct that encodes a bounding box, value and level of a tile.
Definition: FindActiveValues.h:47
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
Definition: ValueAccessor.h:480
bool anyActiveTiles(const TreeT &tree, const CoordBBox &bbox)
Returns true if the bounding box intersects any of the active tiles in a tree, i.e. ignores active leaf values.
Definition: FindActiveValues.h:663
Finds the active values in a tree which intersects a bounding box.
Definition: FindActiveValues.h:140
bool anyActiveValues(const CoordBBox &bbox, bool useAccessor=false) const
Returns true if the specified bounding box intersects any active values.
Definition: FindActiveValues.h:265
TileData(const ParentNodeT &parent, const Coord &ijk, const ValueType &v)
Constructor form a parent node, the coordinate of the origin of one of its tiles, and said tiles valu...
Definition: FindActiveValues.h:631
~FindActiveValues()
Default destructor.
Definition: FindActiveValues.h:232
BBox< Coord > CoordBBox
Definition: NanoVDB.h:2535
uint64_t Index64
Definition: Types.h:53
bool anyActiveVoxels(const TreeT &tree, const CoordBBox &bbox)
Returns true if the bounding box intersects any of the active voxels in a tree, i.e. ignores active tile values.
Definition: FindActiveValues.h:654
bool anyActiveTiles(const CoordBBox &bbox) const
Returns true if the specified bounding box intersects any active tiles only.
Definition: FindActiveValues.h:305
std::vector< TileData< typename TreeT::ValueType > > activeTiles(const TreeT &tree, const CoordBBox &bbox)
Return a vector with bounding boxes that represents all the intersections between active tiles in the...
Definition: FindActiveValues.h:689
void update(const TreeT &tree)
Initiate this class with a new (or modified) tree.
Definition: FindActiveValues.h:238
RootChild(const Coord &ijk=Coord(), const RootChildType *ptr=nullptr)
Definition: FindActiveValues.h:588
Definition: FindActiveValues.h:584
TileData(const CoordBBox &b, const ValueType &v, Index l, bool active=true)
Member data constructor.
Definition: FindActiveValues.h:608
Definition: Exceptions.h:13
CoordBBox bbox
Definition: FindActiveValues.h:599
Index level
Definition: FindActiveValues.h:601
std::vector< TileDataT > activeTiles(const CoordBBox &bbox) const
Return a vector with bounding boxes that represents all the intersections between active tiles in the...
Definition: FindActiveValues.h:353
const CoordBBox bbox
Definition: FindActiveValues.h:586
Index32 Index
Definition: Types.h:54
Functions to count tiles, nodes or voxels in a grid.
Level getLevel()
Return the current logging level.
Definition: logging.h:141
ValueAccessors are designed to help accelerate accesses into the OpenVDB Tree structures by storing c...
const RootChildType * child
Definition: FindActiveValues.h:587
Index64 countActiveVoxels(const TreeT &tree, bool threaded=true)
Return the total number of active voxels in the tree.
Definition: Count.h:413
ValueType value
Definition: FindActiveValues.h:600
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
TileData< typename TreeT::ValueType > TileDataT
Definition: FindActiveValues.h:144
bool noActiveValues(const TreeT &tree, const CoordBBox &bbox)
Returns true if the bounding box intersects none of the active values in a tree, i.e. neither active voxels or active tiles.
Definition: FindActiveValues.h:672
Index64 countActiveValues(const TreeT &tree, const CoordBBox &bbox)
Returns the number of active values that intersects a bounding box intersects, i.e. the count includes both active voxels and virtual voxels in active tiles.
Definition: FindActiveValues.h:681
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212
bool noActiveValues(const CoordBBox &bbox, bool useAccessor=false) const
Returns true if the specified bounding box does not intersect any active values.
Definition: FindActiveValues.h:173
bool state
Definition: FindActiveValues.h:602