1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
4 /// @file Count.h
5 ///
6 /// @brief Functions to count tiles, nodes or voxels in a grid
7 ///
8 /// @author Dan Bailey
9 ///
10
11 #ifndef OPENVDB_TOOLS_COUNT_HAS_BEEN_INCLUDED
12 #define OPENVDB_TOOLS_COUNT_HAS_BEEN_INCLUDED
13
14 #include <openvdb/version.h>
15 #include <openvdb/tree/LeafManager.h>
16 #include <openvdb/tree/NodeManager.h>
17
18 namespace openvdb {
19 OPENVDB_USE_VERSION_NAMESPACE
20 namespace OPENVDB_VERSION_NAME {
21 namespace tools {
22
23
24 /// @brief Return the total number of active voxels in the tree.
25 template <typename TreeT>
26 Index64 countActiveVoxels(const TreeT& tree, bool threaded = true);
27
28
29 /// @brief Return the total number of active voxels in the tree that intersects
30 /// a bounding box.
31 template <typename TreeT>
32 Index64 countActiveVoxels(const TreeT& tree, const CoordBBox& bbox, bool threaded = true);
33
34
35 /// @brief Return the total number of active voxels stored in leaf nodes.
36 template <typename TreeT>
37 Index64 countActiveLeafVoxels(const TreeT& tree, bool threaded = true);
38
39
40 /// @brief Return the total number of active voxels stored in leaf nodes that intersects
41 /// a bounding box.
42 template <typename TreeT>
43 Index64 countActiveLeafVoxels(const TreeT& tree, const CoordBBox& bbox, bool threaded = true);
44
45
46 /// @brief Return the total number of inactive voxels in the tree.
47 template <typename TreeT>
48 Index64 countInactiveVoxels(const TreeT& tree, bool threaded = true);
49
50
51 /// @brief Return the total number of inactive voxels stored in leaf nodes.
52 template <typename TreeT>
53 Index64 countInactiveLeafVoxels(const TreeT& tree, bool threaded = true);
54
55
56 /// @brief Return the total number of active tiles in the tree.
57 template <typename TreeT>
58 Index64 countActiveTiles(const TreeT& tree, bool threaded = true);
59
60
61 /// @brief Return the total amount of memory in bytes occupied by this tree.
62 template <typename TreeT>
63 Index64 memUsage(const TreeT& tree, bool threaded = true);
64
65
66 ////////////////////////////////////////
67
68 /// @cond OPENVDB_DOCS_INTERNAL
69
70 namespace count_internal {
71
72 /// @brief A DynamicNodeManager operator to count active voxels in a tree
73 template<typename TreeType>
74 struct ActiveVoxelCountOp
75 {
76 using LeafT = typename TreeType::LeafNodeType;
77
78 ActiveVoxelCountOp() = default;
ActiveVoxelCountOpActiveVoxelCountOp79 ActiveVoxelCountOp(const ActiveVoxelCountOp&, tbb::split) { }
80
81 // accumulate all voxels in active tile children
82 template<typename NodeT>
operatorActiveVoxelCountOp83 bool operator()(const NodeT& node, size_t)
84 {
85 for (auto iter = node.cbeginValueOn(); iter; ++iter) {
86 count += NodeT::ChildNodeType::NUM_VOXELS;
87 }
88 return true;
89 }
90
91 // accumulate all active voxels in the leaf
operatorActiveVoxelCountOp92 bool operator()(const LeafT& leaf, size_t)
93 {
94 count += leaf.onVoxelCount();
95 return false;
96 }
97
joinActiveVoxelCountOp98 void join(const ActiveVoxelCountOp& other)
99 {
100 count += other.count;
101 }
102
103 openvdb::Index64 count{0};
104 }; // struct ActiveVoxelCountOp
105
106 /// @brief A DynamicNodeManager operator to count active voxels in a tree
107 /// that fall within a provided bounding box
108 template<typename TreeType>
109 struct ActiveVoxelCountBBoxOp
110 {
111 using LeafT = typename TreeType::LeafNodeType;
112
ActiveVoxelCountBBoxOpActiveVoxelCountBBoxOp113 explicit ActiveVoxelCountBBoxOp(const CoordBBox& bbox)
114 : mBBox(bbox) { }
ActiveVoxelCountBBoxOpActiveVoxelCountBBoxOp115 ActiveVoxelCountBBoxOp(const ActiveVoxelCountBBoxOp& other, tbb::split)
116 : mBBox(other.mBBox) { }
117
118 // accumulate all voxels in active tile children bounded by the bbox
119 template<typename NodeT>
operatorActiveVoxelCountBBoxOp120 bool operator()(const NodeT& node, size_t)
121 {
122 if (!mBBox.hasOverlap(node.getNodeBoundingBox())) return false;
123
124 // count any overlapping regions in active tiles
125 for (auto iter = node.cbeginValueOn(); iter; ++iter) {
126 CoordBBox bbox(CoordBBox::createCube(iter.getCoord(), NodeT::ChildNodeType::DIM));
127
128 if (!bbox.hasOverlap(mBBox)) {
129 // box is completely outside the active tile
130 continue;
131 } else if (bbox.isInside(mBBox)) {
132 // bbox is completely inside the active tile
133 count += mBBox.volume();
134 } else if (mBBox.isInside(bbox)) {
135 // active tile is completely inside bbox
136 count += bbox.volume();
137 } else {
138 // partial overlap between tile and bbox
139 bbox.intersect(mBBox);
140 count += bbox.volume();
141 }
142 }
143
144 // return true if any child nodes overlap with the bounding box
145 for (auto iter = node.cbeginChildOn(); iter; ++iter) {
146 if (mBBox.hasOverlap(iter->getNodeBoundingBox())) return true;
147 }
148
149 // otherwise return false to prevent recursion along this branch
150 return false;
151 }
152
153 // accumulate all active voxels in the leaf bounded by the bbox
operatorActiveVoxelCountBBoxOp154 inline bool operator()(const LeafT& leaf, size_t)
155 {
156 // note: the true/false return value does nothing
157
158 CoordBBox bbox = leaf.getNodeBoundingBox();
159
160 if (mBBox.isInside(bbox)) {
161 // leaf node is completely inside bbox
162 count += leaf.onVoxelCount();
163 } else if (!bbox.hasOverlap(mBBox)) {
164 // bbox is completely outside the leaf node
165 return false;
166 } else if (leaf.isDense()) {
167 // partial overlap between dense leaf node and bbox
168 bbox.intersect(mBBox);
169 count += bbox.volume();
170 } else {
171 // partial overlap between sparse leaf node and bbox
172 for (auto i = leaf.cbeginValueOn(); i; ++i) {
173 if (mBBox.isInside(i.getCoord())) ++count;
174 }
175 }
176 return false;
177 }
178
joinActiveVoxelCountBBoxOp179 void join(const ActiveVoxelCountBBoxOp& other)
180 {
181 count += other.count;
182 }
183
184 openvdb::Index64 count{0};
185 private:
186 CoordBBox mBBox;
187 }; // struct ActiveVoxelCountBBoxOp
188
189 /// @brief A DynamicNodeManager operator to count inactive voxels in a tree
190 template<typename TreeType>
191 struct InactiveVoxelCountOp
192 {
193 using RootT = typename TreeType::RootNodeType;
194 using LeafT = typename TreeType::LeafNodeType;
195
196 InactiveVoxelCountOp() = default;
InactiveVoxelCountOpInactiveVoxelCountOp197 InactiveVoxelCountOp(const InactiveVoxelCountOp&, tbb::split) { }
198
199 // accumulate all inactive voxels in the root node
operatorInactiveVoxelCountOp200 bool operator()(const RootT& root, size_t)
201 {
202 for (auto iter = root.cbeginValueOff(); iter; ++iter) {
203 // background tiles are not considered to contain inactive voxels
204 if (!math::isApproxEqual(*iter, root.background())) {
205 count += RootT::ChildNodeType::NUM_VOXELS;
206 }
207 }
208 return true;
209 }
210
211 // accumulate all voxels in inactive tile children
212 template<typename NodeT>
operatorInactiveVoxelCountOp213 bool operator()(const NodeT& node, size_t)
214 {
215 for (auto iter = node.cbeginValueOff(); iter; ++iter) {
216 if (node.isChildMaskOff(iter.pos())) {
217 count += NodeT::ChildNodeType::NUM_VOXELS;
218 }
219 }
220 return true;
221 }
222
223 // accumulate all inactive voxels in the leaf
operatorInactiveVoxelCountOp224 bool operator()(const LeafT& leaf, size_t)
225 {
226 count += leaf.offVoxelCount();
227 return false;
228 }
229
joinInactiveVoxelCountOp230 void join(const InactiveVoxelCountOp& other)
231 {
232 count += other.count;
233 }
234
235 openvdb::Index64 count{0};
236 }; // struct InactiveVoxelCountOp
237
238 /// @brief A DynamicNodeManager operator to count active tiles in a tree
239 template<typename TreeType>
240 struct ActiveTileCountOp
241 {
242 using RootT = typename TreeType::RootNodeType;
243 using LeafT = typename TreeType::LeafNodeType;
244
245 ActiveTileCountOp() = default;
ActiveTileCountOpActiveTileCountOp246 ActiveTileCountOp(const ActiveTileCountOp&, tbb::split) { }
247
248 // accumulate all active tiles in root node
operatorActiveTileCountOp249 bool operator()(const RootT& root, size_t)
250 {
251 for (auto iter = root.cbeginValueOn(); iter; ++iter) count++;
252 return true;
253 }
254
255 // accumulate all active tiles in internal node
256 template<typename NodeT>
operatorActiveTileCountOp257 bool operator()(const NodeT& node, size_t)
258 {
259 count += node.getValueMask().countOn();
260 return true;
261 }
262
263 // do nothing (leaf nodes cannot contain tiles)
operatorActiveTileCountOp264 bool operator()(const LeafT&, size_t)
265 {
266 return false;
267 }
268
joinActiveTileCountOp269 void join(const ActiveTileCountOp& other)
270 {
271 count += other.count;
272 }
273
274 openvdb::Index64 count{0};
275 }; // struct ActiveTileCountOp
276
277 /// @brief A DynamicNodeManager operator to sum the number of bytes of memory used
278 template<typename TreeType>
279 struct MemUsageOp
280 {
281 using RootT = typename TreeType::RootNodeType;
282 using LeafT = typename TreeType::LeafNodeType;
283
284 MemUsageOp() = default;
MemUsageOpMemUsageOp285 MemUsageOp(const MemUsageOp&, tbb::split) { }
286
287 // accumulate size of the root node in bytes
operatorMemUsageOp288 bool operator()(const RootT& root, size_t)
289 {
290 count += sizeof(root);
291 return true;
292 }
293
294 // accumulate size of all child nodes in bytes
295 template<typename NodeT>
operatorMemUsageOp296 bool operator()(const NodeT& node, size_t)
297 {
298 count += NodeT::NUM_VALUES * sizeof(typename NodeT::UnionType) +
299 node.getChildMask().memUsage() + node.getValueMask().memUsage() +
300 sizeof(Coord);
301 return true;
302 }
303
304 // accumulate size of leaf node in bytes
operatorMemUsageOp305 bool operator()(const LeafT& leaf, size_t)
306 {
307 count += leaf.memUsage();
308 return false;
309 }
310
joinMemUsageOp311 void join(const MemUsageOp& other)
312 {
313 count += other.count;
314 }
315
316 openvdb::Index64 count{0};
317 }; // struct MemUsageOp
318
319 } // namespace count_internal
320
321 /// @endcond
322
323
324 ////////////////////////////////////////
325
326
327 template <typename TreeT>
countActiveVoxels(const TreeT & tree,bool threaded)328 Index64 countActiveVoxels(const TreeT& tree, bool threaded)
329 {
330 count_internal::ActiveVoxelCountOp<TreeT> op;
331 tree::DynamicNodeManager<const TreeT> nodeManager(tree);
332 nodeManager.reduceTopDown(op, threaded);
333 return op.count;
334 }
335
336
337 template <typename TreeT>
countActiveVoxels(const TreeT & tree,const CoordBBox & bbox,bool threaded)338 Index64 countActiveVoxels(const TreeT& tree, const CoordBBox& bbox, bool threaded)
339 {
340 if (bbox.empty()) return Index64(0);
341 else if (bbox == CoordBBox::inf()) return countActiveVoxels(tree, threaded);
342
343 count_internal::ActiveVoxelCountBBoxOp<TreeT> op(bbox);
344 tree::DynamicNodeManager<const TreeT> nodeManager(tree);
345 nodeManager.reduceTopDown(op, threaded);
346 return op.count;
347 }
348
349
350 template <typename TreeT>
countActiveLeafVoxels(const TreeT & tree,bool threaded)351 Index64 countActiveLeafVoxels(const TreeT& tree, bool threaded)
352 {
353 count_internal::ActiveVoxelCountOp<TreeT> op;
354 // use a leaf manager instead of a node manager
355 tree::LeafManager<const TreeT> leafManager(tree);
356 leafManager.reduce(op, threaded);
357 return op.count;
358 }
359
360
361 template <typename TreeT>
countActiveLeafVoxels(const TreeT & tree,const CoordBBox & bbox,bool threaded)362 Index64 countActiveLeafVoxels(const TreeT& tree, const CoordBBox& bbox, bool threaded)
363 {
364 if (bbox.empty()) return Index64(0);
365 else if (bbox == CoordBBox::inf()) return countActiveLeafVoxels(tree, threaded);
366
367 count_internal::ActiveVoxelCountBBoxOp<TreeT> op(bbox);
368 // use a leaf manager instead of a node manager
369 tree::LeafManager<const TreeT> leafManager(tree);
370 leafManager.reduce(op, threaded);
371 return op.count;
372 }
373
374
375 template <typename TreeT>
countInactiveVoxels(const TreeT & tree,bool threaded)376 Index64 countInactiveVoxels(const TreeT& tree, bool threaded)
377 {
378 count_internal::InactiveVoxelCountOp<TreeT> op;
379 tree::DynamicNodeManager<const TreeT> nodeManager(tree);
380 nodeManager.reduceTopDown(op, threaded);
381 return op.count;
382 }
383
384
385 template <typename TreeT>
countInactiveLeafVoxels(const TreeT & tree,bool threaded)386 Index64 countInactiveLeafVoxels(const TreeT& tree, bool threaded)
387 {
388 count_internal::InactiveVoxelCountOp<TreeT> op;
389 // use a leaf manager instead of a node manager
390 tree::LeafManager<const TreeT> leafManager(tree);
391 leafManager.reduce(op, threaded);
392 return op.count;
393 }
394
395
396 template <typename TreeT>
countActiveTiles(const TreeT & tree,bool threaded)397 Index64 countActiveTiles(const TreeT& tree, bool threaded)
398 {
399 count_internal::ActiveTileCountOp<TreeT> op;
400 // exclude leaf nodes as they cannot contain tiles
401 tree::DynamicNodeManager<const TreeT, TreeT::DEPTH-2> nodeManager(tree);
402 nodeManager.reduceTopDown(op, threaded);
403 return op.count;
404 }
405
406
407 template <typename TreeT>
memUsage(const TreeT & tree,bool threaded)408 Index64 memUsage(const TreeT& tree, bool threaded)
409 {
410 count_internal::MemUsageOp<TreeT> op;
411 tree::DynamicNodeManager<const TreeT> nodeManager(tree);
412 nodeManager.reduceTopDown(op, threaded);
413 return op.count + sizeof(tree);
414 }
415
416
417 } // namespace tools
418 } // namespace OPENVDB_VERSION_NAME
419 } // namespace openvdb
420
421 #endif // OPENVDB_TOOLS_COUNT_HAS_BEEN_INCLUDED
422