OpenVDB  7.0.0
MultiResGrid.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
24 
25 #ifndef OPENVDB_TOOLS_MULTIRESGRID_HAS_BEEN_INCLUDED
26 #define OPENVDB_TOOLS_MULTIRESGRID_HAS_BEEN_INCLUDED
27 
28 #include <openvdb/Grid.h>
30 #include <openvdb/math/Math.h>
31 #include <openvdb/math/Operators.h>
32 #include <openvdb/math/Stencils.h>
33 #include <openvdb/Metadata.h>
36 #include "Interpolation.h"
37 #include "Morphology.h"
38 #include "Prune.h"
39 #include "SignedFloodFill.h"
40 #include "ValueTransformer.h"
41 
42 #include <tbb/blocked_range.h>
43 #include <tbb/enumerable_thread_specific.h>
44 #include <tbb/parallel_for.h>
45 
46 #include <iostream>
47 #include <sstream>
48 #include <string>
49 #include <vector>
50 
51 
52 namespace openvdb {
54 namespace OPENVDB_VERSION_NAME {
55 namespace tools {
56 
57 template<typename TreeType>
58 class MultiResGrid: public MetaMap
59 {
60 public:
63 
64  using ValueType = typename TreeType::ValueType;
65  using ValueOnCIter = typename TreeType::ValueOnCIter;
66  using ValueOnIter = typename TreeType::ValueOnIter;
67  using TreePtr = typename TreeType::Ptr;
68  using ConstTreePtr = typename TreeType::ConstPtr;
69  using GridPtr = typename Grid<TreeType>::Ptr;
71 
73 
79  MultiResGrid(size_t levels, ValueType background, double voxelSize = 1.0);
80 
89  MultiResGrid(size_t levels, const Grid<TreeType> &grid, bool useInjection = false);
90 
99  MultiResGrid(size_t levels, GridPtr grid, bool useInjection = false);
100 
102 
106  size_t numLevels() const { return mTrees.size(); }
107 
109  static size_t finestLevel() { return 0; }
110 
112  size_t coarsestLevel() const { return mTrees.size()-1; }
113 
115 
119  TreeType& tree(size_t level);
120 
124  const TreeType& constTree(size_t level) const;
125 
129  TreePtr treePtr(size_t level);
130 
134  ConstTreePtr constTreePtr(size_t level) const;
135 
137  TreeType& finestTree() { return *mTrees.front(); }
138 
140  const TreeType& finestConstTree() const { return *mTrees.front(); }
141 
143  TreePtr finestTreePtr() { return mTrees.front(); }
144 
146  ConstTreePtr finestConstTreePtr() const { return mTrees.front(); }
147 
149  TreeType& coarsestTree() { return *mTrees.back(); }
150 
152  const TreeType& coarsestConstTree() const { return *mTrees.back(); }
153 
155  TreePtr coarsestTreePtr() { return mTrees.back(); }
156 
158  ConstTreePtr coarsestConstTreePtr() const { return mTrees.back(); }
159 
161 
165  GridPtr grid(size_t level);
166 
170  ConstGridPtr grid(size_t level) const;
171 
179  template<Index Order>
180  GridPtr createGrid(float level, size_t grainSize = 1) const;
181 
185  GridPtrVecPtr grids();
186 
190  GridCPtrVecPtr grids() const;
191 
193 
195  math::Transform& transform() { return *mTransform; }
201  const math::Transform& transform() const { return *mTransform; }
202  const math::Transform& constTransform() const { return *mTransform; }
204 
206 
208  static Vec3R xyz(const Coord& in_ijk, size_t in_level, size_t out_level);
211  static Vec3R xyz(const Vec3R& in_xyz, size_t in_level, size_t out_level);
212  static Vec3R xyz(const Vec3R& in_xyz, double in_level, double out_level);
214 
216 
217 
218 
220  template<Index Order>
230  ValueType sampleValue(const Coord& in_ijk, size_t in_level, size_t out_level) const;
231  template<Index Order>
232  ValueType sampleValue(const Vec3R& in_ijk, size_t in_level, size_t out_level) const;
234 
241  template<Index Order>
242  ValueType sampleValue(const Coord& ijk, double level) const;
243 
251  template<Index Order>
252  ValueType sampleValue(const Vec3R& xyz, double level) const;
253 
255 
262  ValueType prolongateVoxel(const Coord& coords, const size_t level) const;
263 
264 
268  void prolongateActiveVoxels(size_t destlevel, size_t grainSize = 1);
269 
271 
276  ValueType restrictVoxel(Coord ijk, const size_t level, bool useInjection = false) const;
277 
284  void restrictActiveVoxels(size_t destlevel, size_t grainSize = 1);
285 
287  void print(std::ostream& = std::cout, int verboseLevel = 1) const;
288 
290  std::string getName() const
291  {
292  if (Metadata::ConstPtr meta = (*this)[GridBase::META_GRID_NAME]) return meta->str();
293  return "";
294  }
295 
297  void setName(const std::string& name)
298  {
299  this->removeMeta(GridBase::META_GRID_NAME);
300  this->insertMeta(GridBase::META_GRID_NAME, StringMetadata(name));
301  }
302 
305  {
306  typename StringMetadata::ConstPtr s =
307  this->getMetadata<StringMetadata>(GridBase::META_GRID_CLASS);
308  return s ? GridBase::stringToGridClass(s->value()) : GRID_UNKNOWN;
309  }
310 
313  {
315  }
316 
318  void clearGridClass() { this->removeMeta(GridBase::META_GRID_CLASS); }
319 
320 private:
321 
322  MultiResGrid(const MultiResGrid& other);//disallow copy construction
323  MultiResGrid& operator=(const MultiResGrid& other);//disallow copy assignment
324 
325  // For optimal performance we disable registration of the ValueAccessor
328 
329  void topDownRestrict(bool useInjection);
330 
331  inline void initMeta();
332 
333  // Private struct that concurrently creates a mask of active voxel
334  // in a coarse tree from the active voxels in a fine tree
335  struct MaskOp;
336 
338  struct RestrictOp;
339 
341  struct ProlongateOp;
342 
343  // Private struct that performs multi-threaded computation of grids a fraction levels
344  template<Index Order>
345  struct FractionOp;
346 
348  template<typename OpType> struct CookOp;
349 
350  // Array of shared pointer to trees, level 0 has the highest resolution.
351  std::vector<TreePtr> mTrees;
352  // Shared pointer to a transform associated with the finest level grid
353  typename math::Transform::Ptr mTransform;
354 };// MultiResGrid
355 
356 template<typename TreeType>
358 MultiResGrid(size_t levels, ValueType background, double voxelSize)
359  : mTrees(levels)
360  , mTransform(math::Transform::createLinearTransform( voxelSize ))
361 {
362  this->initMeta();
363  for (size_t i=0; i<levels; ++i) mTrees[i] = TreePtr(new TreeType(background));
364 }
365 
366 template<typename TreeType>
368 MultiResGrid(size_t levels, const Grid<TreeType> &grid, bool useInjection)
369  : MetaMap(grid)
370  , mTrees(levels)
371  , mTransform( grid.transform().copy() )
372 {
373  this->initMeta();
374  mTrees[0].reset( new TreeType( grid.tree() ) );// deep copy input tree
375  mTrees[0]->voxelizeActiveTiles();
376  this->topDownRestrict(useInjection);
377 }
378 
379 template<typename TreeType>
381 MultiResGrid(size_t levels, GridPtr grid, bool useInjection)
382  : MetaMap(*grid)
383  , mTrees(levels)
384  , mTransform( grid->transform().copy() )
385 {
386  this->initMeta();
387  mTrees[0] = grid->treePtr();// steal tree from input grid
388  mTrees[0]->voxelizeActiveTiles();
389  grid->newTree();
390  this->topDownRestrict(useInjection);
391 }
392 
393 template<typename TreeType>
394 inline TreeType& MultiResGrid<TreeType>::
395 tree(size_t level)
396 {
397  assert( level < mTrees.size() );
398  return *mTrees[level];
399 }
400 
401 template<typename TreeType>
402 inline const TreeType& MultiResGrid<TreeType>::
403 constTree(size_t level) const
404 {
405  assert( level < mTrees.size() );
406  return *mTrees[level];
407 }
408 
409 template<typename TreeType>
410 inline typename TreeType::Ptr MultiResGrid<TreeType>::
411 treePtr(size_t level)
412 {
413  assert( level < mTrees.size() );
414  return mTrees[level];
415 }
416 
417 template<typename TreeType>
418 inline typename TreeType::ConstPtr MultiResGrid<TreeType>::
419 constTreePtr(size_t level) const
420 {
421  assert( level < mTrees.size() );
422  return mTrees[level];
423 }
424 
425 template<typename TreeType>
427 grid(size_t level)
428 {
429  typename Grid<TreeType>::Ptr grid = Grid<TreeType>::create(this->treePtr(level));
430  math::Transform::Ptr xform = mTransform->copy();
431  if (level>0) xform->preScale( Real(1 << level) );
432  grid->setTransform( xform );
433  grid->insertMeta( *this->copyMeta() );
434  grid->insertMeta( "MultiResGrid_Level", Int64Metadata(level));
435  std::stringstream ss;
436  ss << this->getName() << "_level_" << level;
437  grid->setName( ss.str() );
438  return grid;
439 }
440 
441 template<typename TreeType>
443 grid(size_t level) const
444 {
445  return const_cast<MultiResGrid*>(this)->grid(level);
446 }
447 
448 template<typename TreeType>
449 template<Index Order>
451 createGrid(float level, size_t grainSize) const
452 {
453  assert( level >= 0.0f && level <= float(mTrees.size()-1) );
454 
455  typename Grid<TreeType>::Ptr grid(new Grid<TreeType>(this->constTree(0).background()));
456  math::Transform::Ptr xform = mTransform->copy();
457  xform->preScale( math::Pow(2.0f, level) );
458  grid->setTransform( xform );
459  grid->insertMeta( *(this->copyMeta()) );
460  grid->insertMeta( "MultiResGrid_Level", FloatMetadata(level) );
461  std::stringstream ss;
462  ss << this->getName() << "_level_" << level;
463  grid->setName( ss.str() );
464 
465  if ( size_t(floorf(level)) == size_t(ceilf(level)) ) {
466  grid->setTree( this->constTree( size_t(floorf(level))).copy() );
467  } else {
468  FractionOp<Order> tmp(*this, grid->tree(), level, grainSize);
469  if ( grid->getGridClass() == GRID_LEVEL_SET ) {
470  signedFloodFill( grid->tree() );
471  pruneLevelSet( grid->tree() );//only creates inactive tiles
472  }
473  }
474 
475  return grid;
476 }
477 
478 template<typename TreeType>
481 {
483  for (size_t level=0; level<mTrees.size(); ++level) grids->push_back(this->grid(level));
484  return grids;
485 }
486 
487 template<typename TreeType>
489 grids() const
490 {
492  for (size_t level=0; level<mTrees.size(); ++level) grids->push_back(this->grid(level));
493  return grids;
494 }
495 
496 template<typename TreeType>
498 xyz(const Coord& in_ijk, size_t in_level, size_t out_level)
499 {
500  return Vec3R( in_ijk.data() ) * Real(1 << in_level) / Real(1 << out_level);
501 }
502 
503 template<typename TreeType>
505 xyz(const Vec3R& in_xyz, size_t in_level, size_t out_level)
506 {
507  return in_xyz * Real(1 << in_level) / Real(1 << out_level);
508 }
509 
510 template<typename TreeType>
512 xyz(const Vec3R& in_xyz, double in_level, double out_level)
513 {
514  return in_xyz * math::Pow(2.0, in_level - out_level);
515 
516 }
517 
518 template<typename TreeType>
519 template<Index Order>
520 typename TreeType::ValueType MultiResGrid<TreeType>::
521 sampleValue(const Coord& in_ijk, size_t in_level, size_t out_level) const
522 {
523  assert( in_level >= 0 && in_level < mTrees.size() );
524  assert( out_level >= 0 && out_level < mTrees.size() );
525  const ConstAccessor acc(*mTrees[out_level]);// has disabled registration!
526  return tools::Sampler<Order>::sample( acc, this->xyz(in_ijk, in_level, out_level) );
527 }
528 
529 template<typename TreeType>
530 template<Index Order>
531 typename TreeType::ValueType MultiResGrid<TreeType>::
532 sampleValue(const Vec3R& in_xyz, size_t in_level, size_t out_level) const
533 {
534  assert( in_level >= 0 && in_level < mTrees.size() );
535  assert( out_level >= 0 && out_level < mTrees.size() );
536  const ConstAccessor acc(*mTrees[out_level]);// has disabled registration!
537  return tools::Sampler<Order>::sample( acc, this->xyz(in_xyz, in_level, out_level) );
538 }
539 
540 template<typename TreeType>
541 template<Index Order>
542 typename TreeType::ValueType MultiResGrid<TreeType>::
543 sampleValue(const Coord& ijk, double level) const
544 {
545  assert( level >= 0.0 && level <= double(mTrees.size()-1) );
546  const size_t level0 = size_t(floor(level)), level1 = size_t(ceil(level));
547  const ValueType v0 = this->template sampleValue<Order>( ijk, 0, level0 );
548  if ( level0 == level1 ) return v0;
549  assert( level1 - level0 == 1 );
550  const ValueType v1 = this->template sampleValue<Order>( ijk, 0, level1 );
552  const ValueType a = ValueType(level1 - level);
554  return a * v0 + (ValueType(1) - a) * v1;
555 }
556 
557 template<typename TreeType>
558 template<Index Order>
559 typename TreeType::ValueType MultiResGrid<TreeType>::
560 sampleValue(const Vec3R& xyz, double level) const
561 {
562  assert( level >= 0.0 && level <= double(mTrees.size()-1) );
563  const size_t level0 = size_t(floor(level)), level1 = size_t(ceil(level));
564  const ValueType v0 = this->template sampleValue<Order>( xyz, 0, level0 );
565  if ( level0 == level1 ) return v0;
566  assert( level1 - level0 == 1 );
567  const ValueType v1 = this->template sampleValue<Order>( xyz, 0, level1 );
569  const ValueType a = ValueType(level1 - level);
571  return a * v0 + (ValueType(1) - a) * v1;
572 }
573 
574 template<typename TreeType>
575 typename TreeType::ValueType MultiResGrid<TreeType>::
576 prolongateVoxel(const Coord& ijk, const size_t level) const
577 {
578  assert( level+1 < mTrees.size() );
579  const ConstAccessor acc(*mTrees[level + 1]);// has disabled registration!
580  return ProlongateOp::run(ijk, acc);
581 }
582 
583 template<typename TreeType>
585 prolongateActiveVoxels(size_t destlevel, size_t grainSize)
586 {
587  assert( destlevel < mTrees.size()-1 );
588  TreeType &fineTree = *mTrees[ destlevel ];
589  const TreeType &coarseTree = *mTrees[ destlevel+1 ];
590  CookOp<ProlongateOp> tmp( coarseTree, fineTree, grainSize );
591 }
592 
593 template<typename TreeType>
594 typename TreeType::ValueType MultiResGrid<TreeType>::
595 restrictVoxel(Coord ijk, const size_t destlevel, bool useInjection) const
596 {
597  assert( destlevel > 0 && destlevel < mTrees.size() );
598  const TreeType &fineTree = *mTrees[ destlevel-1 ];
599  if ( useInjection ) return fineTree.getValue(ijk<<1);
600  const ConstAccessor acc( fineTree );// has disabled registration!
601  return RestrictOp::run( ijk, acc);
602 }
603 
604 template<typename TreeType>
606 restrictActiveVoxels(size_t destlevel, size_t grainSize)
607 {
608  assert( destlevel > 0 && destlevel < mTrees.size() );
609  const TreeType &fineTree = *mTrees[ destlevel-1 ];
610  TreeType &coarseTree = *mTrees[ destlevel ];
611  CookOp<RestrictOp> tmp( fineTree, coarseTree, grainSize );
612 }
613 
614 template<typename TreeType>
616 print(std::ostream& os, int verboseLevel) const
617 {
618  os << "MultiResGrid with " << mTrees.size() << " levels\n";
619  for (size_t i=0; i<mTrees.size(); ++i) {
620  os << "Level " << i << ": ";
621  mTrees[i]->print(os, verboseLevel);
622  }
623 
624  if ( MetaMap::metaCount() > 0) {
625  os << "Additional metadata:" << std::endl;
626  for (ConstMetaIterator it = beginMeta(), end = endMeta(); it != end; ++it) {
627  os << " " << it->first;
628  if (it->second) {
629  const std::string value = it->second->str();
630  if (!value.empty()) os << ": " << value;
631  }
632  os << "\n";
633  }
634  }
635 
636  os << "Transform:" << std::endl;
637  transform().print(os, /*indent=*/" ");
638  os << std::endl;
639 }
640 
641 template<typename TreeType>
643 initMeta()
644 {
645  const size_t levels = this->numLevels();
646  if (levels < 2) {
647  OPENVDB_THROW(ValueError, "MultiResGrid: at least two levels are required");
648  }
649  this->insertMeta("MultiResGrid_Levels", Int64Metadata( levels ) );
650 }
651 
652 template<typename TreeType>
654 topDownRestrict(bool useInjection)
655 {
656  const bool isLevelSet = this->getGridClass() == GRID_LEVEL_SET;
657  for (size_t n=1; n<mTrees.size(); ++n) {
658  const TreeType &fineTree = *mTrees[n-1];
659  mTrees[n] = TreePtr(new TreeType( fineTree.background() ) );// empty tree
660  TreeType &coarseTree = *mTrees[n];
661  if (useInjection) {// Restriction by injection
662  for (ValueOnCIter it = fineTree.cbeginValueOn(); it; ++it) {
663  const Coord ijk = it.getCoord();
664  if ( (ijk[0] & 1) || (ijk[1] & 1) || (ijk[2] & 1) ) continue;
665  coarseTree.setValue( ijk >> 1, *it );
666  }
667  } else {// Restriction by full-weighting
668  MaskOp tmp(fineTree, coarseTree, 128);
669  this->restrictActiveVoxels(n, 64);
670  }
671  if ( isLevelSet ) {
672  tools::signedFloodFill( coarseTree );
673  tools::pruneLevelSet( coarseTree );//only creates inactive tiles
674  }
675  }// loop over grid levels
676 }
677 
678 template<typename TreeType>
680 {
681  using MaskT = typename TreeType::template ValueConverter<ValueMask>::Type;
682  using PoolType = tbb::enumerable_thread_specific<TreeType>;
684  using RangeT = typename ManagerT::LeafRange;
685  using VoxelIterT = typename ManagerT::LeafNodeType::ValueOnCIter;
686 
687  MaskOp(const TreeType& fineTree, TreeType& coarseTree, size_t grainSize = 1)
688  : mPool(new PoolType( coarseTree ) )// empty coarse tree acts as examplar
689  {
690  assert( coarseTree.empty() );
691 
692  // Create Mask of restruction performed on fineTree
693  MaskT mask(fineTree, false, true, TopologyCopy() );
694 
695  // Muli-threaded dilation which also linearizes the tree to leaf nodes
697 
698  // Restriction by injection using thread-local storage of coarse tree masks
699  ManagerT leafs( mask );
700  tbb::parallel_for(leafs.leafRange( grainSize ), *this);
701 
702  // multithreaded union of thread-local coarse tree masks with the coarse tree
703  using IterT = typename PoolType::const_iterator;
704  for (IterT it=mPool->begin(); it!=mPool->end(); ++it) coarseTree.topologyUnion( *it );
705  delete mPool;
706  }
707  void operator()(const RangeT& range) const
708  {
709  Accessor coarseAcc( mPool->local() );// disabled registration
710  for (typename RangeT::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
711  for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
712  Coord ijk = voxelIter.getCoord();
713  if ( (ijk[2] & 1) || (ijk[1] & 1) || (ijk[0] & 1) ) continue;//no overlap
714  coarseAcc.setValueOn( ijk >> 1 );//injection from fine to coarse level
715  }//loop over active voxels in the fine tree
716  }// loop over leaf nodes in the fine tree
717  }
719 };// MaskOp
720 
721 template<typename TreeType>
722 template<Index Order>
724 {
725  using MaskT = typename TreeType::template ValueConverter<ValueMask>::Type;
726  using PoolType = tbb::enumerable_thread_specific<MaskT>;
727  using PoolIterT = typename PoolType::iterator;
728  using Manager1 = tree::LeafManager<const TreeType>;
729  using Manager2 = tree::LeafManager<TreeType>;
730  using Range1 = typename Manager1::LeafRange;
731  using Range2 = typename Manager2::LeafRange;
732 
733  FractionOp(const MultiResGrid& parent,
734  TreeType& midTree,
735  float level,
736  size_t grainSize = 1)
737  : mLevel( level )
738  , mPool(nullptr)
739  , mTree0( &*(parent.mTrees[size_t(floorf(level))]) )//high-resolution
740  , mTree1( &*(parent.mTrees[size_t(ceilf(level))]) ) //low-resolution
741  {
742  assert( midTree.empty() );
743  assert( mTree0 != mTree1 );
744 
745  // Create a pool of thread-local masks
746  MaskT examplar( false );
747  mPool = new PoolType( examplar );
748 
749  {// create mask from re-mapping coarse tree to mid-level tree
750  tree::LeafManager<const TreeType> manager( *mTree1 );
751  tbb::parallel_for( manager.leafRange(grainSize), *this );
752  }
753 
754  // Multi-threaded dilation of mask
755  tbb::parallel_for(tbb::blocked_range<PoolIterT>(mPool->begin(),mPool->end(),1), *this);
756 
757  // Union thread-local coarse tree masks into the coarse tree
758  for (PoolIterT it=mPool->begin(); it!=mPool->end(); ++it) midTree.topologyUnion( *it );
759  delete mPool;
760 
761  {// Interpolate values into the static mid level tree
762  Manager2 manager( midTree );
763  tbb::parallel_for(manager.leafRange(grainSize), *this);
764  }
765  }
766  void operator()(const Range1& range) const
767  {
768  using VoxelIter = typename Manager1::LeafNodeType::ValueOnCIter;
769  // Let mLevel = level + frac, where
770  // level is integer part of mLevel and frac is the fractional part
771  // low-res voxel size in world units = dx1 = 2^(level + 1)
772  // mid-res voxel size in world units = dx = 2^(mLevel) = 2^(level + frac)
773  // low-res index -> world: ijk * dx1
774  // world -> mid-res index: world / dx
775  // low-res index -> mid-res index: (ijk * dx1) / dx = ijk * scale where
776  // scale = dx1/dx = 2^(level+1)/2^(level+frac) = 2^(1-frac)
777  const float scale = math::Pow(2.0f, 1.0f - math::FractionalPart(mLevel));
778  tree::ValueAccessor<MaskT, false> acc( mPool->local() );// disabled registration
779  for (typename Range1::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
780  for (VoxelIter voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
781  Coord ijk = voxelIter.getCoord();
783  const auto value0 = ijk[0] * scale;
784  const auto value1 = ijk[1] * scale;
785  const auto value2 = ijk[2] * scale;
787  ijk[0] = int(math::Round(value0));
788  ijk[1] = int(math::Round(value1));
789  ijk[2] = int(math::Round(value2));
790 
791  acc.setValueOn( ijk );
792  }//loop over active voxels in the fine tree
793  }// loop over leaf nodes in the fine tree
794  }
795  void operator()(const tbb::blocked_range<PoolIterT>& range) const
796  {
797  for (PoolIterT it=range.begin(); it!=range.end(); ++it) {
799  }
800  }
801  void operator()(const Range2 &r) const
802  {
803  using VoxelIter = typename TreeType::LeafNodeType::ValueOnIter;
804  // Let mLevel = level + frac, where
805  // level is integer part of mLevel and frac is the fractional part
806  // high-res voxel size in world units = dx0 = 2^(level)
807  // low-res voxel size in world units = dx1 = 2^(level+1)
808  // mid-res voxel size in world units = dx = 2^(mLevel) = 2^(level + frac)
809  // mid-res index -> world: ijk * dx
810  // world -> high-res index: world / dx0
811  // world -> low-res index: world / dx1
812  // mid-res index -> high-res index: (ijk * dx) / dx0 = ijk * scale0 where
813  // scale0 = dx/dx0 = 2^(level+frac)/2^(level) = 2^(frac)
814  // mid-res index -> low-res index: (ijk * dx) / dx1 = ijk * scale1 where
815  // scale1 = dx/dx1 = 2^(level+frac)/2^(level+1) = 2^(frac-1)
816  const float b = math::FractionalPart(mLevel), a = 1.0f - b;
817  const float scale0 = math::Pow( 2.0f, b );
818  const float scale1 = math::Pow( 2.0f,-a );
819  ConstAccessor acc0( *mTree0 ), acc1( *mTree1 );
820  for (typename Range2::Iterator leafIter = r.begin(); leafIter; ++leafIter) {
821  for (VoxelIter voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
822  const Vec3R xyz = Vec3R( voxelIter.getCoord().data() );// mid level coord
823  const ValueType v0 = tools::Sampler<Order>::sample( acc0, xyz * scale0 );
824  const ValueType v1 = tools::Sampler<Order>::sample( acc1, xyz * scale1 );
826  const auto value0 = a*v0;
827  const auto value1 = b*v1;
829  voxelIter.setValue( ValueType(value0 + value1) );
830  }
831  }
832  }
833  const float mLevel;
834  PoolType* mPool;
835  const TreeType *mTree0, *mTree1;
836 };// FractionOp
837 
838 
839 template<typename TreeType>
840 template<typename OperatorType>
842 {
844  using RangeT = typename ManagerT::LeafRange;
845 
846  CookOp(const TreeType& srcTree, TreeType& dstTree, size_t grainSize): acc(srcTree)
847  {
848  ManagerT leafs(dstTree);
849  tbb::parallel_for(leafs.leafRange(grainSize), *this);
850  }
851  CookOp(const CookOp &other): acc(other.acc.tree()) {}
852 
853  void operator()(const RangeT& range) const
854  {
855  for (auto leafIt = range.begin(); leafIt; ++leafIt) {
856  auto& phi = leafIt.buffer(0);
857  for (auto voxelIt = leafIt->beginValueOn(); voxelIt; ++voxelIt) {
858  phi.setValue(voxelIt.pos(), OperatorType::run(voxelIt.getCoord(), acc));
859  }
860  }
861  }
862 
863  const ConstAccessor acc;
864 };// CookOp
865 
866 
867 template<typename TreeType>
869 {
873  static ValueType run(Coord ijk, const ConstAccessor &acc)
874  {
875  ijk <<= 1;
876  // Overlapping grid point
877  ValueType v = 8*acc.getValue(ijk);
878  // neighbors in one axial direction
879  v += 4*(acc.getValue(ijk.offsetBy(-1, 0, 0)) + acc.getValue(ijk.offsetBy( 1, 0, 0)) +// x
880  acc.getValue(ijk.offsetBy( 0,-1, 0)) + acc.getValue(ijk.offsetBy( 0, 1, 0)) +// y
881  acc.getValue(ijk.offsetBy( 0, 0,-1)) + acc.getValue(ijk.offsetBy( 0, 0, 1)));// z
882  // neighbors in two axial directions
883  v += 2*(acc.getValue(ijk.offsetBy(-1,-1, 0)) + acc.getValue(ijk.offsetBy(-1, 1, 0)) +// xy
884  acc.getValue(ijk.offsetBy( 1,-1, 0)) + acc.getValue(ijk.offsetBy( 1, 1, 0)) +// xy
885  acc.getValue(ijk.offsetBy(-1, 0,-1)) + acc.getValue(ijk.offsetBy(-1, 0, 1)) +// xz
886  acc.getValue(ijk.offsetBy( 1, 0,-1)) + acc.getValue(ijk.offsetBy( 1, 0, 1)) +// xz
887  acc.getValue(ijk.offsetBy( 0,-1,-1)) + acc.getValue(ijk.offsetBy( 0,-1, 1)) +// yz
888  acc.getValue(ijk.offsetBy( 0, 1,-1)) + acc.getValue(ijk.offsetBy( 0, 1, 1)));// yz
889  // neighbors in three axial directions
890  for (int i=-1; i<=1; i+=2) {
891  for (int j=-1; j<=1; j+=2) {
892  for (int k=-1; k<=1; k+=2) v += acc.getValue(ijk.offsetBy(i,j,k));// xyz
893  }
894  }
895  v *= ValueType(1.0f/64.0f);
896  return v;
897  }
898 };// RestrictOp
899 
900 template<typename TreeType>
902 {
906  static ValueType run(const Coord& ijk, const ConstAccessor &acc)
907  {
908  switch ( (ijk[0] & 1) | ((ijk[1] & 1) << 1) | ((ijk[2] & 1) << 2) ) {
909  case 0:// all even
910  return acc.getValue(ijk>>1);
911  case 1:// x is odd
912  return ValueType(0.5)*(acc.getValue(ijk.offsetBy(-1,0,0)>>1) +
913  acc.getValue(ijk.offsetBy( 1,0,0)>>1));
914  case 2:// y is odd
915  return ValueType(0.5)*(acc.getValue(ijk.offsetBy(0,-1,0)>>1) +
916  acc.getValue(ijk.offsetBy(0, 1,0)>>1));
917  case 3:// x&y are odd
918  return ValueType(0.25)*(acc.getValue(ijk.offsetBy(-1,-1,0)>>1) +
919  acc.getValue(ijk.offsetBy(-1, 1,0)>>1) +
920  acc.getValue(ijk.offsetBy( 1,-1,0)>>1) +
921  acc.getValue(ijk.offsetBy( 1, 1,0)>>1));
922  case 4:// z is odd
923  return ValueType(0.5)*(acc.getValue(ijk.offsetBy(0,0,-1)>>1) +
924  acc.getValue(ijk.offsetBy(0,0, 1)>>1));
925  case 5:// x&z are odd
926  return ValueType(0.25)*(acc.getValue(ijk.offsetBy(-1,0,-1)>>1) +
927  acc.getValue(ijk.offsetBy(-1,0, 1)>>1) +
928  acc.getValue(ijk.offsetBy( 1,0,-1)>>1) +
929  acc.getValue(ijk.offsetBy( 1,0, 1)>>1));
930  case 6:// y&z are odd
931  return ValueType(0.25)*(acc.getValue(ijk.offsetBy(0,-1,-1)>>1) +
932  acc.getValue(ijk.offsetBy(0,-1, 1)>>1) +
933  acc.getValue(ijk.offsetBy(0, 1,-1)>>1) +
934  acc.getValue(ijk.offsetBy(0, 1, 1)>>1));
935  }
936  // all are odd
937  ValueType v = zeroVal<ValueType>();
938  for (int i=-1; i<=1; i+=2) {
939  for (int j=-1; j<=1; j+=2) {
940  for (int k=-1; k<=1; k+=2) v += acc.getValue(ijk.offsetBy(i,j,k)>>1);// xyz
941  }
942  }
943  return ValueType(0.125) * v;
944  }
945 };// ProlongateOp
946 
947 } // namespace tools
948 } // namespace OPENVDB_VERSION_NAME
949 } // namespace openvdb
950 
951 #endif // OPENVDB_TOOLS_MULTIRESGRID_HAS_BEEN_INCLUDED
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
Bracket code with OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN/_END, to inhibit warnings about type conve...
Definition: Platform.h:196
Definition: MultiResGrid.h:679
static bool sample(const TreeT &inTree, const Vec3R &inCoord, typename TreeT::ValueType &result)
Sample inTree at the floating-point index coordinate inCoord and store the result in result...
typename TreeType::Ptr TreePtr
Definition: MultiResGrid.h:67
size_t coarsestLevel() const
Return the level of the coarsest grid, i.e. numLevels()-1.
Definition: MultiResGrid.h:112
typename Grid< TreeType >::ConstPtr ConstGridPtr
Definition: MultiResGrid.h:70
SharedPtr< const TypedMetadata< T >> ConstPtr
Definition: Metadata.h:148
Definition: ValueAccessor.h:193
const TreeType & constTree(size_t level) const
Return a const reference to the tree at the specified level.
Definition: MultiResGrid.h:403
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
static const char *const META_GRID_NAME
Definition: Grid.h:352
PoolType * mPool
Definition: MultiResGrid.h:718
const TreeType & finestConstTree() const
Return a const reference to the tree at the finest level.
Definition: MultiResGrid.h:140
SharedPtr< Grid > Ptr
Definition: Grid.h:574
ConstTreePtr constTreePtr(size_t level) const
Return a const shared pointer to the tree at the specified level.
Definition: MultiResGrid.h:419
void setValueOn(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
typename ManagerT::LeafRange RangeT
Definition: MultiResGrid.h:684
Type FractionalPart(Type x)
Return the fractional part of x.
Definition: Math.h:790
void operator()(const RangeT &range) const
Definition: MultiResGrid.h:707
void setName(const std::string &name)
Set the name of this MultiResGrid.
Definition: MultiResGrid.h:297
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
std::shared_ptr< T > SharedPtr
Definition: Types.h:91
ConstTreePtr finestConstTreePtr() const
Return a const shared pointer to the tree at the finest level.
Definition: MultiResGrid.h:146
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
static size_t finestLevel()
Return the level of the finest grid (always 0)
Definition: MultiResGrid.h:109
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:230
typename TreeType::ValueOnIter ValueOnIter
Definition: MultiResGrid.h:66
MetadataMap::const_iterator ConstMetaIterator
Definition: MetaMap.h:28
float Round(float x)
Return x rounded to the nearest integer.
Definition: Math.h:766
static std::string gridClassToString(GridClass)
Return the metadata string value for the given class of volumetric data.
static const char *const META_GRID_CLASS
Definition: Grid.h:350
typename TreeType::ConstPtr ConstTreePtr
Definition: MultiResGrid.h:68
double Real
Definition: Types.h:37
size_t numLevels() const
Return the number of levels, i.e. trees, in this MultiResGrid.
Definition: MultiResGrid.h:106
void insertMeta(const Name &, const Metadata &value)
Insert a new metadata field or overwrite the value of an existing field.
static Ptr create()
Return a new grid with background value zero.
Definition: Grid.h:1318
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_END
Definition: Platform.h:197
void setGridClass(GridClass cls)
Specify the class of volumetric data (level set, fog volume, etc.) stored in this grid...
Definition: MultiResGrid.h:312
TreePtr finestTreePtr()
Return a shared pointer to the tree at the finest level.
Definition: MultiResGrid.h:143
TreeType & finestTree()
Return a reference to the tree at the finest level.
Definition: MultiResGrid.h:137
Defined various multi-threaded utility functions for trees.
Definition: Exceptions.h:65
Container that maps names (strings) to values of arbitrary types.
Definition: MetaMap.h:19
static ValueType run(Coord ijk, const ConstAccessor &acc)
Static method that performs restriction by full weighting.
Definition: MultiResGrid.h:873
void print(std::ostream &=std::cout, int verboseLevel=1) const
Output a human-readable description of this MultiResGrid.
Definition: MultiResGrid.h:616
MaskOp(const TreeType &fineTree, TreeType &coarseTree, size_t grainSize=1)
Definition: MultiResGrid.h:687
typename TreeType::ValueOnCIter ValueOnCIter
Definition: MultiResGrid.h:65
SharedPtr< MetaMap > Ptr
Definition: MetaMap.h:22
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:389
GridPtr grid(size_t level)
Return a shared pointer to the grid at the specified integer level.
Definition: MultiResGrid.h:427
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
TreeType & tree(size_t level)
Return a reference to the tree at the specified level.
Definition: MultiResGrid.h:395
SharedPtr< GridPtrVec > GridPtrVecPtr
Definition: Grid.h:512
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:826
MetaIterator beginMeta()
Definition: MetaMap.h:84
static Vec3R xyz(const Coord &in_ijk, size_t in_level, size_t out_level)
Return the floating-point index coordinate at out_level given the index coordinate in_xyz at in_level...
Definition: MultiResGrid.h:498
TreeType & tree()
Return a reference to this grid&#39;s tree, which might be shared with other grids.
Definition: Grid.h:905
void setTree(TreeBase::Ptr) override
Associate the given tree with this grid, in place of its existing tree.
Definition: Grid.h:1460
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
typename ManagerT::LeafNodeType::ValueOnCIter VoxelIterT
Definition: MultiResGrid.h:685
std::string getName() const
Return a string with the name of this MultiResGrid.
Definition: MultiResGrid.h:290
void clearGridClass()
Remove the setting specifying the class of this grid&#39;s volumetric data.
Definition: MultiResGrid.h:318
SharedPtr< const Grid > ConstPtr
Definition: Grid.h:575
Definition: MultiResGrid.h:58
Implementation of morphological dilation and erosion.
void prolongateActiveVoxels(size_t destlevel, size_t grainSize=1)
Definition: MultiResGrid.h:585
ValueType restrictVoxel(Coord ijk, const size_t level, bool useInjection=false) const
Definition: MultiResGrid.h:595
MetaMap::Ptr copyMeta() const
Return a copy of this map whose fields are shared with this map.
TypedMetadata< std::string > StringMetadata
Definition: Metadata.h:386
const math::Transform & constTransform() const
Return a reference to the finest grid&#39;s transform, which might be shared with other grids...
Definition: MultiResGrid.h:202
Definition: Exceptions.h:13
SharedPtr< const MetaMap > ConstPtr
Definition: MetaMap.h:23
Definition: Morphology.h:75
math::Vec3< Real > Vec3R
Definition: Types.h:49
TreeType & coarsestTree()
Return a reference to the tree at the coarsest level.
Definition: MultiResGrid.h:149
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) stored in this grid.
Definition: MultiResGrid.h:304
ConstTreePtr coarsestConstTreePtr() const
Return a const shared pointer to the tree at the coarsest level.
Definition: MultiResGrid.h:158
typename Grid< TreeType >::Ptr GridPtr
Definition: MultiResGrid.h:69
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) that is stored in this grid...
void print(std::ostream &os=std::cout, const std::string &indent="") const
Print a description of this transform.
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:82
typename TreeType::ValueType ValueType
Definition: MultiResGrid.h:64
math::Transform & transform()
Return a reference to the finest grid&#39;s transform, which might be shared with other grids...
Definition: MultiResGrid.h:200
TreePtr treePtr(size_t level)
Return a shared pointer to the tree at the specified level.
Definition: MultiResGrid.h:411
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:358
Definition: Types.h:453
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:681
GridType::Ptr createGrid(const typename GridType::ValueType &background)
Create a new grid of type GridType with a given background value.
Definition: Grid.h:1728
GridPtr createGrid(float level, size_t grainSize=1) const
Return a shared pointer to a new grid at the specified floating-point level.
std::vector< GridBase::Ptr > GridPtrVec
Definition: Grid.h:509
TreePtr coarsestTreePtr()
Return a shared pointer to the tree at the coarsest level.
Definition: MultiResGrid.h:155
Definition: Transform.h:39
Type Pow(Type x, int n)
Return xn.
Definition: Math.h:508
std::vector< GridBase::ConstPtr > GridCPtrVec
Definition: Grid.h:514
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
ValueType sampleValue(const Coord &in_ijk, size_t in_level, size_t out_level) const
Return the value at the specified coordinate position using interpolation of the specified order into...
ValueType prolongateVoxel(const Coord &coords, const size_t level) const
Return the value at coordinate location in level tree from the coarser tree at level+1 using trilinea...
Definition: MultiResGrid.h:576
tbb::enumerable_thread_specific< TreeType > PoolType
Definition: MultiResGrid.h:682
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
void setName(const std::string &)
Specify a name for this grid.
void restrictActiveVoxels(size_t destlevel, size_t grainSize=1)
Definition: MultiResGrid.h:606
TypedMetadata< int64_t > Int64Metadata
Definition: Metadata.h:385
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:1047
GridClass
Definition: Types.h:452
const math::Transform & transform() const
Return a reference to the finest grid&#39;s transform, which might be shared with other grids...
Definition: MultiResGrid.h:201
static GridClass stringToGridClass(const std::string &)
Return the class of volumetric data specified by the given string.
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
SharedPtr< GridCPtrVec > GridCPtrVecPtr
Definition: Grid.h:517
A LeafManager manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional au...
const TreeType & coarsestConstTree() const
Return a const reference to the tree at the coarsest level.
Definition: MultiResGrid.h:152
GridPtrVecPtr grids()
Return a shared pointer to a vector of all the base grids in this instance of the MultiResGrid...
Definition: MultiResGrid.h:480
size_t metaCount() const
Definition: MetaMap.h:91
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:266
MultiResGrid(size_t levels, ValueType background, double voxelSize=1.0)
Constructor of empty grids.
Definition: MultiResGrid.h:358
MetaIterator endMeta()
Definition: MetaMap.h:85
typename TreeType::template ValueConverter< ValueMask >::Type MaskT
Definition: MultiResGrid.h:681
static ValueType run(const Coord &ijk, const ConstAccessor &acc)
Interpolate values from a coarse grid (acc) into the index space (ijk) of a fine grid.
Definition: MultiResGrid.h:906
SharedPtr< const Metadata > ConstPtr
Definition: Metadata.h:27
Definition: Types.h:454
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:620
TypedMetadata< float > FloatMetadata
Definition: Metadata.h:383
void setTransform(math::Transform::Ptr)
Associate the given transform with this grid, in place of its existing transform. ...
Definition: Grid.h:1242
SharedPtr< Transform > Ptr
Definition: Transform.h:42