OpenVDB  8.0.1
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
326  using Accessor = tree::ValueAccessor<TreeType, false>;
327  using ConstAccessor = tree::ValueAccessor<const TreeType, false>;
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>
480 grids()
481 {
482  GridPtrVecPtr grids( new GridPtrVec );
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 {
491  GridCPtrVecPtr grids( new GridCPtrVec );
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>
653 void MultiResGrid<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>
841 struct MultiResGrid<TreeType>::CookOp
842 {
843  using ManagerT = tree::LeafManager<TreeType>;
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
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Implementation of morphological dilation and erosion.
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
#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:174
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_END
Definition: Platform.h:175
Defined various multi-threaded utility functions for trees.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
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 setTransform(math::Transform::Ptr)
Associate the given transform with this grid, in place of its existing transform.
Definition: Grid.h:1254
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) that is stored in this grid.
static const char *const META_GRID_NAME
Definition: Grid.h:357
static const char *const META_GRID_CLASS
Definition: Grid.h:355
static GridClass stringToGridClass(const std::string &)
Return the class of volumetric data specified by the given string.
static std::string gridClassToString(GridClass)
Return the metadata string value for the given class of volumetric data.
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:577
void setTree(TreeBase::Ptr) override
Associate the given tree with this grid, in place of its existing tree.
Definition: Grid.h:1480
SharedPtr< const Grid > ConstPtr
Definition: Grid.h:580
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
Definition: Grid.h:917
SharedPtr< Grid > Ptr
Definition: Grid.h:579
static Ptr create()
Return a new grid with background value zero.
Definition: Grid.h:1330
Container that maps names (strings) to values of arbitrary types.
Definition: MetaMap.h:20
SharedPtr< const MetaMap > ConstPtr
Definition: MetaMap.h:23
size_t metaCount() const
Definition: MetaMap.h:91
MetadataMap::const_iterator ConstMetaIterator
Definition: MetaMap.h:28
SharedPtr< MetaMap > Ptr
Definition: MetaMap.h:22
void insertMeta(const Name &, const Metadata &value)
Insert a new metadata field or overwrite the value of an existing field.
SharedPtr< const Metadata > ConstPtr
Definition: Metadata.h:27
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: openvdb/Types.h:542
SharedPtr< const TypedMetadata< T > > ConstPtr
Definition: Metadata.h:125
Definition: openvdb/Exceptions.h:65
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:26
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:92
const Int32 * data() const
Definition: Coord.h:140
Definition: Transform.h:40
SharedPtr< Transform > Ptr
Definition: Transform.h:42
Definition: MultiResGrid.h:59
ValueType restrictVoxel(Coord ijk, const size_t level, bool useInjection=false) const
Definition: MultiResGrid.h:595
void setGridClass(GridClass cls)
Specify the class of volumetric data (level set, fog volume, etc.) stored in this grid.
Definition: MultiResGrid.h:312
typename TreeType::ValueOnIter ValueOnIter
Definition: MultiResGrid.h:66
void prolongateActiveVoxels(size_t destlevel, size_t grainSize=1)
Definition: MultiResGrid.h:585
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...
ConstTreePtr coarsestConstTreePtr() const
Return a const shared pointer to the tree at the coarsest level.
Definition: MultiResGrid.h:158
typename TreeType::ValueType ValueType
Definition: MultiResGrid.h:64
void print(std::ostream &=std::cout, int verboseLevel=1) const
Output a human-readable description of this MultiResGrid.
Definition: MultiResGrid.h:616
TreeType & finestTree()
Return a reference to the tree at the finest level.
Definition: MultiResGrid.h:137
GridPtr grid(size_t level)
Return a shared pointer to the grid at the specified integer level.
Definition: MultiResGrid.h:427
void clearGridClass()
Remove the setting specifying the class of this grid's volumetric data.
Definition: MultiResGrid.h:318
TreeType & tree(size_t level)
Return a reference to the tree at the specified level.
Definition: MultiResGrid.h:395
GridPtrVecPtr grids()
Return a shared pointer to a vector of all the base grids in this instance of the MultiResGrid.
Definition: MultiResGrid.h:480
MultiResGrid(size_t levels, ValueType background, double voxelSize=1.0)
Constructor of empty grids.
Definition: MultiResGrid.h:358
static size_t finestLevel()
Return the level of the finest grid (always 0)
Definition: MultiResGrid.h:109
const math::Transform & transform() const
Definition: MultiResGrid.h:201
const TreeType & finestConstTree() const
Return a const reference to the tree at the finest level.
Definition: MultiResGrid.h:140
size_t coarsestLevel() const
Return the level of the coarsest grid, i.e. numLevels()-1.
Definition: MultiResGrid.h:112
size_t numLevels() const
Return the number of levels, i.e. trees, in this MultiResGrid.
Definition: MultiResGrid.h:106
ConstTreePtr constTreePtr(size_t level) const
Return a const shared pointer to the tree at the specified level.
Definition: MultiResGrid.h:419
ValueType sampleValue(const Vec3R &in_ijk, size_t in_level, size_t out_level) const
std::string getName() const
Return a string with the name of this MultiResGrid.
Definition: MultiResGrid.h:290
ValueType sampleValue(const Coord &ijk, double level) const
Return the value at the specified integer coordinate position and level using interpolation of the sp...
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) stored in this grid.
Definition: MultiResGrid.h:304
typename TreeType::ValueOnCIter ValueOnCIter
Definition: MultiResGrid.h:65
void setName(const std::string &name)
Set the name of this MultiResGrid.
Definition: MultiResGrid.h:297
typename Grid< TreeType >::Ptr GridPtr
Definition: MultiResGrid.h:69
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
const math::Transform & constTransform() const
Definition: MultiResGrid.h:202
typename Grid< TreeType >::ConstPtr ConstGridPtr
Definition: MultiResGrid.h:70
void restrictActiveVoxels(size_t destlevel, size_t grainSize=1)
Definition: MultiResGrid.h:606
const TreeType & coarsestConstTree() const
Return a const reference to the tree at the coarsest level.
Definition: MultiResGrid.h:152
const TreeType & constTree(size_t level) const
Return a const reference to the tree at the specified level.
Definition: MultiResGrid.h:403
ConstTreePtr finestConstTreePtr() const
Return a const shared pointer to the tree at the finest level.
Definition: MultiResGrid.h:146
TreePtr finestTreePtr()
Return a shared pointer to the tree at the finest level.
Definition: MultiResGrid.h:143
typename TreeType::Ptr TreePtr
Definition: MultiResGrid.h:67
GridPtr createGrid(float level, size_t grainSize=1) const
Return a shared pointer to a new grid at the specified floating-point level.
ValueType sampleValue(const Vec3R &xyz, double level) const
Return the value at the specified floating-point coordinate position and level using interpolation of...
TreePtr treePtr(size_t level)
Return a shared pointer to the tree at the specified level.
Definition: MultiResGrid.h:411
TreeType & coarsestTree()
Return a reference to the tree at the coarsest level.
Definition: MultiResGrid.h:149
typename TreeType::ConstPtr ConstTreePtr
Definition: MultiResGrid.h:68
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
TreePtr coarsestTreePtr()
Return a shared pointer to the tree at the coarsest level.
Definition: MultiResGrid.h:155
Definition: LeafManager.h:102
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:345
Definition: ValueAccessor.h:183
void setValueOn(const Coord &xyz, const ValueType &value)
Definition: ValueAccessor.h:255
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:219
void print(const ast::Node &node, const bool numberStatements=true, std::ostream &os=std::cout, const char *indent=" ")
Writes a descriptive printout of a Node hierarchy into a target stream.
void run(const char *ax, openvdb::GridBase &grid)
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
OPENVDB_API uint32_t getGridClass(std::ios_base &)
Return the class (GRID_LEVEL_SET, GRID_UNKNOWN, etc.) of the grid currently being read from or writte...
float Round(float x)
Return x rounded to the nearest integer.
Definition: Math.h:822
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:637
Type Pow(Type x, int n)
Return xn.
Definition: Math.h:564
Type FractionalPart(Type x)
Return the fractional part of x.
Definition: Math.h:846
@ NN_FACE_EDGE_VERTEX
Definition: Morphology.h:60
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
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
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
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
@ EXPAND_TILES
Definition: Morphology.h:75
std::vector< GridBase::Ptr > GridPtrVec
Definition: Grid.h:514
TypedMetadata< float > FloatMetadata
Definition: Metadata.h:360
double Real
Definition: openvdb/Types.h:38
GridClass
Definition: openvdb/Types.h:313
@ GRID_LEVEL_SET
Definition: openvdb/Types.h:315
@ GRID_UNKNOWN
Definition: openvdb/Types.h:314
SharedPtr< GridCPtrVec > GridCPtrVecPtr
Definition: Grid.h:522
SharedPtr< GridPtrVec > GridPtrVecPtr
Definition: Grid.h:517
TypedMetadata< std::string > StringMetadata
Definition: Metadata.h:363
math::Vec3< Real > Vec3R
Definition: openvdb/Types.h:50
std::shared_ptr< T > SharedPtr
Definition: openvdb/Types.h:92
TypedMetadata< int64_t > Int64Metadata
Definition: Metadata.h:362
std::vector< GridBase::ConstPtr > GridCPtrVec
Definition: Grid.h:519
openvdb::GridBase::Ptr GridPtr
Definition: openvdb_houdini/openvdb_houdini/Utils.h:34
Definition: openvdb/Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: openvdb/Exceptions.h:74
Definition: MultiResGrid.h:680
typename ManagerT::LeafNodeType::ValueOnCIter VoxelIterT
Definition: MultiResGrid.h:685
MaskOp(const TreeType &fineTree, TreeType &coarseTree, size_t grainSize=1)
Definition: MultiResGrid.h:687
tbb::enumerable_thread_specific< TreeType > PoolType
Definition: MultiResGrid.h:682
PoolType * mPool
Definition: MultiResGrid.h:718
void operator()(const RangeT &range) const
Definition: MultiResGrid.h:707
typename ManagerT::LeafRange RangeT
Definition: MultiResGrid.h:684
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
static ValueType run(Coord ijk, const ConstAccessor &acc)
Static method that performs restriction by full weighting.
Definition: MultiResGrid.h:873
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.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:101
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:153