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