OpenVDB: openvdb/tools/Composite.h Source File

OpenVDB 9.0.0

Composite.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: MPL-2.0
3//
4/// @file Composite.h
5///
6/// @brief Functions to efficiently perform various compositing operations on grids
7///
8/// @authors Peter Cucka, Mihai Alden, Ken Museth
9
10#ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
11#define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
12
13#include <openvdb/Platform.h>
14#include <openvdb/Exceptions.h>
15#include <openvdb/Types.h>
16#include <openvdb/Grid.h>
17#include <openvdb/math/Math.h> // for isExactlyEqual()
18#include <openvdb/openvdb.h>
19#include "Merge.h"
20#include "ValueTransformer.h" // for transformValues()
21#include "Prune.h"// for prune
22#include "SignedFloodFill.h" // for signedFloodFill()
23
24#include <tbb/blocked_range.h>
25#include <tbb/parallel_for.h>
26#include <tbb/parallel_reduce.h>
27#include <tbb/task_group.h>
28
29#include <type_traits>
30#include <functional>
31
32namespace openvdb {
33 OPENVDB_USE_VERSION_NAMESPACE
34namespace OPENVDB_VERSION_NAME {
35namespace tools {
36
37/// @brief Given two level set grids, replace the A grid with the union of A and B.
38/// @throw ValueError if the background value of either grid is not greater than zero.
39/// @note This operation always leaves the B grid empty.
40template<typename GridOrTreeT>
41void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
42/// @brief Given two level set grids, replace the A grid with the intersection of A and B.
43/// @throw ValueError if the background value of either grid is not greater than zero.
44/// @note This operation always leaves the B grid empty.
45template<typename GridOrTreeT>
46void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
47/// @brief Given two level set grids, replace the A grid with the difference A / B.
48/// @throw ValueError if the background value of either grid is not greater than zero.
49/// @note This operation always leaves the B grid empty.
50template<typename GridOrTreeT>
51void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true);
52
53/// @brief Threaded CSG union operation that produces a new grid or tree from
54/// immutable inputs.
55/// @return The CSG union of the @a and @b level set inputs.
56template<typename GridOrTreeT>
57typename GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
58/// @brief Threaded CSG intersection operation that produces a new grid or tree from
59/// immutable inputs.
60/// @return The CSG intersection of the @a and @b level set inputs.
61template<typename GridOrTreeT>
62typename GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b);
63/// @brief Threaded CSG difference operation that produces a new grid or tree from
64/// immutable inputs.
65/// @return The CSG difference of the @a and @b level set inputs.
66template<typename GridOrTreeT>
67typename GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b);
68
69/// @brief Given grids A and B, compute max(a, b) per voxel (using sparse traversal).
70/// Store the result in the A grid and leave the B grid empty.
71template<typename GridOrTreeT>
72void compMax(GridOrTreeT& a, GridOrTreeT& b);
73/// @brief Given grids A and B, compute min(a, b) per voxel (using sparse traversal).
74/// Store the result in the A grid and leave the B grid empty.
75template<typename GridOrTreeT>
76void compMin(GridOrTreeT& a, GridOrTreeT& b);
77/// @brief Given grids A and B, compute a + b per voxel (using sparse traversal).
78/// Store the result in the A grid and leave the B grid empty.
79template<typename GridOrTreeT>
80void compSum(GridOrTreeT& a, GridOrTreeT& b);
81/// @brief Given grids A and B, compute a * b per voxel (using sparse traversal).
82/// Store the result in the A grid and leave the B grid empty.
83template<typename GridOrTreeT>
84void compMul(GridOrTreeT& a, GridOrTreeT& b);
85/// @brief Given grids A and B, compute a / b per voxel (using sparse traversal).
86/// Store the result in the A grid and leave the B grid empty.
87template<typename GridOrTreeT>
88void compDiv(GridOrTreeT& a, GridOrTreeT& b);
89
90/// Copy the active voxels of B into A.
91template<typename GridOrTreeT>
92void compReplace(GridOrTreeT& a, const GridOrTreeT& b);
93
94
95////////////////////////////////////////
96
97
98 namespace composite {
99
100// composite::min() and composite::max() for non-vector types compare with operator<().
101template<typename T> inline
102const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& // = T if T is not a vector type
103 min(const T& a, const T& b) { return std::min(a, b); }
104
105template<typename T> inline
106const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
107 max(const T& a, const T& b) { return std::max(a, b); }
108
109
110// composite::min() and composite::max() for OpenVDB vector types compare by magnitude.
111template<typename T> inline
112const typename std::enable_if<VecTraits<T>::IsVec, T>::type& // = T if T is a vector type
113min(const T& a, const T& b)
114{
115 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
116 return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
117}
118
119template<typename T> inline
120const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
121max(const T& a, const T& b)
122{
123 const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
124 return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
125}
126
127
128template<typename T> inline
129typename std::enable_if<!std::is_integral<T>::value, T>::type // = T if T is not an integer type
130 divide(const T& a, const T& b) { return a / b; }
131
132template<typename T> inline
133typename std::enable_if<std::is_integral<T>::value, T>::type // = T if T is an integer type
134 divide(const T& a, const T& b)
135{
136 const T zero(0);
137 if (b != zero) return a / b;
138 if (a == zero) return 0;
139 return (a > 0 ? std::numeric_limits<T>::max() : -std::numeric_limits<T>::max());
140}
141
142// If b is true, return a / 1 = a.
143// If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a.
144// If b is false and a is false, return 0 / 0 = NaN = 0 = a.
145 inline bool divide(bool a, bool /*b*/) { return a; }
146
147
148/// @cond OPENVDB_DOCS_INTERNAL
149
150enum CSGOperation { CSG_UNION, CSG_INTERSECTION, CSG_DIFFERENCE };
151
152template<typename TreeType, CSGOperation Operation>
153struct BuildPrimarySegment
154{
155 using ValueType = typename TreeType::ValueType;
156 using TreePtrType = typename TreeType::Ptr;
157 using LeafNodeType = typename TreeType::LeafNodeType;
158 using NodeMaskType = typename LeafNodeType::NodeMaskType;
159 using RootNodeType = typename TreeType::RootNodeType;
160 using NodeChainType = typename RootNodeType::NodeChainType;
161 using InternalNodeType = typename NodeChainType::template Get<1>;
162
163 BuildPrimarySegment(const TreeType& lhs, const TreeType& rhs)
164 : mSegment(new TreeType(lhs.background()))
165 , mLhsTree(&lhs)
166 , mRhsTree(&rhs)
167 {
168 }
169
170 void operator()() const
171 {
172 std::vector<const LeafNodeType*> leafNodes;
173
174 {
175 std::vector<const InternalNodeType*> internalNodes;
176 mLhsTree->getNodes(internalNodes);
177
178 ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
179 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
180 }
181
182 ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
183 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
184 }
185
186 TreePtrType& segment() { return mSegment; }
187
188private:
189
190 struct ProcessInternalNodes {
191
192 ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
193 const TreeType& rhsTree, TreeType& outputTree,
194 std::vector<const LeafNodeType*>& outputLeafNodes)
195 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
196 , mRhsTree(&rhsTree)
197 , mLocalTree(mRhsTree->background())
198 , mOutputTree(&outputTree)
199 , mLocalLeafNodes()
200 , mOutputLeafNodes(&outputLeafNodes)
201 {
202 }
203
204 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
205 : mLhsNodes(other.mLhsNodes)
206 , mRhsTree(other.mRhsTree)
207 , mLocalTree(mRhsTree->background())
208 , mOutputTree(&mLocalTree)
209 , mLocalLeafNodes()
210 , mOutputLeafNodes(&mLocalLeafNodes)
211 {
212 }
213
214 void join(ProcessInternalNodes& other)
215 {
216 mOutputTree->merge(*other.mOutputTree);
217 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
218 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
219 }
220
221 void operator()(const tbb::blocked_range<size_t>& range)
222 {
223 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
224 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
225
226 std::vector<const LeafNodeType*> tmpLeafNodes;
227
228 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
229
230 const InternalNodeType& lhsNode = *mLhsNodes[n];
231 const Coord& ijk = lhsNode.origin();
232 const InternalNodeType * rhsNode =
233 rhsAcc.template probeConstNode<InternalNodeType>(ijk);
234
235 if (rhsNode) {
236 lhsNode.getNodes(*mOutputLeafNodes);
237 } else {
238 if (Operation == CSG_INTERSECTION) {
239 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
240 tmpLeafNodes.clear();
241 lhsNode.getNodes(tmpLeafNodes);
242 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
243 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
244 }
245 }
246 } else { // Union & Difference
247 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
248 tmpLeafNodes.clear();
249 lhsNode.getNodes(tmpLeafNodes);
250 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
251 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
252 }
253 }
254 }
255 }
256 } // end range loop
257 }
258
259 InternalNodeType const * const * const mLhsNodes;
260 TreeType const * const mRhsTree;
261 TreeType mLocalTree;
262 TreeType * const mOutputTree;
263
264 std::vector<const LeafNodeType*> mLocalLeafNodes;
265 std::vector<const LeafNodeType*> * const mOutputLeafNodes;
266 }; // struct ProcessInternalNodes
267
268 struct ProcessLeafNodes {
269
270 ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
271 const TreeType& rhsTree, TreeType& output)
272 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes.front())
273 , mRhsTree(&rhsTree)
274 , mLocalTree(mRhsTree->background())
275 , mOutputTree(&output)
276 {
277 }
278
279 ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
280 : mLhsNodes(other.mLhsNodes)
281 , mRhsTree(other.mRhsTree)
282 , mLocalTree(mRhsTree->background())
283 , mOutputTree(&mLocalTree)
284 {
285 }
286
287 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
288
289 void operator()(const tbb::blocked_range<size_t>& range)
290 {
291 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
292 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
293
294 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
295
296 const LeafNodeType& lhsNode = *mLhsNodes[n];
297 const Coord& ijk = lhsNode.origin();
298
299 const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
300
301 if (rhsNodePt) { // combine overlapping nodes
302
303 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
304 ValueType * outputData = outputNode->buffer().data();
305 NodeMaskType& outputMask = outputNode->getValueMask();
306
307 const ValueType * lhsData = lhsNode.buffer().data();
308 const NodeMaskType& lhsMask = lhsNode.getValueMask();
309
310 const ValueType * rhsData = rhsNodePt->buffer().data();
311 const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
312
313 if (Operation == CSG_INTERSECTION) {
314 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
315 const bool fromRhs = lhsData[pos] < rhsData[pos];
316 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
317 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
318 }
319 } else if (Operation == CSG_DIFFERENCE){
320 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
321 const ValueType rhsVal = math::negative(rhsData[pos]);
322 const bool fromRhs = lhsData[pos] < rhsVal;
323 outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
324 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
325 }
326 } else { // Union
327 for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
328 const bool fromRhs = lhsData[pos] > rhsData[pos];
329 outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
330 outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
331 }
332 }
333
334 } else {
335 if (Operation == CSG_INTERSECTION) {
336 if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
337 outputAcc.addLeaf(new LeafNodeType(lhsNode));
338 }
339 } else { // Union & Difference
340 if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
341 outputAcc.addLeaf(new LeafNodeType(lhsNode));
342 }
343 }
344 }
345 } // end range loop
346 }
347
348 LeafNodeType const * const * const mLhsNodes;
349 TreeType const * const mRhsTree;
350 TreeType mLocalTree;
351 TreeType * const mOutputTree;
352 }; // struct ProcessLeafNodes
353
354 TreePtrType mSegment;
355 TreeType const * const mLhsTree;
356 TreeType const * const mRhsTree;
357}; // struct BuildPrimarySegment
358
359
360template<typename TreeType, CSGOperation Operation>
361struct BuildSecondarySegment
362{
363 using ValueType = typename TreeType::ValueType;
364 using TreePtrType = typename TreeType::Ptr;
365 using LeafNodeType = typename TreeType::LeafNodeType;
366 using NodeMaskType = typename LeafNodeType::NodeMaskType;
367 using RootNodeType = typename TreeType::RootNodeType;
368 using NodeChainType = typename RootNodeType::NodeChainType;
369 using InternalNodeType = typename NodeChainType::template Get<1>;
370
371 BuildSecondarySegment(const TreeType& lhs, const TreeType& rhs)
372 : mSegment(new TreeType(lhs.background()))
373 , mLhsTree(&lhs)
374 , mRhsTree(&rhs)
375 {
376 }
377
378 void operator()() const
379 {
380 std::vector<const LeafNodeType*> leafNodes;
381
382 {
383 std::vector<const InternalNodeType*> internalNodes;
384 mRhsTree->getNodes(internalNodes);
385
386 ProcessInternalNodes op(internalNodes, *mLhsTree, *mSegment, leafNodes);
387 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
388 }
389
390 ProcessLeafNodes op(leafNodes, *mLhsTree, *mSegment);
391 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
392 }
393
394 TreePtrType& segment() { return mSegment; }
395
396private:
397
398 struct ProcessInternalNodes {
399
400 ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
401 const TreeType& lhsTree, TreeType& outputTree,
402 std::vector<const LeafNodeType*>& outputLeafNodes)
403 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
404 , mLhsTree(&lhsTree)
405 , mLocalTree(mLhsTree->background())
406 , mOutputTree(&outputTree)
407 , mLocalLeafNodes()
408 , mOutputLeafNodes(&outputLeafNodes)
409 {
410 }
411
412 ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
413 : mRhsNodes(other.mRhsNodes)
414 , mLhsTree(other.mLhsTree)
415 , mLocalTree(mLhsTree->background())
416 , mOutputTree(&mLocalTree)
417 , mLocalLeafNodes()
418 , mOutputLeafNodes(&mLocalLeafNodes)
419 {
420 }
421
422 void join(ProcessInternalNodes& other)
423 {
424 mOutputTree->merge(*other.mOutputTree);
425 mOutputLeafNodes->insert(mOutputLeafNodes->end(),
426 other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
427 }
428
429 void operator()(const tbb::blocked_range<size_t>& range)
430 {
431 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
432 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
433
434 std::vector<const LeafNodeType*> tmpLeafNodes;
435
436 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
437
438 const InternalNodeType& rhsNode = *mRhsNodes[n];
439 const Coord& ijk = rhsNode.origin();
440 const InternalNodeType * lhsNode =
441 lhsAcc.template probeConstNode<InternalNodeType>(ijk);
442
443 if (lhsNode) {
444 rhsNode.getNodes(*mOutputLeafNodes);
445 } else {
446 if (Operation == CSG_INTERSECTION) {
447 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
448 tmpLeafNodes.clear();
449 rhsNode.getNodes(tmpLeafNodes);
450 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
451 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
452 }
453 }
454 } else if (Operation == CSG_DIFFERENCE) {
455 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
456 tmpLeafNodes.clear();
457 rhsNode.getNodes(tmpLeafNodes);
458 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
459 LeafNodeType* outputNode = new LeafNodeType(*tmpLeafNodes[i]);
460 outputNode->negate();
461 outputAcc.addLeaf(outputNode);
462 }
463 }
464 } else { // Union
465 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
466 tmpLeafNodes.clear();
467 rhsNode.getNodes(tmpLeafNodes);
468 for (size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
469 outputAcc.addLeaf(new LeafNodeType(*tmpLeafNodes[i]));
470 }
471 }
472 }
473 }
474 } // end range loop
475 }
476
477 InternalNodeType const * const * const mRhsNodes;
478 TreeType const * const mLhsTree;
479 TreeType mLocalTree;
480 TreeType * const mOutputTree;
481
482 std::vector<const LeafNodeType*> mLocalLeafNodes;
483 std::vector<const LeafNodeType*> * const mOutputLeafNodes;
484 }; // struct ProcessInternalNodes
485
486 struct ProcessLeafNodes {
487
488 ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
489 const TreeType& lhsTree, TreeType& output)
490 : mRhsNodes(rhsNodes.empty() ? nullptr : &rhsNodes.front())
491 , mLhsTree(&lhsTree)
492 , mLocalTree(mLhsTree->background())
493 , mOutputTree(&output)
494 {
495 }
496
497 ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
498 : mRhsNodes(rhs.mRhsNodes)
499 , mLhsTree(rhs.mLhsTree)
500 , mLocalTree(mLhsTree->background())
501 , mOutputTree(&mLocalTree)
502 {
503 }
504
505 void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
506
507 void operator()(const tbb::blocked_range<size_t>& range)
508 {
509 tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
510 tree::ValueAccessor<TreeType> outputAcc(*mOutputTree);
511
512 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
513
514 const LeafNodeType& rhsNode = *mRhsNodes[n];
515 const Coord& ijk = rhsNode.origin();
516
517 const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
518
519 if (!lhsNode) {
520 if (Operation == CSG_INTERSECTION) {
521 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
522 outputAcc.addLeaf(new LeafNodeType(rhsNode));
523 }
524 } else if (Operation == CSG_DIFFERENCE) {
525 if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
526 LeafNodeType* outputNode = new LeafNodeType(rhsNode);
527 outputNode->negate();
528 outputAcc.addLeaf(outputNode);
529 }
530 } else { // Union
531 if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
532 outputAcc.addLeaf(new LeafNodeType(rhsNode));
533 }
534 }
535 }
536 } // end range loop
537 }
538
539 LeafNodeType const * const * const mRhsNodes;
540 TreeType const * const mLhsTree;
541 TreeType mLocalTree;
542 TreeType * const mOutputTree;
543 }; // struct ProcessLeafNodes
544
545 TreePtrType mSegment;
546 TreeType const * const mLhsTree;
547 TreeType const * const mRhsTree;
548}; // struct BuildSecondarySegment
549
550
551template<CSGOperation Operation, typename TreeType>
552typename TreeType::Ptr
553doCSGCopy(const TreeType& lhs, const TreeType& rhs)
554{
555 BuildPrimarySegment<TreeType, Operation> primary(lhs, rhs);
556 BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
557
558 // Exploiting nested parallelism
559 tbb::task_group tasks;
560 tasks.run(primary);
561 tasks.run(secondary);
562 tasks.wait();
563
564 primary.segment()->merge(*secondary.segment());
565
566 // The leafnode (level = 0) sign is set in the segment construction.
567 tools::signedFloodFill(*primary.segment(), /*threaded=*/true, /*grainSize=*/1, /*minLevel=*/1);
568
569 return primary.segment();
570}
571
572
573////////////////////////////////////////
574
575
576template<typename TreeType>
577struct GridOrTreeConstructor
578{
579 using TreeTypePtr = typename TreeType::Ptr;
580 static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; }
581};
582
583
584template<typename TreeType>
585struct GridOrTreeConstructor<Grid<TreeType> >
586{
587 using GridType = Grid<TreeType>;
588 using GridTypePtr = typename Grid<TreeType>::Ptr;
589 using TreeTypePtr = typename TreeType::Ptr;
590
591 static GridTypePtr construct(const GridType& grid, TreeTypePtr& tree) {
592 GridTypePtr maskGrid(GridType::create(tree));
593 maskGrid->setTransform(grid.transform().copy());
594 maskGrid->insertMeta(grid);
595 return maskGrid;
596 }
597};
598
599
600////////////////////////////////////////
601
602/// List of pairs of leaf node pointers
603template <typename LeafT>
604using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
605
606/// Transfers leaf nodes from a source tree into a
607/// destination tree, unless it already exists in the destination tree
608/// in which case pointers to both leaf nodes are added to a list for
609/// subsequent compositing operations.
610template <typename TreeT>
611void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
612 LeafPairList<typename TreeT::LeafNodeType> &overlapping)
613{
614 using LeafT = typename TreeT::LeafNodeType;
615 tree::ValueAccessor<TreeT> acc(dstTree);//destination
616 std::vector<LeafT*> srcLeafNodes;
617 srcLeafNodes.reserve(srcTree.leafCount());
618 srcTree.stealNodes(srcLeafNodes);
619 srcTree.clear();
620 for (LeafT *srcLeaf : srcLeafNodes) {
621 LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
622 if (dstLeaf) {
623 overlapping.emplace_back(dstLeaf, srcLeaf);//dst, src
624 } else {
625 acc.addLeaf(srcLeaf);
626 }
627 }
628}
629
630/// Template specialization of compActiveLeafVoxels
631template <typename TreeT, typename OpT>
632inline
633typename std::enable_if<
634 !std::is_same<typename TreeT::ValueType, bool>::value &&
635 !std::is_same<typename TreeT::BuildType, ValueMask>::value &&
636 std::is_same<typename TreeT::LeafNodeType::Buffer::ValueType,
637 typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
638doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
639{
640 using LeafT = typename TreeT::LeafNodeType;
641 LeafPairList<LeafT> overlapping;//dst, src
642 transferLeafNodes(srcTree, dstTree, overlapping);
643
644 using RangeT = tbb::blocked_range<size_t>;
645 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
646 for (auto i = r.begin(); i != r.end(); ++i) {
647 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
648 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
649 auto *ptr = dstLeaf->buffer().data();
650 for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
651 delete srcLeaf;
652 }
653 });
654}
655
656/// Template specialization of compActiveLeafVoxels
657template <typename TreeT, typename OpT>
658inline
659typename std::enable_if<
660 std::is_same<typename TreeT::BuildType, ValueMask>::value &&
661 std::is_same<typename TreeT::ValueType, bool>::value>::type
662doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
663{
664 using LeafT = typename TreeT::LeafNodeType;
665 LeafPairList<LeafT> overlapping;//dst, src
666 transferLeafNodes(srcTree, dstTree, overlapping);
667
668 using RangeT = tbb::blocked_range<size_t>;
669 tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](const RangeT& r) {
670 for (auto i = r.begin(); i != r.end(); ++i) {
671 overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
672 delete overlapping[i].second;
673 }
674 });
675}
676
677/// Template specialization of compActiveLeafVoxels
678template <typename TreeT, typename OpT>
679inline
680typename std::enable_if<
681 std::is_same<typename TreeT::ValueType, bool>::value &&
682 !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
683doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
684{
685 using LeafT = typename TreeT::LeafNodeType;
686 LeafPairList<LeafT> overlapping;//dst, src
687 transferLeafNodes(srcTree, dstTree, overlapping);
688
689 using RangeT = tbb::blocked_range<size_t>;
690 using WordT = typename LeafT::Buffer::WordType;
691 tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](const RangeT& r) {
692 for (auto i = r.begin(); i != r.end(); ++i) {
693 LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
694 WordT *w1 = dstLeaf->buffer().data();
695 const WordT *w2 = srcLeaf->buffer().data();
696 const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
697 for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
698 WordT tmp = *w1, state = *w3++;
699 op (tmp, *w2++);
700 *w1 = (state & tmp) | (~state & *w1);//inactive values are unchanged
701 }
702 dstLeaf->getValueMask() |= srcLeaf->getValueMask();
703 delete srcLeaf;
704 }
705 });
706}
707
708/// Default functor for compActiveLeafVoxels
709template <typename TreeT>
710struct CopyOp
711{
712 using ValueT = typename TreeT::ValueType;
713 CopyOp() = default;
714 void operator()(ValueT& dst, const ValueT& src) const { dst = src; }
715};
716
717template <typename TreeT>
718void validateLevelSet(const TreeT& tree, const std::string& gridName = std::string(""))
719{
720 using ValueT = typename TreeT::ValueType;
721 const ValueT zero = zeroVal<ValueT>();
722 if (!(tree.background() > zero)) {
723 std::stringstream ss;
724 ss << "expected grid ";
725 if (!gridName.empty()) ss << gridName << " ";
726 ss << "outside value > 0, got " << tree.background();
727 OPENVDB_THROW(ValueError, ss.str());
728 }
729 if (!(-tree.background() < zero)) {
730 std::stringstream ss;
731 ss << "expected grid ";
732 if (!gridName.empty()) ss << gridName << " ";
733 ss << "inside value < 0, got " << -tree.background();
734 OPENVDB_THROW(ValueError, ss.str());
735 }
736}
737
738/// @endcond
739
740} // namespace composite
741
742
743template<typename GridOrTreeT>
744void
745compMax(GridOrTreeT& aTree, GridOrTreeT& bTree)
746{
747 using Adapter = TreeAdapter<GridOrTreeT>;
748 using TreeT = typename Adapter::TreeType;
749 using ValueT = typename TreeT::ValueType;
750 struct Local {
751 static inline void op(CombineArgs<ValueT>& args) {
752 args.setResult(composite::max(args.a(), args.b()));
753 }
754 };
755 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
756}
757
758
759template<typename GridOrTreeT>
760void
761compMin(GridOrTreeT& aTree, GridOrTreeT& bTree)
762{
763 using Adapter = TreeAdapter<GridOrTreeT>;
764 using TreeT = typename Adapter::TreeType;
765 using ValueT = typename TreeT::ValueType;
766 struct Local {
767 static inline void op(CombineArgs<ValueT>& args) {
768 args.setResult(composite::min(args.a(), args.b()));
769 }
770 };
771 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
772}
773
774
775template<typename GridOrTreeT>
776void
777compSum(GridOrTreeT& aTree, GridOrTreeT& bTree)
778{
779 using Adapter = TreeAdapter<GridOrTreeT>;
780 using TreeT = typename Adapter::TreeType;
781 struct Local {
782 static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
783 args.setResult(args.a() + args.b());
784 }
785 };
786 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
787}
788
789
790template<typename GridOrTreeT>
791void
792compMul(GridOrTreeT& aTree, GridOrTreeT& bTree)
793{
794 using Adapter = TreeAdapter<GridOrTreeT>;
795 using TreeT = typename Adapter::TreeType;
796 struct Local {
797 static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
798 args.setResult(args.a() * args.b());
799 }
800 };
801 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
802}
803
804
805template<typename GridOrTreeT>
806void
807compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree)
808{
809 using Adapter = TreeAdapter<GridOrTreeT>;
810 using TreeT = typename Adapter::TreeType;
811 struct Local {
812 static inline void op(CombineArgs<typename TreeT::ValueType>& args) {
813 args.setResult(composite::divide(args.a(), args.b()));
814 }
815 };
816 Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false);
817}
818
819
820////////////////////////////////////////
821
822
823template<typename TreeT>
824 struct CompReplaceOp
825{
826 TreeT* const aTree;
827
828 CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {}
829
830 /// @note fill operation is not thread safe
831 void operator()(const typename TreeT::ValueOnCIter& iter) const
832 {
833 CoordBBox bbox;
834 iter.getBoundingBox(bbox);
835 aTree->fill(bbox, *iter);
836 }
837
838 void operator()(const typename TreeT::LeafCIter& leafIter) const
839 {
840 tree::ValueAccessor<TreeT> acc(*aTree);
841 for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter =
842 leafIter->cbeginValueOn(); iter; ++iter)
843 {
844 acc.setValue(iter.getCoord(), *iter);
845 }
846 }
847};
848
849
850template<typename GridOrTreeT>
851void
852compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree)
853{
854 using Adapter = TreeAdapter<GridOrTreeT>;
855 using TreeT = typename Adapter::TreeType;
856 using ValueOnCIterT = typename TreeT::ValueOnCIter;
857
858 // Copy active states (but not values) from B to A.
859 Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree));
860
861 CompReplaceOp<TreeT> op(Adapter::tree(aTree));
862
863 // Copy all active tile values from B to A.
864 ValueOnCIterT iter = bTree.cbeginValueOn();
865 iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes
866 foreach(iter, op, /*threaded=*/false);
867
868 // Copy all active voxel values from B to A.
869 foreach(Adapter::tree(bTree).cbeginLeaf(), op);
870}
871
872
873////////////////////////////////////////
874
875
876template<typename GridOrTreeT>
877void
878csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune)
879{
880 using Adapter = TreeAdapter<GridOrTreeT>;
881 using TreeT = typename Adapter::TreeType;
882 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
883 composite::validateLevelSet(aTree, "A");
884 composite::validateLevelSet(bTree, "B");
885 CsgUnionOp<TreeT> op(bTree, Steal());
886 tree::DynamicNodeManager<TreeT> nodeManager(aTree);
887 nodeManager.foreachTopDown(op);
888 if (prune) tools::pruneLevelSet(aTree);
889}
890
891template<typename GridOrTreeT>
892void
893csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune)
894{
895 using Adapter = TreeAdapter<GridOrTreeT>;
896 using TreeT = typename Adapter::TreeType;
897 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
898 composite::validateLevelSet(aTree, "A");
899 composite::validateLevelSet(bTree, "B");
900 CsgIntersectionOp<TreeT> op(bTree, Steal());
901 tree::DynamicNodeManager<TreeT> nodeManager(aTree);
902 nodeManager.foreachTopDown(op);
903 if (prune) tools::pruneLevelSet(aTree);
904}
905
906template<typename GridOrTreeT>
907void
908csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune)
909{
910 using Adapter = TreeAdapter<GridOrTreeT>;
911 using TreeT = typename Adapter::TreeType;
912 TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b);
913 composite::validateLevelSet(aTree, "A");
914 composite::validateLevelSet(bTree, "B");
915 CsgDifferenceOp<TreeT> op(bTree, Steal());
916 tree::DynamicNodeManager<TreeT> nodeManager(aTree);
917 nodeManager.foreachTopDown(op);
918 if (prune) tools::pruneLevelSet(aTree);
919}
920
921
922template<typename GridOrTreeT>
923typename GridOrTreeT::Ptr
924csgUnionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
925{
926 using Adapter = TreeAdapter<GridOrTreeT>;
927 using TreePtrT = typename Adapter::TreeType::Ptr;
928
929 TreePtrT output = composite::doCSGCopy<composite::CSG_UNION>(
930 Adapter::tree(a), Adapter::tree(b));
931
932 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
933}
934
935
936template<typename GridOrTreeT>
937typename GridOrTreeT::Ptr
938csgIntersectionCopy(const GridOrTreeT& a, const GridOrTreeT& b)
939{
940 using Adapter = TreeAdapter<GridOrTreeT>;
941 using TreePtrT = typename Adapter::TreeType::Ptr;
942
943 TreePtrT output = composite::doCSGCopy<composite::CSG_INTERSECTION>(
944 Adapter::tree(a), Adapter::tree(b));
945
946 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
947}
948
949
950template<typename GridOrTreeT>
951typename GridOrTreeT::Ptr
952csgDifferenceCopy(const GridOrTreeT& a, const GridOrTreeT& b)
953{
954 using Adapter = TreeAdapter<GridOrTreeT>;
955 using TreePtrT = typename Adapter::TreeType::Ptr;
956
957 TreePtrT output = composite::doCSGCopy<composite::CSG_DIFFERENCE>(
958 Adapter::tree(a), Adapter::tree(b));
959
960 return composite::GridOrTreeConstructor<GridOrTreeT>::construct(a, output);
961}
962
963////////////////////////////////////////////////////////
964
965/// @brief Composite the active values in leaf nodes, i.e. active
966/// voxels, of a source tree into a destination tree.
967///
968/// @param srcTree source tree from which active voxels are composited.
969///
970/// @param dstTree destination tree into which active voxels are composited.
971///
972/// @param op a functor of the form <tt>void op(T& dst, const T& src)</tt>,
973/// where @c T is the @c ValueType of the tree, that composites
974/// a source value into a destination value. By default
975/// it copies the value from src to dst.
976///
977/// @details All active voxels in the source tree will
978/// be active in the destination tree, and their value is
979/// determined by a use-defined functor (OpT op) that operates on the
980/// source and destination values. The only exception is when
981/// the tree type is MaskTree, in which case no functor is
982/// needed since by defintion a MaskTree has no values (only topology).
983///
984/// @warning This function only operated on leaf node values,
985/// i.e. tile values are ignored.
986template<typename TreeT, typename OpT = composite::CopyOp<TreeT> >
987void
988compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op = composite::CopyOp<TreeT>())
989{
990 composite::doCompActiveLeafVoxels<TreeT, OpT>(srcTree, dstTree, op);
991}
992
993
994////////////////////////////////////////
995
996
997// Explicit Template Instantiation
998
999#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1000
1001#ifdef OPENVDB_INSTANTIATE_COMPOSITE
1002#include <openvdb/util/ExplicitInstantiation.h>
1003#endif
1004
1005#define _FUNCTION(TreeT) \
1006 void csgUnion(TreeT&, TreeT&, bool)
1007 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1008#undef _FUNCTION
1009
1010#define _FUNCTION(TreeT) \
1011 void csgUnion(Grid<TreeT>&, Grid<TreeT>&, bool)
1012 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1013#undef _FUNCTION
1014
1015#define _FUNCTION(TreeT) \
1016 void csgIntersection(TreeT&, TreeT&, bool)
1017 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1018#undef _FUNCTION
1019
1020#define _FUNCTION(TreeT) \
1021 void csgIntersection(Grid<TreeT>&, Grid<TreeT>&, bool)
1022 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1023#undef _FUNCTION
1024
1025#define _FUNCTION(TreeT) \
1026 void csgDifference(TreeT&, TreeT&, bool)
1027 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1028#undef _FUNCTION
1029
1030#define _FUNCTION(TreeT) \
1031 void csgDifference(Grid<TreeT>&, Grid<TreeT>&, bool)
1032 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1033#undef _FUNCTION
1034
1035#define _FUNCTION(TreeT) \
1036 TreeT::Ptr csgUnionCopy(const TreeT&, const TreeT&)
1037 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1038#undef _FUNCTION
1039
1040#define _FUNCTION(TreeT) \
1041 Grid<TreeT>::Ptr csgUnionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1042 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1043#undef _FUNCTION
1044
1045#define _FUNCTION(TreeT) \
1046 TreeT::Ptr csgIntersectionCopy(const TreeT&, const TreeT&)
1047 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1048#undef _FUNCTION
1049
1050#define _FUNCTION(TreeT) \
1051 Grid<TreeT>::Ptr csgIntersectionCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1052 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1053#undef _FUNCTION
1054
1055#define _FUNCTION(TreeT) \
1056 TreeT::Ptr csgDifferenceCopy(const TreeT&, const TreeT&)
1057 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1058#undef _FUNCTION
1059
1060#define _FUNCTION(TreeT) \
1061 Grid<TreeT>::Ptr csgDifferenceCopy(const Grid<TreeT>&, const Grid<TreeT>&)
1062 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
1063#undef _FUNCTION
1064
1065#define _FUNCTION(TreeT) \
1066 void compMax(TreeT&, TreeT&)
1067 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1068#undef _FUNCTION
1069
1070#define _FUNCTION(TreeT) \
1071 void compMax(Grid<TreeT>&, Grid<TreeT>&)
1072 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1073#undef _FUNCTION
1074
1075#define _FUNCTION(TreeT) \
1076 void compMin(TreeT&, TreeT&)
1077 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1078#undef _FUNCTION
1079
1080#define _FUNCTION(TreeT) \
1081 void compMin(Grid<TreeT>&, Grid<TreeT>&)
1082 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1083#undef _FUNCTION
1084
1085#define _FUNCTION(TreeT) \
1086 void compSum(TreeT&, TreeT&)
1087 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1088#undef _FUNCTION
1089
1090#define _FUNCTION(TreeT) \
1091 void compSum(Grid<TreeT>&, Grid<TreeT>&)
1092 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1093#undef _FUNCTION
1094
1095#define _FUNCTION(TreeT) \
1096 void compDiv(TreeT&, TreeT&)
1097 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1098#undef _FUNCTION
1099
1100#define _FUNCTION(TreeT) \
1101 void compDiv(Grid<TreeT>&, Grid<TreeT>&)
1102 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1103#undef _FUNCTION
1104
1105#define _FUNCTION(TreeT) \
1106 void compReplace(TreeT&, const TreeT&)
1107 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1108#undef _FUNCTION
1109
1110#define _FUNCTION(TreeT) \
1111 void compReplace(Grid<TreeT>&, const Grid<TreeT>&)
1112 OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION)
1113#undef _FUNCTION
1114
1115#endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
1116
1117
1118} // namespace tools
1119} // namespace OPENVDB_VERSION_NAME
1120} // namespace openvdb
1121
1122#endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED
ExplicitInstantiation.h
value
ValueT value
Definition: GridBuilder.h:1287
Grid.h
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Merge.h
Functions to efficiently merge grids.
Platform.h
Prune.h
Defined various multi-threaded utility functions for trees.
SignedFloodFill.h
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
ValueTransformer.h
openvdb::v9_0::CombineArgs
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:451
openvdb::v9_0::CombineArgs::b
const BValueType & b() const
Get the B input value.
Definition: Types.h:492
openvdb::v9_0::CombineArgs::a
const AValueType & a() const
Get the A input value.
Definition: Types.h:490
openvdb::v9_0::CombineArgs::setResult
CombineArgs & setResult(const AValueType &val)
Set the output value.
Definition: Types.h:500
openvdb::v9_0::Grid::Ptr
SharedPtr< Grid > Ptr
Definition: Grid.h:579
openvdb::v9_0::Steal
Tag dispatch class that distinguishes constructors that steal.
Definition: Types.h:568
openvdb::v9_0::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:248
openvdb::v9_0::tree::DynamicNodeManager
Definition: NodeManager.h:890
openvdb::v9_0::tree::DynamicNodeManager::foreachTopDown
void foreachTopDown(const NodeOp &op, bool threaded=true, size_t leafGrainSize=1, size_t nonLeafGrainSize=1)
Threaded method that applies a user-supplied functor to all the nodes in the tree.
Definition: NodeManager.h:976
openvdb::v9_0::tree::ValueAccessor< TreeT >
openvdb::v9_0::tree::ValueAccessor::setValue
void setValue(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active.
Definition: ValueAccessor.h:250
nanovdb::GridType
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
openvdb::v9_0::math::negative
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:127
openvdb::v9_0::tools::composite::max
const std::enable_if< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:121
openvdb::v9_0::tools::composite::min
const std::enable_if< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:113
openvdb::v9_0::tools::composite::divide
bool divide(bool a, bool)
Definition: Composite.h:145
openvdb::v9_0::tools::compDiv
void compDiv(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a / b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:807
openvdb::v9_0::tools::csgUnion
void csgUnion(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the union of A and B.
Definition: Composite.h:878
openvdb::v9_0::tools::compReplace
void compReplace(GridOrTreeT &a, const GridOrTreeT &b)
Copy the active voxels of B into A.
Definition: Composite.h:852
openvdb::v9_0::tools::csgDifference
void csgDifference(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the difference A / B.
Definition: Composite.h:908
openvdb::v9_0::tools::pruneLevelSet
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition: Prune.h:390
openvdb::v9_0::tools::compActiveLeafVoxels
void compActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op=composite::CopyOp< TreeT >())
Composite the active values in leaf nodes, i.e. active voxels, of a source tree into a destination tr...
Definition: Composite.h:988
openvdb::v9_0::tools::csgDifferenceCopy
GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG difference operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:952
openvdb::v9_0::tools::csgIntersection
void csgIntersection(GridOrTreeT &a, GridOrTreeT &b, bool prune=true)
Given two level set grids, replace the A grid with the intersection of A and B.
Definition: Composite.h:893
openvdb::v9_0::tools::prune
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition: Prune.h:335
openvdb::v9_0::tools::csgUnionCopy
GridOrTreeT::Ptr csgUnionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG union operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:924
openvdb::v9_0::tools::compSum
void compSum(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a + b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:777
openvdb::v9_0::tools::compMax
void compMax(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute max(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:745
openvdb::v9_0::tools::signedFloodFill
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:267
openvdb::v9_0::tools::compMul
void compMul(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute a * b per voxel (using sparse traversal). Store the result in the A grid...
Definition: Composite.h:792
openvdb::v9_0::tools::compMin
void compMin(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute min(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition: Composite.h:761
openvdb::v9_0::tools::csgIntersectionCopy
GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG intersection operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:938
openvdb::v9_0::Index
Index32 Index
Definition: Types.h:54
openvdb_houdini::Grid
openvdb::GridBase Grid
Definition: Utils.h:34
openvdb
Definition: Exceptions.h:13
Exceptions.h
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Types.h
openvdb.h
openvdb::v9_0::TreeAdapter
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1071
openvdb::v9_0::tools::CompReplaceOp
Definition: Composite.h:825
openvdb::v9_0::tools::CompReplaceOp::operator()
void operator()(const typename TreeT::LeafCIter &leafIter) const
Definition: Composite.h:838
openvdb::v9_0::tools::CompReplaceOp::aTree
TreeT *const aTree
Definition: Composite.h:826
openvdb::v9_0::tools::CompReplaceOp::operator()
void operator()(const typename TreeT::ValueOnCIter &iter) const
Definition: Composite.h:831
openvdb::v9_0::tools::CompReplaceOp::CompReplaceOp
CompReplaceOp(TreeT &_aTree)
Definition: Composite.h:828
openvdb::v9_0::tools::CsgDifferenceOp
DynamicNodeManager operator to merge two trees using a CSG difference.
Definition: Merge.h:263
openvdb::v9_0::tools::CsgUnionOrIntersectionOp
DynamicNodeManager operator to merge trees using a CSG union or intersection.
Definition: Merge.h:183
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
OPENVDB_REAL_TREE_INSTANTIATE
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147
OPENVDB_VOLUME_TREE_INSTANTIATE
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition: version.h.in:150