HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Morphology.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2018 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
29 ///////////////////////////////////////////////////////////////////////////
30 //
31 /// @file Morphology.h
32 ///
33 /// @brief Implementation of morphological dilation and erosion.
34 ///
35 /// @note By design the morphological operations only change the
36 /// state of voxels, not their values. If one desires to
37 /// change the values of voxels that change state an efficient
38 /// technique is to construct a boolean mask by performing a
39 /// topology difference between the original and final grids.
40 ///
41 /// @todo Extend erosion with 18 and 26 neighbors (coming soon!)
42 ///
43 /// @author Ken Museth
44 ///
45 
46 #ifndef OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED
47 #define OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED
48 
49 #include <openvdb/Types.h>
50 #include <openvdb/Grid.h>
51 #include <openvdb/math/Math.h> // for isApproxEqual()
55 #include "Prune.h"// for pruneLevelSet
56 #include "ValueTransformer.h" // for foreach()
57 #include <tbb/tbb_thread.h>
58 #include <tbb/task_scheduler_init.h>
59 #include <tbb/enumerable_thread_specific.h>
60 #include <tbb/parallel_for.h>
61 #include <type_traits>
62 
63 
64 namespace openvdb {
66 namespace OPENVDB_VERSION_NAME {
67 namespace tools {
68 
69 /// @brief Voxel topology of nearest neighbors
70 /// @details
71 /// <dl>
72 /// <dt><b>NN_FACE</b>
73 /// <dd>face adjacency (6 nearest neighbors, defined as all neighbor
74 /// voxels connected along one of the primary axes)
75 ///
76 /// <dt><b>NN_FACE_EDGE</b>
77 /// <dd>face and edge adjacency (18 nearest neighbors, defined as all
78 /// neighbor voxels connected along either one or two of the primary axes)
79 ///
80 /// <dt><b>NN_FACE_EDGE_VERTEX</b>
81 /// <dd>face, edge and vertex adjacency (26 nearest neighbors, defined
82 /// as all neighbor voxels connected along either one, two or all
83 /// three of the primary axes)
84 /// </dl>
86 
87 /// @brief Different policies when dilating trees with active tiles
88 /// @details
89 /// <dl>
90 /// <dt><b>IGNORE_TILES</b>
91 /// <dd>Active tiles are ignores, i.e. only active voxels are dilates.
92 ///
93 /// <dt><b>EXPAND_TILES</b>
94 /// <dd>Active tiles are expanded into active voxels and then dilated.
95 ///
96 /// <dt><b>PRESERVE_TILES</b>
97 /// <dd>Active tiles remain unchanged but they still contribute to the
98 /// dilation as if they were active voxels.
99 /// </dl>
101 
102 /// @brief Topologically dilate all active values (i.e. both voxels
103 /// and tiles) in a tree using one of three nearest neighbor
104 /// connectivity patterns.
105 /// @note This method is fully multi-threaded and support active tiles!
106 ///
107 /// @param tree tree to be dilated
108 /// @param iterations number of iterations to apply the dilation
109 /// @param nn connectivity pattern of the dilation: either
110 /// face-adjacent (6 nearest neighbors), face- and edge-adjacent
111 /// (18 nearest neighbors) or face-, edge- and vertex-adjacent (26
112 /// nearest neighbors).
113 /// @param mode Defined the policy for handling active tiles
114 /// (see above for details)
115 ///
116 /// @note The values of any voxels are unchanged.
117 template<typename TreeType> OPENVDB_STATIC_SPECIALIZATION
118 inline void dilateActiveValues(TreeType& tree,
119  int iterations = 1,
122 
123 /// @brief Topologically dilate all active values (i.e. both voxels
124 /// and tiles) in a tree using one of three nearest neighbor
125 /// connectivity patterns.
126 ///
127 /// @warning Unlike the method above this one takes a LeafManger,
128 /// however (unlike dilateVoxels method below) it offers no performance
129 /// advantage over the one that takes a tree. Its merely included for
130 /// API compatability. The leaf nodes in the manger are updated
131 /// after the dilation, which incurres a (very small) overhead.
132 ///
133 /// @note This method is fully multi-threaded and support active tiles!
134 ///
135 /// @param manager Leaf node manager for the tree to be dilated.
136 /// On exit it is updated to include all the leaf
137 /// nodes of the dilated tree.
138 /// @param iterations number of iterations to apply the dilation
139 /// @param nn connectivity pattern of the dilation: either
140 /// face-adjacent (6 nearest neighbors), face- and edge-adjacent
141 /// (18 nearest neighbors) or face-, edge- and vertex-adjacent (26
142 /// nearest neighbors).
143 /// @param mode Defined the policy for handling active tiles
144 /// (see above for details)
145 ///
146 /// @note The values of any voxels are unchanged.
147 template<typename TreeType> OPENVDB_STATIC_SPECIALIZATION
149  int iterations = 1,
152 
153 
154 /// @brief Topologically dilate all leaf-level active voxels in a tree
155 /// using one of three nearest neighbor connectivity patterns.
156 /// @warning This method is NOT multi-threaded and ignores active tiles!
157 ///
158 /// @param tree tree to be dilated
159 /// @param iterations number of iterations to apply the dilation
160 /// @param nn connectivity pattern of the dilation: either
161 /// face-adjacent (6 nearest neighbors), face- and edge-adjacent
162 /// (18 nearest neighbors) or face-, edge- and vertex-adjacent (26
163 /// nearest neighbors).
164 ///
165 /// @note The values of any voxels are unchanged.
166 template<typename TreeType> OPENVDB_STATIC_SPECIALIZATION
167 inline void dilateVoxels(TreeType& tree,
168  int iterations = 1,
170 
171 /// @brief Topologically dilate all leaf-level active voxels in a tree
172 /// using one of three nearest neighbor connectivity patterns.
173 /// @warning This method is NOT multi-threaded and ignores active tiles!
174 ///
175 /// @param manager LeafManager containing the tree to be dilated.
176 /// On exit it is updated to include all the leaf
177 /// nodes of the dilated tree.
178 /// @param iterations number of iterations to apply the dilation
179 /// @param nn connectivity pattern of the dilation: either
180 /// face-adjacent (6 nearest neighbors), face- and edge-adjacent
181 /// (18 nearest neighbors) or face-, edge- and vertex-adjacent (26
182 /// nearest neighbors).
183 ///
184 /// @note The values of any voxels are unchanged.
185 template<typename TreeType> OPENVDB_STATIC_SPECIALIZATION
186 inline void dilateVoxels(tree::LeafManager<TreeType>& manager,
187  int iterations = 1,
189 
190 
191 //@{
192 /// @brief Topologically erode all leaf-level active voxels in the given tree.
193 /// @details That is, shrink the set of active voxels by @a iterations voxels
194 /// in the +x, -x, +y, -y, +z and -z directions, but don't change the values
195 /// of any voxels, only their active states.
196 /// @todo Currently operates only on leaf voxels; need to extend to tiles.
197 template<typename TreeType> OPENVDB_STATIC_SPECIALIZATION
198 inline void erodeVoxels(TreeType& tree,
199  int iterations=1,
201 
202 template<typename TreeType> OPENVDB_STATIC_SPECIALIZATION
203 inline void erodeVoxels(tree::LeafManager<TreeType>& manager,
204  int iterations = 1,
206 //@}
207 
208 
209 /// @brief Mark as active any inactive tiles or voxels in the given grid or tree
210 /// whose values are equal to @a value (optionally to within the given @a tolerance).
211 template<typename GridOrTree>
212 inline void activate(
213  GridOrTree&,
214  const typename GridOrTree::ValueType& value,
215  const typename GridOrTree::ValueType& tolerance = zeroVal<typename GridOrTree::ValueType>()
216 );
217 
218 
219 /// @brief Mark as inactive any active tiles or voxels in the given grid or tree
220 /// whose values are equal to @a value (optionally to within the given @a tolerance).
221 template<typename GridOrTree>
222 inline void deactivate(
223  GridOrTree&,
224  const typename GridOrTree::ValueType& value,
225  const typename GridOrTree::ValueType& tolerance = zeroVal<typename GridOrTree::ValueType>()
226 );
227 
228 
229 ////////////////////////////////////////
230 
231 
232 /// Mapping from a Log2Dim to a data type of size 2^Log2Dim bits
233 template<Index Log2Dim> struct DimToWord {};
234 template<> struct DimToWord<3> { typedef uint8_t Type; };
235 template<> struct DimToWord<4> { typedef uint16_t Type; };
236 template<> struct DimToWord<5> { typedef uint32_t Type; };
237 template<> struct DimToWord<6> { typedef uint64_t Type; };
238 
239 
240 ////////////////////////////////////////
241 
242 
243 template<typename TreeType>
245 {
246 public:
248 
249  Morphology(TreeType& tree):
250  mOwnsManager(true), mManager(new ManagerType(tree)), mAcc(tree), mSteps(1) {}
252  mOwnsManager(false), mManager(mgr), mAcc(mgr->tree()), mSteps(1) {}
253  virtual ~Morphology() { if (mOwnsManager) delete mManager; }
254 
255  /// @brief Face-adjacent dilation pattern
256  void dilateVoxels6();
257  /// @brief Face- and edge-adjacent dilation pattern.
258  void dilateVoxels18();
259  /// @brief Face-, edge- and vertex-adjacent dilation pattern.
260  void dilateVoxels26();
261  void dilateVoxels(int iterations = 1, NearestNeighbors nn = NN_FACE);
262 
263  /// @brief Face-adjacent erosion pattern.
264  void erodeVoxels6() { mSteps = 1; this->doErosion(NN_FACE); }
265  /// @brief Face- and edge-adjacent erosion pattern.
266  void erodeVoxels18() { mSteps = 1; this->doErosion(NN_FACE_EDGE); }
267  /// @brief Face-, edge- and vertex-adjacent erosion pattern.
269  void erodeVoxels(int iterations = 1, NearestNeighbors nn = NN_FACE)
270  {
271  mSteps = iterations;
272  this->doErosion(nn);
273  }
274 
275 protected:
276 
277  void doErosion(NearestNeighbors nn);
278 
279  typedef typename TreeType::LeafNodeType LeafType;
280  typedef typename LeafType::NodeMaskType MaskType;
282 
283  const bool mOwnsManager;
286  int mSteps;
287 
288  static const int LEAF_DIM = LeafType::DIM;
289  static const int END = LEAF_DIM - 1;
290  static const int LEAF_LOG2DIM = LeafType::LOG2DIM;
292 
293  struct Neighbor {
294  LeafType* leaf;//null if a tile
295  bool init;//true if initialization is required
296  bool isOn;//true if an active tile
297  Neighbor() : leaf(nullptr), init(true) {}
298  inline void clear() { leaf = nullptr; init = true; }
299  template<int DX, int DY, int DZ>
300  void scatter(AccessorType& acc, const Coord &xyz, int indx, Word mask)
301  {
302  if (init) {
303  init = false;
304  Coord orig = xyz.offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
305  leaf = acc.probeLeaf(orig);
306  if ((leaf == nullptr) && !acc.isValueOn(orig)) leaf = acc.touchLeaf(orig);
307  }
308 #ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics
309  static
310 #endif
311  const int N = (LEAF_DIM - 1)*(DY + DX*LEAF_DIM);
312  if (leaf) leaf->getValueMask().template getWord<Word>(indx-N) |= mask;
313  }
314 
315  template<int DX, int DY, int DZ>
316  Word gather(AccessorType& acc, const Coord &xyz, int indx)
317  {
318  if (init) {
319  init = false;
320  Coord orig = xyz.offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
321  leaf = acc.probeLeaf(orig);
322  isOn = leaf ? false : acc.isValueOn(orig);
323  }
324 #ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics
325  static
326 #endif
327  const int N = (LEAF_DIM -1 )*(DY + DX*LEAF_DIM);
328  return leaf ? leaf->getValueMask().template getWord<Word>(indx-N)
329  : isOn ? ~Word(0) : Word(0);
330  }
331  };// Neighbor
332 
333  struct LeafCache
334  {
335  LeafCache(size_t n, TreeType& tree) : size(n), leafs(new LeafType*[n]), acc(tree)
336  {
337  onTile.setValuesOn();
338  this->clear();
339  }
340  ~LeafCache() { delete [] leafs; }
341  LeafType*& operator[](int offset) { return leafs[offset]; }
342  inline void clear() { for (size_t i = 0; i < size; ++i) leafs[i] = nullptr; }
343  inline void setOrigin(const Coord& xyz) { origin = &xyz; }
344  inline void scatter(int n, int indx)
345  {
346  assert(leafs[n]);
347  leafs[n]->getValueMask().template getWord<Word>(indx) |= mask;
348  }
349  template<int DX, int DY, int DZ>
350  inline void scatter(int n, int indx)
351  {
352  if (!leafs[n]) {
353  const Coord xyz = origin->offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
354  leafs[n] = acc.probeLeaf(xyz);
355  if (!leafs[n]) leafs[n] = acc.isValueOn(xyz) ? &onTile : acc.touchLeaf(xyz);
356  }
357  this->scatter(n, indx - (LEAF_DIM - 1)*(DY + DX*LEAF_DIM));
358  }
359  inline Word gather(int n, int indx)
360  {
361  assert(leafs[n]);
362  return leafs[n]->getValueMask().template getWord<Word>(indx);
363  }
364  template<int DX, int DY, int DZ>
365  inline Word gather(int n, int indx)
366  {
367  if (!leafs[n]) {
368  const Coord xyz = origin->offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM);
369  leafs[n] = acc.probeLeaf(xyz);
370  if (!leafs[n]) leafs[n] = acc.isValueOn(xyz) ? &onTile : &offTile;
371  }
372  return this->gather(n, indx - (LEAF_DIM -1 )*(DY + DX*LEAF_DIM));
373  }
374  // Scatters in the xy face-directions relative to leaf i1
375  void scatterFacesXY(int x, int y, int i1, int n, int i2);
376 
377  // Scatters in the xy edge-directions relative to leaf i1
378  void scatterEdgesXY(int x, int y, int i1, int n, int i2);
379 
380  Word gatherFacesXY(int x, int y, int i1, int n, int i2);
381 
382  Word gatherEdgesXY(int x, int y, int i1, int n, int i2);
383 
384  const Coord* origin;
385  size_t size;
390  };// LeafCache
391 
392  struct ErodeVoxelsOp {
393  typedef tbb::blocked_range<size_t> RangeT;
394  ErodeVoxelsOp(std::vector<MaskType>& masks, ManagerType& manager)
395  : mTask(0), mSavedMasks(masks) , mManager(manager) {}
396  void runParallel(NearestNeighbors nn);
397  void operator()(const RangeT& r) const {mTask(const_cast<ErodeVoxelsOp*>(this), r);}
398  void erode6( const RangeT&) const;
399  void erode18(const RangeT&) const;
400  void erode26(const RangeT&) const;
401  private:
402  using FuncT = typename std::function<void (ErodeVoxelsOp*, const RangeT&)>;
403  FuncT mTask;
404  std::vector<MaskType>& mSavedMasks;
405  ManagerType& mManager;
406  };// ErodeVoxelsOp
407 
408  struct MaskManager {
409  MaskManager(std::vector<MaskType>& masks, ManagerType& manager)
410  : mMasks(masks) , mManager(manager), mSaveMasks(true) {}
411 
412  void save() { mSaveMasks = true; tbb::parallel_for(mManager.getRange(), *this); }
413  void update() { mSaveMasks = false; tbb::parallel_for(mManager.getRange(), *this); }
414  void operator()(const tbb::blocked_range<size_t>& range) const
415  {
416  if (mSaveMasks) {
417  for (size_t i = range.begin(); i < range.end(); ++i) {
418  mMasks[i] = mManager.leaf(i).getValueMask();
419  }
420  } else {
421  for (size_t i = range.begin(); i < range.end(); ++i) {
422  mManager.leaf(i).setValueMask(mMasks[i]);
423  }
424  }
425  }
426  private:
427  std::vector<MaskType>& mMasks;
428  ManagerType& mManager;
429  bool mSaveMasks;
430  };// MaskManager
431 
432  struct UpdateMasks {
433  UpdateMasks(const std::vector<MaskType>& masks, ManagerType& manager)
434  : mMasks(masks), mManager(manager) {}
435  void update() { tbb::parallel_for(mManager.getRange(), *this); }
436  void operator()(const tbb::blocked_range<size_t>& r) const {
437  for (size_t i=r.begin(); i<r.end(); ++i) mManager.leaf(i).setValueMask(mMasks[i]);
438  }
439  const std::vector<MaskType>& mMasks;
441  };
442  struct CopyMasks {
443  CopyMasks(std::vector<MaskType>& masks, const ManagerType& manager)
444  : mMasks(masks), mManager(manager) {}
445  void copy() { tbb::parallel_for(mManager.getRange(), *this); }
446  void operator()(const tbb::blocked_range<size_t>& r) const {
447  for (size_t i=r.begin(); i<r.end(); ++i) mMasks[i]=mManager.leaf(i).getValueMask();
448  }
449  std::vector<MaskType>& mMasks;
451  };
452  void copyMasks(std::vector<MaskType>& a, const ManagerType& b) {CopyMasks c(a, b); c.copy();}
453 };// Morphology
454 
455 
456 template<typename TreeType>
457 inline void
459 {
460  for (int i=0; i<iterations; ++i) {
461  switch (nn) {
462  case NN_FACE_EDGE:
463  this->dilateVoxels18();
464  break;
465  case NN_FACE_EDGE_VERTEX:
466  this->dilateVoxels26();
467  break;
468  case NN_FACE:
469  default:
470  this->dilateVoxels6();
471  }
472  }
473 }
474 
475 
476 template<typename TreeType>
477 inline void
479 {
480  /// @todo Currently operates only on leaf voxels; need to extend to tiles.
481  const int leafCount = static_cast<int>(mManager->leafCount());
482 
483  // Save the value masks of all leaf nodes.
484  std::vector<MaskType> savedMasks(leafCount);
485  this->copyMasks(savedMasks, *mManager);
486  LeafCache cache(7, mManager->tree());
487  for (int leafIdx = 0; leafIdx < leafCount; ++leafIdx) {
488  const MaskType& oldMask = savedMasks[leafIdx];//original bit-mask of current leaf node
489  cache[0] = &mManager->leaf(leafIdx);
490  cache.setOrigin(cache[0]->origin());
491  for (int x = 0; x < LEAF_DIM; ++x ) {
492  for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
493  // Extract the portion of the original mask that corresponds to a row in z.
494  if (const Word w = oldMask.template getWord<Word>(n)) {
495 
496  // Dilate the current leaf in the +z and -z direction
497  cache.mask = Word(w | (w>>1) | (w<<1)); cache.scatter(0, n);
498 
499  // Dilate into neighbor leaf in the -z direction
500  if ( (cache.mask = Word(w<<(LEAF_DIM-1))) ) {
501  cache.template scatter< 0, 0,-1>(1, n);
502  }
503  // Dilate into neighbor leaf in the +z direction
504  if ( (cache.mask = Word(w>>(LEAF_DIM-1))) ) {
505  cache.template scatter< 0, 0, 1>(2, n);
506  }
507  // Dilate in the xy-face directions relative to the center leaf
508  cache.mask = w; cache.scatterFacesXY(x, y, 0, n, 3);
509  }
510  }// loop over y
511  }//loop over x
512  cache.clear();
513  }//loop over leafs
514 
515  mManager->rebuildLeafArray();
516 }//dilateVoxels6
517 
518 
519 template<typename TreeType>
520 inline void
522 {
523  /// @todo Currently operates only on leaf voxels; need to extend to tiles.
524  const int leafCount = static_cast<int>(mManager->leafCount());
525 
526  // Save the value masks of all leaf nodes.
527  std::vector<MaskType> savedMasks(leafCount);
528  this->copyMasks(savedMasks, *mManager);
529  LeafCache cache(19, mManager->tree());
530  Coord orig_mz, orig_pz;//origins of neighbor leaf nodes in the -z and +z directions
531  for (int leafIdx = 0; leafIdx < leafCount; ++leafIdx) {
532  const MaskType& oldMask = savedMasks[leafIdx];//original bit-mask of current leaf node
533  cache[0] = &mManager->leaf(leafIdx);
534  orig_mz = cache[0]->origin().offsetBy(0, 0, -LEAF_DIM);
535  orig_pz = cache[0]->origin().offsetBy(0, 0, LEAF_DIM);
536  for (int x = 0; x < LEAF_DIM; ++x ) {
537  for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
538  if (const Word w = oldMask.template getWord<Word>(n)) {
539  {
540  cache.mask = Word(w | (w>>1) | (w<<1));
541  cache.setOrigin(cache[0]->origin());
542  cache.scatter(0, n);
543  cache.scatterFacesXY(x, y, 0, n, 3);
544  cache.mask = w;
545  cache.scatterEdgesXY(x, y, 0, n, 3);
546  }
547  if ( (cache.mask = Word(w<<(LEAF_DIM-1))) ) {
548  cache.setOrigin(cache[0]->origin());
549  cache.template scatter< 0, 0,-1>(1, n);
550  cache.setOrigin(orig_mz);
551  cache.scatterFacesXY(x, y, 1, n, 11);
552  }
553  if ( (cache.mask = Word(w>>(LEAF_DIM-1))) ) {
554  cache.setOrigin(cache[0]->origin());
555  cache.template scatter< 0, 0, 1>(2, n);
556  cache.setOrigin(orig_pz);
557  cache.scatterFacesXY(x, y, 2, n, 15);
558  }
559  }
560  }// loop over y
561  }//loop over x
562  cache.clear();
563  }//loop over leafs
564 
565  mManager->rebuildLeafArray();
566 }// dilateVoxels18
567 
568 
569 template<typename TreeType>
570 inline void
572 {
573  const int leafCount = static_cast<int>(mManager->leafCount());
574 
575  // Save the value masks of all leaf nodes.
576  std::vector<MaskType> savedMasks(leafCount);
577  this->copyMasks(savedMasks, *mManager);
578  LeafCache cache(27, mManager->tree());
579  Coord orig_mz, orig_pz;//origins of neighbor leaf nodes in the -z and +z directions
580  for (int leafIdx = 0; leafIdx < leafCount; ++leafIdx) {
581  const MaskType& oldMask = savedMasks[leafIdx];//original bit-mask of current leaf node
582  cache[0] = &mManager->leaf(leafIdx);
583  orig_mz = cache[0]->origin().offsetBy(0, 0, -LEAF_DIM);
584  orig_pz = cache[0]->origin().offsetBy(0, 0, LEAF_DIM);
585  for (int x = 0; x < LEAF_DIM; ++x ) {
586  for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
587  if (const Word w = oldMask.template getWord<Word>(n)) {
588  {
589  cache.mask = Word(w | (w>>1) | (w<<1));
590  cache.setOrigin(cache[0]->origin());
591  cache.scatter(0, n);
592  cache.scatterFacesXY(x, y, 0, n, 3);
593  cache.scatterEdgesXY(x, y, 0, n, 3);
594  }
595  if ( (cache.mask = Word(w<<(LEAF_DIM-1))) ) {
596  cache.setOrigin(cache[0]->origin());
597  cache.template scatter< 0, 0,-1>(1, n);
598  cache.setOrigin(orig_mz);
599  cache.scatterFacesXY(x, y, 1, n, 11);
600  cache.scatterEdgesXY(x, y, 1, n, 11);
601  }
602  if ( (cache.mask = Word(w>>(LEAF_DIM-1))) ) {
603  cache.setOrigin(cache[0]->origin());
604  cache.template scatter< 0, 0, 1>(2, n);
605  cache.setOrigin(orig_pz);
606  cache.scatterFacesXY(x, y, 2, n, 19);
607  cache.scatterEdgesXY(x, y, 2, n, 19);
608  }
609  }
610  }// loop over y
611  }//loop over x
612  cache.clear();
613  }//loop over leafs
614 
615  mManager->rebuildLeafArray();
616 }// dilateVoxels26
617 
618 
619 template<typename TreeType>
620 inline void
621 Morphology<TreeType>::LeafCache::scatterFacesXY(int x, int y, int i1, int n, int i2)
622 {
623  // dilate current leaf or neighbor in the -x direction
624  if (x > 0) {
625  this->scatter(i1, n-LEAF_DIM);
626  } else {
627  this->template scatter<-1, 0, 0>(i2, n);
628  }
629  // dilate current leaf or neighbor in the +x direction
630  if (x < LEAF_DIM-1) {
631  this->scatter(i1, n+LEAF_DIM);
632  } else {
633  this->template scatter< 1, 0, 0>(i2+1, n);
634  }
635  // dilate current leaf or neighbor in the -y direction
636  if (y > 0) {
637  this->scatter(i1, n-1);
638  } else {
639  this->template scatter< 0,-1, 0>(i2+2, n);
640  }
641  // dilate current leaf or neighbor in the +y direction
642  if (y < LEAF_DIM-1) {
643  this->scatter(i1, n+1);
644  } else {
645  this->template scatter< 0, 1, 0>(i2+3, n);
646  }
647 }
648 
649 
650 template<typename TreeType>
651 inline void
652 Morphology<TreeType>::LeafCache::scatterEdgesXY(int x, int y, int i1, int n, int i2)
653 {
654  if (x > 0) {
655  if (y > 0) {
656  this->scatter(i1, n-LEAF_DIM-1);
657  } else {
658  this->template scatter< 0,-1, 0>(i2+2, n-LEAF_DIM);
659  }
660  if (y < LEAF_DIM-1) {
661  this->scatter(i1, n-LEAF_DIM+1);
662  } else {
663  this->template scatter< 0, 1, 0>(i2+3, n-LEAF_DIM);
664  }
665  } else {
666  if (y < LEAF_DIM-1) {
667  this->template scatter<-1, 0, 0>(i2 , n+1);
668  } else {
669  this->template scatter<-1, 1, 0>(i2+7, n );
670  }
671  if (y > 0) {
672  this->template scatter<-1, 0, 0>(i2 , n-1);
673  } else {
674  this->template scatter<-1,-1, 0>(i2+4, n );
675  }
676  }
677  if (x < LEAF_DIM-1) {
678  if (y > 0) {
679  this->scatter(i1, n+LEAF_DIM-1);
680  } else {
681  this->template scatter< 0,-1, 0>(i2+2, n+LEAF_DIM);
682  }
683  if (y < LEAF_DIM-1) {
684  this->scatter(i1, n+LEAF_DIM+1);
685  } else {
686  this->template scatter< 0, 1, 0>(i2+3, n+LEAF_DIM);
687  }
688  } else {
689  if (y > 0) {
690  this->template scatter< 1, 0, 0>(i2+1, n-1);
691  } else {
692  this->template scatter< 1,-1, 0>(i2+6, n );
693  }
694  if (y < LEAF_DIM-1) {
695  this->template scatter< 1, 0, 0>(i2+1, n+1);
696  } else {
697  this->template scatter< 1, 1, 0>(i2+5, n );
698  }
699  }
700 }
701 
702 
703 template<typename TreeType>
704 inline void
706 {
707  namespace ph = std::placeholders;
708  switch (nn) {
709  case NN_FACE_EDGE:
710  mTask = std::bind(&ErodeVoxelsOp::erode18, ph::_1, ph::_2);
711  break;
712  case NN_FACE_EDGE_VERTEX:
713  mTask = std::bind(&ErodeVoxelsOp::erode26, ph::_1, ph::_2);
714  break;
715  case NN_FACE:
716  default:
717  mTask = std::bind(&ErodeVoxelsOp::erode6, ph::_1, ph::_2);
718  }
719  tbb::parallel_for(mManager.getRange(), *this);
720 }
721 
722 
723 template<typename TreeType>
724 inline typename Morphology<TreeType>::Word
725 Morphology<TreeType>::LeafCache::gatherFacesXY(int x, int y, int i1, int n, int i2)
726 {
727  // erode current leaf or neighbor in negative x-direction
728  Word w = x>0 ? this->gather(i1,n-LEAF_DIM) : this->template gather<-1,0,0>(i2, n);
729 
730  // erode current leaf or neighbor in positive x-direction
731  w = Word(w & (x<LEAF_DIM-1?this->gather(i1,n+LEAF_DIM):this->template gather<1,0,0>(i2+1,n)));
732 
733  // erode current leaf or neighbor in negative y-direction
734  w = Word(w & (y>0 ? this->gather(i1, n-1) : this->template gather<0,-1,0>(i2+2, n)));
735 
736  // erode current leaf or neighbor in positive y-direction
737  w = Word(w & (y<LEAF_DIM-1 ? this->gather(i1, n+1) : this->template gather<0,1,0>(i2+3, n)));
738 
739  return w;
740 }
741 
742 
743 template<typename TreeType>
744 inline typename Morphology<TreeType>::Word
745 Morphology<TreeType>::LeafCache::gatherEdgesXY(int x, int y, int i1, int n, int i2)
746 {
747  Word w = ~Word(0);
748 
749  if (x > 0) {
750  w &= y > 0 ? this->gather(i1, n-LEAF_DIM-1) :
751  this->template gather< 0,-1, 0>(i2+2, n-LEAF_DIM);
752  w &= y < LEAF_DIM-1 ? this->gather(i1, n-LEAF_DIM+1) :
753  this->template gather< 0, 1, 0>(i2+3, n-LEAF_DIM);
754  } else {
755  w &= y < LEAF_DIM-1 ? this->template gather<-1, 0, 0>(i2 , n+1):
756  this->template gather<-1, 1, 0>(i2+7, n );
757  w &= y > 0 ? this->template gather<-1, 0, 0>(i2 , n-1):
758  this->template gather<-1,-1, 0>(i2+4, n );
759  }
760  if (x < LEAF_DIM-1) {
761  w &= y > 0 ? this->gather(i1, n+LEAF_DIM-1) :
762  this->template gather< 0,-1, 0>(i2+2, n+LEAF_DIM);
763  w &= y < LEAF_DIM-1 ? this->gather(i1, n+LEAF_DIM+1) :
764  this->template gather< 0, 1, 0>(i2+3, n+LEAF_DIM);
765  } else {
766  w &= y > 0 ? this->template gather< 1, 0, 0>(i2+1, n-1):
767  this->template gather< 1,-1, 0>(i2+6, n );
768  w &= y < LEAF_DIM-1 ? this->template gather< 1, 0, 0>(i2+1, n+1):
769  this->template gather< 1, 1, 0>(i2+5, n );
770  }
771 
772  return w;
773 }
774 
775 
776 template <typename TreeType>
777 inline void
779 {
780  LeafCache cache(7, mManager.tree());
781  for (size_t leafIdx = range.begin(); leafIdx < range.end(); ++leafIdx) {
782  cache[0] = &mManager.leaf(leafIdx);
783  if (cache[0]->isEmpty()) continue;
784  cache.setOrigin(cache[0]->origin());
785  MaskType& newMask = mSavedMasks[leafIdx];//original bit-mask of current leaf node
786  for (int x = 0; x < LEAF_DIM; ++x ) {
787  for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) {
788  // Extract the portion of the original mask that corresponds to a row in z.
789  if (Word& w = newMask.template getWord<Word>(n)) {
790 
791  // erode in two z directions (this is first since it uses the original w)
792  w = Word(w &
793  (Word(w<<1 | (cache.template gather<0,0,-1>(1, n)>>(LEAF_DIM-1))) &
794  Word(w>>1 | (cache.template gather<0,0, 1>(2, n)<<(LEAF_DIM-1)))));
795 
796  w = Word(w & cache.gatherFacesXY(x, y, 0, n, 3));
797  }
798  }// loop over y
799  }//loop over x
800  cache.clear();
801  }//loop over leafs
802 }
803 
804 
805 template <typename TreeType>
806 inline void
808 {
809  OPENVDB_THROW(NotImplementedError, "tools::erode18 is not implemented yet!");
810 }
811 
812 
813 template <typename TreeType>
814 inline void
816 {
817  OPENVDB_THROW(NotImplementedError, "tools::erode26 is not implemented yet!");
818 }
819 
820 
821 template<typename TreeType>
822 inline void
824 {
825  /// @todo Currently operates only on leaf voxels; need to extend to tiles.
826  const size_t leafCount = mManager->leafCount();
827 
828  // Save the value masks of all leaf nodes.
829  std::vector<MaskType> savedMasks(leafCount);
830  this->copyMasks(savedMasks, *mManager);
831  UpdateMasks a(savedMasks, *mManager);
832  ErodeVoxelsOp erode(savedMasks, *mManager);
833 
834  for (int i = 0; i < mSteps; ++i) {
835  erode.runParallel(nn);
836  a.update();
837  }
838 
840 }
841 
842 
843 ////////////////////////////////////////
844 
845 
846 template<typename TreeType>
849 {
850  if (iterations > 0 ) {
851  Morphology<TreeType> m(&manager);
852  m.dilateVoxels(iterations, nn);
853  }
854 }
855 
856 template<typename TreeType>
858 dilateVoxels(TreeType& tree, int iterations, NearestNeighbors nn)
859 {
860  if (iterations > 0 ) {
861  Morphology<TreeType> m(tree);
862  m.dilateVoxels(iterations, nn);
863  }
864 }
865 
866 template<typename TreeType>
869 {
870  if (iterations > 0 ) {
871  Morphology<TreeType> m(&manager);
872  m.erodeVoxels(iterations, nn);
873  }
874 }
875 
876 template<typename TreeType>
878 erodeVoxels(TreeType& tree, int iterations, NearestNeighbors nn)
879 {
880  if (iterations > 0 ) {
881  Morphology<TreeType> m(tree);
882  m.erodeVoxels(iterations, nn);
883  }
884 }
885 
886 
887 ////////////////////////////////////////
888 
889 
890 namespace activation {
891 
892 template<typename TreeType>
894 {
895 public:
896  typedef typename TreeType::ValueType ValueT;
897 
898  ActivationOp(bool state, const ValueT& val, const ValueT& tol)
899  : mActivate(state)
900  , mValue(val)
901  , mTolerance(tol)
902  {}
903 
904  void operator()(const typename TreeType::ValueOnIter& it) const
905  {
906  if (math::isApproxEqual(*it, mValue, mTolerance)) {
907  it.setValueOff();
908  }
909  }
910 
911  void operator()(const typename TreeType::ValueOffIter& it) const
912  {
913  if (math::isApproxEqual(*it, mValue, mTolerance)) {
914  it.setActiveState(/*on=*/true);
915  }
916  }
917 
918  void operator()(const typename TreeType::LeafIter& lit) const
919  {
920  typedef typename TreeType::LeafNodeType LeafT;
921  LeafT& leaf = *lit;
922  if (mActivate) {
923  for (typename LeafT::ValueOffIter it = leaf.beginValueOff(); it; ++it) {
924  if (math::isApproxEqual(*it, mValue, mTolerance)) {
925  leaf.setValueOn(it.pos());
926  }
927  }
928  } else {
929  for (typename LeafT::ValueOnIter it = leaf.beginValueOn(); it; ++it) {
930  if (math::isApproxEqual(*it, mValue, mTolerance)) {
931  leaf.setValueOff(it.pos());
932  }
933  }
934  }
935  }
936 
937 private:
938  bool mActivate;
939  const ValueT mValue, mTolerance;
940 }; // class ActivationOp
941 
942 } // namespace activation
943 
944 
945 template<typename GridOrTree>
946 inline void
947 activate(GridOrTree& gridOrTree, const typename GridOrTree::ValueType& value,
948  const typename GridOrTree::ValueType& tolerance)
949 {
950  typedef TreeAdapter<GridOrTree> Adapter;
951  typedef typename Adapter::TreeType TreeType;
952 
953  TreeType& tree = Adapter::tree(gridOrTree);
954 
955  activation::ActivationOp<TreeType> op(/*activate=*/true, value, tolerance);
956 
957  // Process all leaf nodes in parallel.
958  foreach(tree.beginLeaf(), op);
959 
960  // Process all other inactive values serially (because changing active states
961  // is not thread-safe unless no two threads modify the same node).
962  typename TreeType::ValueOffIter it = tree.beginValueOff();
963  it.setMaxDepth(tree.treeDepth() - 2);
964  foreach(it, op, /*threaded=*/false);
965 }
966 
967 
968 template<typename GridOrTree>
969 inline void
970 deactivate(GridOrTree& gridOrTree, const typename GridOrTree::ValueType& value,
971  const typename GridOrTree::ValueType& tolerance)
972 {
973  typedef TreeAdapter<GridOrTree> Adapter;
974  typedef typename Adapter::TreeType TreeType;
975 
976  TreeType& tree = Adapter::tree(gridOrTree);
977 
978  activation::ActivationOp<TreeType> op(/*activate=*/false, value, tolerance);
979 
980  // Process all leaf nodes in parallel.
981  foreach(tree.beginLeaf(), op);
982 
983  // Process all other active values serially (because changing active states
984  // is not thread-safe unless no two threads modify the same node).
985  typename TreeType::ValueOnIter it = tree.beginValueOn();
986  it.setMaxDepth(tree.treeDepth() - 2);
987  foreach(it, op, /*threaded=*/false);
988 }
989 
990 /// @brief Class that performs multi-threaded dilation with support for active tiles.
991 /// @warning Dont use this class directly, instead call the function dilateActiveValues!
992 template<typename TreeT>
994 {
995  typedef typename TreeT::template ValueConverter<ValueMask>::Type MaskT;
996  typedef tbb::enumerable_thread_specific<MaskT> PoolT;
997  typedef typename MaskT::LeafNodeType LeafT;
998 
999  // Very light-weight member data
1000  const int mIter;// number of iterations
1001  const tools::NearestNeighbors mNN;//enum to specify the dilation scheme
1002  PoolT *mPool;// pointer to the thread-local pool of mask trees
1003  LeafT **mLeafs;// raw array of pointers to leaf nodes
1004 
1005 public:
1006 
1007  DilationOp(TreeT &tree, int iterations, NearestNeighbors nn, TilePolicy mode)
1008  : mIter(iterations), mNN(nn), mPool(nullptr), mLeafs(nullptr)
1009  {
1010  const size_t numLeafs = this->init( tree, mode );
1011  const size_t numThreads = size_t(tbb::task_scheduler_init::default_num_threads());
1012  const size_t grainSize = math::Max(size_t(1), numLeafs/(2*numThreads));
1013 
1014  MaskT mask;
1015  PoolT pool(mask);// Scoped thread-local storage of mask trees
1016  mPool = &pool;
1017 
1018  tbb::parallel_for(tbb::blocked_range<LeafT**>(mLeafs, mLeafs+numLeafs, grainSize), *this);
1019 
1020  delete [] mLeafs;// no more need for the array of leaf node pointers
1021 
1022  typedef typename PoolT::iterator IterT;
1023  for (IterT it=pool.begin(); it!=pool.end(); ++it) mask.merge(*it);// fast stealing
1024 
1025  if (mode == PRESERVE_TILES) tools::prune(mask);//multithreaded
1026 
1027  tree.topologyUnion(mask);//multithreaded
1028  }
1029 
1030  // This is required by tbb and should never be called directly
1031  void operator()(const tbb::blocked_range<LeafT**> &r) const
1032  {
1033  MaskT mask;// thread-local temporary mask tree
1034  for (LeafT** it=r.begin(); it!=r.end(); ++it) mask.addLeaf( *it );
1035  tree::LeafManager<MaskT> manager(mask, r.begin(), r.end());
1036  tools::dilateVoxels(manager, mIter, mNN);// serial dilation of active voxels
1037  mPool->local().merge(mask, MERGE_ACTIVE_STATES);
1038  }
1039 private:
1040 
1041  // Simple wrapper of a raw double-pointer to mimic a std container
1042  struct MyArray {
1043  typedef LeafT* value_type;//required by Tree::stealNodes
1044  value_type* ptr;
1045  MyArray(value_type* array) : ptr(array) {}
1046  void push_back(value_type leaf) { *ptr++ = leaf; }//required by Tree::stealNodes
1047  };
1048 
1049  // Convert active tiles to leafs and de-construct the tree into a linear array of leafs.
1050  size_t linearize(MaskT& mask, TilePolicy mode)
1051  {
1052  if (mode != IGNORE_TILES) mask.voxelizeActiveTiles();//lightweight since this is a mask tree
1053  const size_t numLeafs = mask.leafCount();
1054  mLeafs = new LeafT*[numLeafs];// fast pre-allocation
1055  MyArray tmp(mLeafs);
1056  mask.stealNodes(tmp);// serializes the mask tree and leaves it empty
1057  return numLeafs;
1058  }
1059 
1060  template<typename T>
1062  init(T& tree, TilePolicy mode)
1063  {
1064  return this->linearize(tree, mode);
1065  }
1066 
1067  template<typename T>
1069  init(const T& tree, TilePolicy mode)
1070  {
1071  MaskT mask(tree, false, true, TopologyCopy());
1072  return this->linearize(mask, mode);
1073  }
1074 
1075 };// DilationOp
1076 
1077 template<typename TreeType>
1079 dilateActiveValues(TreeType& tree, int iterations, NearestNeighbors nn, TilePolicy mode)
1080 {
1081  if (iterations > 0 ) DilationOp<TreeType> tmp(tree, iterations, nn, mode);
1082 }
1083 
1084 template<typename TreeType>
1087  int iterations,
1088  NearestNeighbors nn,
1089  TilePolicy mode)
1090 {
1091  if (iterations > 0 ) {
1092  DilationOp<TreeType> tmp(manager.tree(), iterations, nn, mode);
1093  manager.rebuildLeafArray();
1094  }
1095 }
1096 
1097 } // namespace tools
1098 } // namespace OPENVDB_VERSION_NAME
1099 } // namespace openvdb
1100 
1101 #endif // OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED
1102 
1103 // Copyright (c) 2012-2018 DreamWorks Animation LLC
1104 // All rights reserved. This software is distributed under the
1105 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
void erodeVoxels6()
Face-adjacent erosion pattern.
Definition: Morphology.h:264
void dilateVoxels26()
Face-, edge- and vertex-adjacent dilation pattern.
Definition: Morphology.h:571
GLenum GLint * range
Definition: glcorearb.h:1924
#define OPENVDB_STATIC_SPECIALIZATION
Macro for determining if there are sufficient C++0x/C++11 features.
Definition: Platform.h:91
Class that performs multi-threaded dilation with support for active tiles.
Definition: Morphology.h:993
png_voidp ptr
Definition: png.h:2145
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition: LeafManager.h:343
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1221
GLint GLuint mask
Definition: glcorearb.h:123
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:189
GLint y
Definition: glcorearb.h:102
void dilateVoxels18()
Face- and edge-adjacent dilation pattern.
Definition: Morphology.h:521
void operator()(const tbb::blocked_range< LeafT ** > &r) const
Definition: Morphology.h:1031
png_uint_32 i
Definition: png.h:2877
uint64 value_type
Definition: GA_PrimCompat.h:29
GLsizeiptr size
Definition: glcorearb.h:663
DilationOp(TreeT &tree, int iterations, NearestNeighbors nn, TilePolicy mode)
Definition: Morphology.h:1007
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:944
void erodeVoxels26()
Face-, edge- and vertex-adjacent erosion pattern.
Definition: Morphology.h:268
size_t leafCount() const
Return the number of leaf nodes.
Definition: LeafManager.h:328
GLdouble n
Definition: glcorearb.h:2007
NearestNeighbors
Voxel topology of nearest neighbors.
Definition: Morphology.h:85
Word gatherEdgesXY(int x, int y, int i1, int n, int i2)
Definition: Morphology.h:745
tree::LeafManager< TreeType > ManagerType
Definition: Morphology.h:247
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Word gatherFacesXY(int x, int y, int i1, int n, int i2)
Definition: Morphology.h:725
tree::ValueAccessor< TreeType > AccessorType
Definition: Morphology.h:281
GLintptr offset
Definition: glcorearb.h:664
void erodeVoxels(int iterations=1, NearestNeighbors nn=NN_FACE)
Definition: Morphology.h:269
Defined various multi-threaded utility functions for trees.
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one, but preserve the values and active states of all voxels.
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
void operator()(const tbb::blocked_range< size_t > &range) const
Definition: Morphology.h:414
Mapping from a Log2Dim to a data type of size 2^Log2Dim bits.
Definition: Morphology.h:233
CopyMasks(std::vector< MaskType > &masks, const ManagerType &manager)
Definition: Morphology.h:443
RangeType getRange(size_t grainsize=1) const
Return a tbb::blocked_range of leaf array indices.
Definition: LeafManager.h:383
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1221
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:358
GLenum mode
Definition: glcorearb.h:98
bool isValueOn(const Coord &xyz) const
Return the active state of the voxel at the given coordinates.
OPENVDB_STATIC_SPECIALIZATION void erodeVoxels(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE)
Topologically erode all leaf-level active voxels in the given tree.
Definition: Morphology.h:878
GLsizei const GLfloat * value
Definition: glcorearb.h:823
void dilateVoxels(int iterations=1, NearestNeighbors nn=NN_FACE)
Definition: Morphology.h:458
DimToWord< LEAF_LOG2DIM >::Type Word
Definition: Morphology.h:291
UpdateMasks(const std::vector< MaskType > &masks, ManagerType &manager)
Definition: Morphology.h:433
void operator()(const typename TreeType::LeafIter &lit) const
Definition: Morphology.h:918
void operator()(const tbb::blocked_range< size_t > &r) const
Definition: Morphology.h:436
TilePolicy
Different policies when dilating trees with active tiles.
Definition: Morphology.h:100
void erodeVoxels18()
Face- and edge-adjacent erosion pattern.
Definition: Morphology.h:266
ActivationOp(bool state, const ValueT &val, const ValueT &tol)
Definition: Morphology.h:898
GLint GLenum GLint x
Definition: glcorearb.h:408
GLuint GLfloat * val
Definition: glcorearb.h:1607
GA_API const UT_StringHolder N
void operator()(const typename TreeType::ValueOnIter &it) const
Definition: Morphology.h:904
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:107
void scatterEdgesXY(int x, int y, int i1, int n, int i2)
Definition: Morphology.h:652
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:856
Word gather(AccessorType &acc, const Coord &xyz, int indx)
Definition: Morphology.h:316
void dilateVoxels6()
Face-adjacent dilation pattern.
Definition: Morphology.h:478
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
GLboolean r
Definition: glcorearb.h:1221
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition: LeafManager.h:359
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:361
void deactivate(GridOrTree &, const typename GridOrTree::ValueType &value, const typename GridOrTree::ValueType &tolerance=zeroVal< typename GridOrTree::ValueType >())
Mark as inactive any active tiles or voxels in the given grid or tree whose values are equal to value...
Definition: Morphology.h:970
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:416
void operator()(const tbb::blocked_range< size_t > &r) const
Definition: Morphology.h:446
void activate(GridOrTree &, const typename GridOrTree::ValueType &value, const typename GridOrTree::ValueType &tolerance=zeroVal< typename GridOrTree::ValueType >())
Mark as active any inactive tiles or voxels in the given grid or tree whose values are equal to value...
Definition: Morphology.h:947
void scatter(AccessorType &acc, const Coord &xyz, int indx, Word mask)
Definition: Morphology.h:300
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:135
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
Definition: Math.h:549
void copyMasks(std::vector< MaskType > &a, const ManagerType &b)
Definition: Morphology.h:452
OPENVDB_STATIC_SPECIALIZATION void dilateActiveValues(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE, TilePolicy mode=PRESERVE_TILES)
Topologically dilate all active values (i.e. both voxels and tiles) in a tree using one of three near...
Definition: Morphology.h:1079
void operator()(const typename TreeType::ValueOffIter &it) const
Definition: Morphology.h:911
void scatterFacesXY(int x, int y, int i1, int n, int i2)
Definition: Morphology.h:621
ErodeVoxelsOp(std::vector< MaskType > &masks, ManagerType &manager)
Definition: Morphology.h:394
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
OPENVDB_STATIC_SPECIALIZATION void dilateVoxels(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE)
Topologically dilate all leaf-level active voxels in a tree using one of three nearest neighbor conne...
Definition: Morphology.h:858
MaskManager(std::vector< MaskType > &masks, ManagerType &manager)
Definition: Morphology.h:409
void rebuildLeafArray()
Remove the auxiliary buffers and rebuild the leaf array.
Definition: LeafManager.h:316