OpenVDB: openvdb/tools/Composite.h Source File

OpenVDB 10.0.1

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