OpenVDB  7.2.1
FastSweeping.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
26 
27 #ifndef OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
28 #define OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
29 
30 //#define BENCHMARK_FAST_SWEEPING
31 
32 #include <type_traits>// for static_assert
33 #include <cmath>
34 #include <limits>
35 #include <deque>
36 #include <unordered_map>
37 #include <utility>// for std::make_pair
38 
39 #include <tbb/parallel_for.h>
40 #include <tbb/enumerable_thread_specific.h>
41 #include <tbb/task_group.h>
42 
43 #include <openvdb/math/Math.h> // for Abs() and isExactlyEqual()
44 #include <openvdb/math/Stencils.h> // for GradStencil
46 #include "LevelSetUtil.h"
47 #include "Morphology.h"
48 
49 #include "Statistics.h"
50 #ifdef BENCHMARK_FAST_SWEEPING
51 #include <openvdb/util/CpuTimer.h>
52 #endif
53 
54 namespace openvdb {
56 namespace OPENVDB_VERSION_NAME {
57 namespace tools {
58 
87 template<typename GridT>
88 typename GridT::Ptr
89 fogToSdf(const GridT &fogGrid,
90  typename GridT::ValueType isoValue,
91  int nIter = 1);
92 
120 template<typename GridT>
121 typename GridT::Ptr
122 sdfToSdf(const GridT &sdfGrid,
123  typename GridT::ValueType isoValue = 0,
124  int nIter = 1);
125 
158 template<typename FogGridT, typename ExtOpT, typename ExtValueT>
159 typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
160 fogToExt(const FogGridT &fogGrid,
161  const ExtOpT &op,
162  const ExtValueT& background,
163  typename FogGridT::ValueType isoValue,
164  int nIter = 1);
165 
196 template<typename SdfGridT, typename ExtOpT, typename ExtValueT>
197 typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
198 sdfToExt(const SdfGridT &sdfGrid,
199  const ExtOpT &op,
200  const ExtValueT &background,
201  typename SdfGridT::ValueType isoValue = 0,
202  int nIter = 1);
203 
238 template<typename FogGridT, typename ExtOpT, typename ExtValueT>
239 std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
240 fogToSdfAndExt(const FogGridT &fogGrid,
241  const ExtOpT &op,
242  const ExtValueT &background,
243  typename FogGridT::ValueType isoValue,
244  int nIter = 1);
245 
280 template<typename SdfGridT, typename ExtOpT, typename ExtValueT>
281 std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
282 sdfToSdfAndExt(const SdfGridT &sdfGrid,
283  const ExtOpT &op,
284  const ExtValueT &background,
285  typename SdfGridT::ValueType isoValue = 0,
286  int nIter = 1);
287 
305 template<typename GridT>
306 typename GridT::Ptr
307 dilateSdf(const GridT &sdfGrid,
308  int dilation,
310  int nIter = 1);
311 
330 template<typename GridT, typename MaskTreeT>
331 typename GridT::Ptr
332 maskSdf(const GridT &sdfGrid,
333  const Grid<MaskTreeT> &mask,
334  bool ignoreActiveTiles = false,
335  int nIter = 1);
336 
349 template<typename SdfGridT, typename ExtValueT = typename SdfGridT::ValueType>
351 {
352  static_assert(std::is_floating_point<typename SdfGridT::ValueType>::value,
353  "FastSweeping requires SdfGridT to have floating-point values");
354  // Defined types related to the signed disntance (or fog) grid
355  using SdfValueT = typename SdfGridT::ValueType;
356  using SdfTreeT = typename SdfGridT::TreeType;
357  using SdfAccT = tree::ValueAccessor<SdfTreeT, false>;//don't register accessors
358 
359  // define types related to the extension field
360  using ExtGridT = typename SdfGridT::template ValueConverter<ExtValueT>::Type;
361  using ExtTreeT = typename ExtGridT::TreeType;
363 
364  // define types related to the tree that masks out the active voxels to be solved for
365  using SweepMaskTreeT = typename SdfTreeT::template ValueConverter<ValueMask>::Type;
366  using SweepMaskAccT = tree::ValueAccessor<SweepMaskTreeT, false>;//don't register accessors
367 
368 public:
369 
371  FastSweeping();
372 
374  ~FastSweeping() { this->clear(); }
375 
377  FastSweeping(const FastSweeping&) = delete;
378 
381 
388  typename SdfGridT::Ptr sdfGrid() { return mSdfGrid; }
389 
396  typename ExtGridT::Ptr extGrid() { return mExtGrid; }
397 
418  bool initSdf(const SdfGridT &sdfGrid, SdfValueT isoValue, bool isInputSdf);
419 
448  template <typename ExtOpT>
449  bool initExt(const SdfGridT &sdfGrid, const ExtOpT &op, const ExtValueT &background, SdfValueT isoValue, bool isInputSdf);
450 
466  bool initDilate(const SdfGridT &sdfGrid, int dilation, NearestNeighbors nn = NN_FACE);
467 
486  template<typename MaskTreeT>
487  bool initMask(const SdfGridT &sdfGrid, const Grid<MaskTreeT> &mask, bool ignoreActiveTiles = false);
488 
501  void sweep(int nIter = 1, bool finalize = true);
502 
504  void clear();
505 
507  size_t sweepingVoxelCount() const { return mSweepingVoxelCount; }
508 
510  size_t boundaryVoxelCount() const { return mBoundaryVoxelCount; }
511 
513  bool isValid() const { return mSweepingVoxelCount > 0 && mBoundaryVoxelCount > 0; }
514 
515 private:
516 
518  void computeSweepMaskLeafOrigins();
519 
520  // Private utility classes
521  template<typename>
522  struct MaskKernel;// initialization to extend a SDF into a mask
523  template<typename>
524  struct InitExt;
525  struct InitSdf;
526  struct DilateKernel;// initialization to dilate a SDF
527  struct MinMaxKernel;
528  struct SweepingKernel;// performs the actual concurrent sparse fast sweeping
529 
530  // Define the topology (i.e. stencil) of the neighboring grid points
531  static const Coord mOffset[6];// = {{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}};
532 
533  // Private member data of FastSweeping
534  typename SdfGridT::Ptr mSdfGrid;
535  typename ExtGridT::Ptr mExtGrid;
536  SweepMaskTreeT mSweepMask; // mask tree containing all non-boundary active voxels
537  std::vector<Coord> mSweepMaskLeafOrigins; // cache of leaf node origins for mask tree
538  size_t mSweepingVoxelCount, mBoundaryVoxelCount;
539 };// FastSweeping
540 
542 
543 // Static member data initialization
544 template <typename SdfGridT, typename ExtValueT>
545 const Coord FastSweeping<SdfGridT, ExtValueT>::mOffset[6] = {{-1,0,0},{1,0,0},
546  {0,-1,0},{0,1,0},
547  {0,0,-1},{0,0,1}};
548 
549 template <typename SdfGridT, typename ExtValueT>
551  : mSdfGrid(nullptr), mExtGrid(nullptr), mSweepingVoxelCount(0), mBoundaryVoxelCount(0)
552 {
553 }
554 
555 template <typename SdfGridT, typename ExtValueT>
557 {
558  mSdfGrid.reset();
559  mExtGrid.reset();
560  mSweepMask.clear();
561  mSweepingVoxelCount = mBoundaryVoxelCount = 0;
562 }
563 
564 template <typename SdfGridT, typename ExtValueT>
566 {
567  // replace any inactive leaf nodes with tiles and voxelize any active tiles
568 
569  pruneInactive(mSweepMask);
570  mSweepMask.voxelizeActiveTiles();
571 
572  using LeafManagerT = tree::LeafManager<SweepMaskTreeT>;
573  using LeafT = typename SweepMaskTreeT::LeafNodeType;
574  LeafManagerT leafManager(mSweepMask);
575 
576  mSweepMaskLeafOrigins.resize(leafManager.leafCount());
577  tbb::atomic<size_t> sweepingVoxelCount = 0;
578  auto kernel = [&](const LeafT& leaf, size_t leafIdx) {
579  mSweepMaskLeafOrigins[leafIdx] = leaf.origin();
580  sweepingVoxelCount += leaf.onVoxelCount();
581  };
582  leafManager.foreach(kernel, /*threaded=*/true, /*grainsize=*/1024);
583 
584  mBoundaryVoxelCount = 0;
585  mSweepingVoxelCount = sweepingVoxelCount;
586  if (mSdfGrid) {
587  const size_t totalCount = mSdfGrid->constTree().activeVoxelCount();
588  assert( totalCount >= mSweepingVoxelCount );
589  mBoundaryVoxelCount = totalCount - mSweepingVoxelCount;
590  }
591 }// FastSweeping::computeSweepMaskLeafOrigins
592 
593 template <typename SdfGridT, typename ExtValueT>
594 bool FastSweeping<SdfGridT, ExtValueT>::initSdf(const SdfGridT &fogGrid, SdfValueT isoValue, bool isInputSdf)
595 {
596  this->clear();
597  mSdfGrid = fogGrid.deepCopy();//very fast
598  InitSdf kernel(*this);
599  kernel.run(isoValue, isInputSdf);
600  return this->isValid();
601 }
602 
603 template <typename SdfGridT, typename ExtValueT>
604 template <typename OpT>
605 bool FastSweeping<SdfGridT, ExtValueT>::initExt(const SdfGridT &fogGrid, const OpT &op, const ExtValueT &background, SdfValueT isoValue, bool isInputSdf)
606 {
607  this->clear();
608  mSdfGrid = fogGrid.deepCopy();//very fast
609  mExtGrid = createGrid<ExtGridT>( background );
610  mExtGrid->topologyUnion( *mSdfGrid );//very fast
611  InitExt<OpT> kernel(*this);
612  kernel.run(isoValue, op, isInputSdf);
613  return this->isValid();
614 }
615 
616 template <typename SdfGridT, typename ExtValueT>
617 bool FastSweeping<SdfGridT, ExtValueT>::initDilate(const SdfGridT &sdfGrid, int dilate, NearestNeighbors nn)
618 {
619  this->clear();
620  mSdfGrid = sdfGrid.deepCopy();//very fast
621  DilateKernel kernel(*this);
622  kernel.run(dilate, nn);
623  return this->isValid();
624 }
625 
626 template <typename SdfGridT, typename ExtValueT>
627 template<typename MaskTreeT>
628 bool FastSweeping<SdfGridT, ExtValueT>::initMask(const SdfGridT &sdfGrid, const Grid<MaskTreeT> &mask, bool ignoreActiveTiles)
629 {
630  this->clear();
631  mSdfGrid = sdfGrid.deepCopy();//very fast
632 
633  if (mSdfGrid->transform() != mask.transform()) {
634  OPENVDB_THROW(RuntimeError, "FastSweeping: Mask not aligned with the grid!");
635  }
636 
637  if (mask.getGridClass() == GRID_LEVEL_SET) {
638  using T = typename MaskTreeT::template ValueConverter<bool>::Type;
639  typename Grid<T>::Ptr tmp = sdfInteriorMask(mask);//might have active tiles
640  tmp->tree().voxelizeActiveTiles();//multi-threaded
641  MaskKernel<T> kernel(*this);
642  kernel.run(tmp->tree());//multi-threaded
643  } else {
644  if (ignoreActiveTiles || !mask.tree().hasActiveTiles()) {
645  MaskKernel<MaskTreeT> kernel(*this);
646  kernel.run(mask.tree());//multi-threaded
647  } else {
648  using T = typename MaskTreeT::template ValueConverter<ValueMask>::Type;
649  T tmp(mask.tree(), false, TopologyCopy());//multi-threaded
650  tmp.voxelizeActiveTiles(true);//multi-threaded
651  MaskKernel<T> kernel(*this);
652  kernel.run(tmp);//multi-threaded
653  }
654  }
655  return this->isValid();
656 }// FastSweeping::initMask
657 
658 template <typename SdfGridT, typename ExtValueT>
659 void FastSweeping<SdfGridT, ExtValueT>::sweep(int nIter, bool finalize)
660 {
661  if (!mSdfGrid) {
662  OPENVDB_THROW(RuntimeError, "FastSweeping::sweep called before initialization");
663  }
664  if (this->boundaryVoxelCount() == 0) {
665  OPENVDB_THROW(RuntimeError, "FastSweeping: No boundary voxels found!");
666  } else if (this->sweepingVoxelCount() == 0) {
667  OPENVDB_THROW(RuntimeError, "FastSweeping: No computing voxels found!");
668  }
669 
670  // note: SweepingKernel is non copy-constructible, so use a deque instead of a vector
671  std::deque<SweepingKernel> kernels;
672  for (int i = 0; i < 4; i++) kernels.emplace_back(*this);
673 
674  { // compute voxel slices
675 #ifdef BENCHMARK_FAST_SWEEPING
676  util::CpuTimer timer("Computing voxel slices");
677 #endif
678 
679  // Exploiting nested parallelism - all voxel slice data is precomputed
680  tbb::task_group tasks;
681  tasks.run([&] { kernels[0].computeVoxelSlices([](const Coord &a){ return a[0]+a[1]+a[2]; });/*+++ & ---*/ });
682  tasks.run([&] { kernels[1].computeVoxelSlices([](const Coord &a){ return a[0]+a[1]-a[2]; });/*++- & --+*/ });
683  tasks.run([&] { kernels[2].computeVoxelSlices([](const Coord &a){ return a[0]-a[1]+a[2]; });/*+-+ & -+-*/ });
684  tasks.run([&] { kernels[3].computeVoxelSlices([](const Coord &a){ return a[0]-a[1]-a[2]; });/*+-- & -++*/ });
685  tasks.wait();
686 
687 #ifdef BENCHMARK_FAST_SWEEPING
688  timer.stop();
689 #endif
690  }
691 
692  // perform nIter iterations of bi-directional sweeping in all directions
693  for (int i = 0; i < nIter; ++i) {
694  for (SweepingKernel& kernel : kernels) kernel.sweep();
695  }
696 
697  if (finalize) {
698 #ifdef BENCHMARK_FAST_SWEEPING
699  util::CpuTimer timer("Computing extrema values");
700 #endif
701  MinMaxKernel kernel;
702  auto e = kernel.run(*mSdfGrid);//multi-threaded
703  //auto e = extrema(mGrid->beginValueOn());// 100x slower!!!!
704 #ifdef BENCHMARK_FAST_SWEEPING
705  std::cerr << "Min = " << e.min() << " Max = " << e.max() << std::endl;
706  timer.restart("Changing asymmetric background value");
707 #endif
708  changeAsymmetricLevelSetBackground(mSdfGrid->tree(), e.max(), e.min());//multi-threaded
709 
710 #ifdef BENCHMARK_FAST_SWEEPING
711  timer.stop();
712 #endif
713  }
714 }// FastSweeping::sweep
715 
719 template <typename SdfGridT, typename ExtValueT>
720 struct FastSweeping<SdfGridT, ExtValueT>::MinMaxKernel
721 {
723  using LeafRange = typename LeafMgr::LeafRange;
724  MinMaxKernel() : mMin(std::numeric_limits<SdfValueT>::max()), mMax(-mMin) {}
725  MinMaxKernel(MinMaxKernel& other, tbb::split) : mMin(other.mMin), mMax(other.mMax) {}
726 
727  math::MinMax<SdfValueT> run(const SdfGridT &grid)
728  {
729  LeafMgr mgr(grid.tree());// super fast
730  tbb::parallel_reduce(mgr.leafRange(), *this);
731  return math::MinMax<SdfValueT>(mMin, mMax);
732  }
733 
734  void operator()(const LeafRange& r)
735  {
736  for (auto leafIter = r.begin(); leafIter; ++leafIter) {
737  for (auto voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
738  const SdfValueT v = *voxelIter;
739  if (v < mMin) mMin = v;
740  if (v > mMax) mMax = v;
741  }
742  }
743  }
744 
745  void join(const MinMaxKernel& other)
746  {
747  if (other.mMin < mMin) mMin = other.mMin;
748  if (other.mMax > mMax) mMax = other.mMax;
749  }
750 
751  SdfValueT mMin, mMax;
752 };// FastSweeping::MinMaxKernel
753 
755 
757 template <typename SdfGridT, typename ExtValueT>
758 struct FastSweeping<SdfGridT, ExtValueT>::DilateKernel
759 {
762  : mParent(&parent), mBackground(parent.mSdfGrid->background())
763  {
764  }
765  DilateKernel(const DilateKernel &parent) = default;// for tbb::parallel_for
767 
768  void run(int dilation, NearestNeighbors nn)
769  {
770 #ifdef BENCHMARK_FAST_SWEEPING
771  util::CpuTimer timer("Construct LeafManager");
772 #endif
773  tree::LeafManager<SdfTreeT> mgr(mParent->mSdfGrid->tree());// super fast
774 
775 #ifdef BENCHMARK_FAST_SWEEPING
776  timer.restart("Changing background value");
777 #endif
778  static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
779  changeLevelSetBackground(mgr, Unknown);//multi-threaded
780 
781  #ifdef BENCHMARK_FAST_SWEEPING
782  timer.restart("Dilating and updating mgr (parallel)");
783  //timer.restart("Dilating and updating mgr (serial)");
784 #endif
785 
786  const int delta = 5;
787  for (int i=0, d = dilation/delta; i<d; ++i) dilateActiveValues(mgr, delta, nn, IGNORE_TILES);
788  dilateActiveValues(mgr, dilation % delta, nn, IGNORE_TILES);
789  //for (int i=0, n=5, d=dilation/n; i<d; ++i) dilateActiveValues(mgr, n, nn, IGNORE_TILES);
790  //dilateVoxels(mgr, dilation, nn);
791 
792 #ifdef BENCHMARK_FAST_SWEEPING
793  timer.restart("Initializing grid and sweep mask");
794 #endif
795 
796  mParent->mSweepMask.clear();
797  mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
798 
800  using LeafT = typename SdfGridT::TreeType::LeafNodeType;
801  LeafManagerT leafManager(mParent->mSdfGrid->tree());
802 
803  auto kernel = [&](LeafT& leaf, size_t /*leafIdx*/) {
804  static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
805  const SdfValueT background = mBackground;//local copy
806  auto* maskLeaf = mParent->mSweepMask.probeLeaf(leaf.origin());
807  assert(maskLeaf);
808  for (auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
809  const SdfValueT value = *voxelIter;
810  if (math::Abs(value) < background) {// disable boundary voxels from the mask tree
811  maskLeaf->setValueOff(voxelIter.pos());
812  } else {
813  voxelIter.setValue(value > 0 ? Unknown : -Unknown);
814  }
815  }
816  };
817 
818  leafManager.foreach( kernel );
819 
820  // cache the leaf node origins for fast lookup in the sweeping kernels
821 
822  mParent->computeSweepMaskLeafOrigins();
823 
824 #ifdef BENCHMARK_FAST_SWEEPING
825  timer.stop();
826 #endif
827  }// FastSweeping::DilateKernel::run
828 
829  // Private member data of DilateKernel
831  const SdfValueT mBackground;
832 };// FastSweeping::DilateKernel
833 
835 template <typename SdfGridT, typename ExtValueT>
836 struct FastSweeping<SdfGridT, ExtValueT>::InitSdf
837 {
839  InitSdf(FastSweeping &parent): mParent(&parent),
840  mSdfGrid(parent.mSdfGrid.get()), mIsoValue(0), mAboveSign(0) {}
841  InitSdf(const InitSdf&) = default;// for tbb::parallel_for
842  InitSdf& operator=(const InitSdf&) = delete;
843 
844  void run(SdfValueT isoValue, bool isInputSdf)
845  {
846  mIsoValue = isoValue;
847  mAboveSign = isInputSdf ? SdfValueT(1) : SdfValueT(-1);
848  SdfTreeT &tree = mSdfGrid->tree();//sdf
849  const bool hasActiveTiles = tree.hasActiveTiles();
850 
851  if (isInputSdf && hasActiveTiles) {
852  OPENVDB_THROW(RuntimeError, "FastSweeping: A SDF should not have active tiles!");
853  }
854 
855 #ifdef BENCHMARK_FAST_SWEEPING
856  util::CpuTimer timer("Initialize voxels");
857 #endif
858  mParent->mSweepMask.clear();
859  mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
860 
861  {// Process all voxels
862  tree::LeafManager<SdfTreeT> mgr(tree, 1);// we need one auxiliary buffer
863  tbb::parallel_for(mgr.leafRange(32), *this);//multi-threaded
864  mgr.swapLeafBuffer(1);//swap voxel values
865  }
866 
867 #ifdef BENCHMARK_FAST_SWEEPING
868  timer.restart("Initialize tiles - new");
869 #endif
870  // Process all tiles
871  tree::NodeManager<SdfTreeT, SdfTreeT::RootNodeType::LEVEL-1> mgr(tree);
872  mgr.foreachBottomUp(*this);//multi-threaded
873  tree.root().setBackground(std::numeric_limits<SdfValueT>::max(), false);
874  if (hasActiveTiles) tree.voxelizeActiveTiles();//multi-threaded
875 
876  // cache the leaf node origins for fast lookup in the sweeping kernels
877 
878  mParent->computeSweepMaskLeafOrigins();
879  }// FastSweeping::InitSdf::run
880 
881  void operator()(const LeafRange& r) const
882  {
883  SweepMaskAccT sweepMaskAcc(mParent->mSweepMask);
884  math::GradStencil<SdfGridT, false> stencil(*mSdfGrid);
885  const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();//local copy
886  const SdfValueT h = mAboveSign*static_cast<SdfValueT>(mSdfGrid->voxelSize()[0]);//Voxel size
887  for (auto leafIter = r.begin(); leafIter; ++leafIter) {
888  SdfValueT* sdf = leafIter.buffer(1).data();
889  for (auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
890  const SdfValueT value = *voxelIter;
891  const bool isAbove = value > isoValue;
892  if (!voxelIter.isValueOn()) {// inactive voxels
893  sdf[voxelIter.pos()] = isAbove ? above : -above;
894  } else {// active voxels
895  const Coord ijk = voxelIter.getCoord();
896  stencil.moveTo(ijk, value);
897  const auto mask = stencil.intersectionMask( isoValue );
898  if (mask.none()) {// most common case
899  sdf[voxelIter.pos()] = isAbove ? above : -above;
900  } else {// compute distance to iso-surface
901  // disable boundary voxels from the mask tree
902  sweepMaskAcc.setValueOff(ijk);
903  const SdfValueT delta = value - isoValue;//offset relative to iso-value
904  if (math::isApproxZero(delta)) {//voxel is on the iso-surface
905  sdf[voxelIter.pos()] = 0;
906  } else {//voxel is neighboring the iso-surface
907  SdfValueT sum = 0;
908  for (int i=0; i<6;) {
909  SdfValueT d = std::numeric_limits<SdfValueT>::max(), d2;
910  if (mask.test(i++)) d = math::Abs(delta/(value-stencil.getValue(i)));
911  if (mask.test(i++)) {
912  d2 = math::Abs(delta/(value-stencil.getValue(i)));
913  if (d2 < d) d = d2;
914  }
915  if (d < std::numeric_limits<SdfValueT>::max()) sum += 1/(d*d);
916  }
917  sdf[voxelIter.pos()] = isAbove ? h / math::Sqrt(sum) : -h / math::Sqrt(sum);
918  }// voxel is neighboring the iso-surface
919  }// intersecting voxels
920  }// active voxels
921  }// loop over voxels
922  }// loop over leaf nodes
923  }// FastSweeping::InitSdf::operator(const LeafRange&)
924 
925  template<typename RootOrInternalNodeT>
926  void operator()(const RootOrInternalNodeT& node) const
927  {
928  const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();
929  for (auto it = node.cbeginValueAll(); it; ++it) {
930  SdfValueT& v = const_cast<SdfValueT&>(*it);
931  v = v > isoValue ? above : -above;
932  }//loop over all tiles
933  }// FastSweeping::InitSdf::operator()(const RootOrInternalNodeT&)
934 
935  // Public member data
937  SdfGridT *mSdfGrid;//raw pointer, i.e. lock free
938  SdfValueT mIsoValue;
939  SdfValueT mAboveSign;//sign of distance values above the iso-value
940 };// FastSweeping::InitSdf
941 
943 template <typename SdfGridT, typename ExtValueT>
944 template <typename OpT>
945 struct FastSweeping<SdfGridT, ExtValueT>::InitExt
946 {
947  using LeafRange = typename tree::LeafManager<SdfTreeT>::LeafRange;
948  using OpPoolT = tbb::enumerable_thread_specific<OpT>;
949  InitExt(FastSweeping &parent) : mParent(&parent),
950  mOpPool(nullptr), mSdfGrid(parent.mSdfGrid.get()),
951  mExtGrid(parent.mExtGrid.get()), mIsoValue(0), mAboveSign(0) {}
952  InitExt(const InitExt&) = default;// for tbb::parallel_for
953  InitExt& operator=(const InitExt&) = delete;
954  void run(SdfValueT isoValue, const OpT &opPrototype, bool isInputSdf)
955  {
956  static_assert(std::is_convertible<decltype(opPrototype(Vec3d(0))),ExtValueT>::value, "Invalid return type of functor");
957  if (!mExtGrid) {
958  OPENVDB_THROW(RuntimeError, "FastSweeping::InitExt expected an extension grid!");
959  }
960 
961  mAboveSign = isInputSdf ? SdfValueT(1) : SdfValueT(-1);
962  mIsoValue = isoValue;
963  auto &tree1 = mSdfGrid->tree();
964  auto &tree2 = mExtGrid->tree();
965  const bool hasActiveTiles = tree1.hasActiveTiles();//very fast
966 
967  if (isInputSdf && hasActiveTiles) {
968  OPENVDB_THROW(RuntimeError, "FastSweeping: A SDF should not have active tiles!");
969  }
970 
971 #ifdef BENCHMARK_FAST_SWEEPING
972  util::CpuTimer timer("Initialize voxels");
973 #endif
974 
975  mParent->mSweepMask.clear();
976  mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
977 
978  {// Process all voxels
979  // Define thread-local operators
980  OpPoolT opPool(opPrototype);
981  mOpPool = &opPool;
982 
983  tree::LeafManager<SdfTreeT> mgr(tree1, 1);// we need one auxiliary buffer
984  tbb::parallel_for(mgr.leafRange(32), *this);//multi-threaded
985  mgr.swapLeafBuffer(1);//swap out auxiliary buffer
986  }
987 
988 #ifdef BENCHMARK_FAST_SWEEPING
989  timer.restart("Initialize tiles");
990 #endif
991  {// Process all tiles
992  tree::NodeManager<SdfTreeT, SdfTreeT::RootNodeType::LEVEL-1> mgr(tree1);
993  mgr.foreachBottomUp(*this);//multi-threaded
994  tree1.root().setBackground(std::numeric_limits<SdfValueT>::max(), false);
995  if (hasActiveTiles) {
996 #ifdef BENCHMARK_FAST_SWEEPING
997  timer.restart("Voxelizing active tiles");
998 #endif
999  tree1.voxelizeActiveTiles();//multi-threaded
1000  tree2.voxelizeActiveTiles();//multi-threaded
1001  }
1002  }
1003 
1004  // cache the leaf node origins for fast lookup in the sweeping kernels
1005 
1006  mParent->computeSweepMaskLeafOrigins();
1007 
1008 #ifdef BENCHMARK_FAST_SWEEPING
1009  timer.stop();
1010 #endif
1011  }// FastSweeping::InitExt::run
1012 
1013  void operator()(const LeafRange& r) const
1014  {
1015  ExtAccT acc(mExtGrid->tree());
1016  SweepMaskAccT sweepMaskAcc(mParent->mSweepMask);
1017  math::GradStencil<SdfGridT, false> stencil(*mSdfGrid);
1018  const math::Transform& xform = mExtGrid->transform();
1019  typename OpPoolT::reference op = mOpPool->local();
1020  const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();//local copy
1021  const SdfValueT h = mAboveSign*static_cast<SdfValueT>(mSdfGrid->voxelSize()[0]);//Voxel size
1022  for (auto leafIter = r.begin(); leafIter; ++leafIter) {
1023  SdfValueT *sdf = leafIter.buffer(1).data();
1024  ExtValueT *ext = acc.probeLeaf(leafIter->origin())->buffer().data();//should be safe!
1025  for (auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1026  const SdfValueT value = *voxelIter;
1027  const bool isAbove = value > isoValue;
1028  if (!voxelIter.isValueOn()) {// inactive voxels
1029  sdf[voxelIter.pos()] = isAbove ? above : -above;
1030  } else {// active voxels
1031  const Coord ijk = voxelIter.getCoord();
1032  stencil.moveTo(ijk, value);
1033  const auto mask = stencil.intersectionMask( isoValue );
1034  if (mask.none()) {// no zero-crossing neighbors, most common case
1035  sdf[voxelIter.pos()] = isAbove ? above : -above;
1036  // the ext grid already has its active values set to the bakground value
1037  } else {// compute distance to iso-surface
1038  // disable boundary voxels from the mask tree
1039  sweepMaskAcc.setValueOff(ijk);
1040  const SdfValueT delta = value - isoValue;//offset relative to iso-value
1041  if (math::isApproxZero(delta)) {//voxel is on the iso-surface
1042  sdf[voxelIter.pos()] = 0;
1043  ext[voxelIter.pos()] = ExtValueT(op(xform.indexToWorld(ijk)));
1044  } else {//voxel is neighboring the iso-surface
1045  SdfValueT sum1 = 0;
1046  ExtValueT sum2 = zeroVal<ExtValueT>();
1047  for (int n=0, i=0; i<6;) {
1048  SdfValueT d = std::numeric_limits<SdfValueT>::max(), d2;
1049  if (mask.test(i++)) {
1050  d = math::Abs(delta/(value-stencil.getValue(i)));
1051  n = i - 1;
1052  }
1053  if (mask.test(i++)) {
1054  d2 = math::Abs(delta/(value-stencil.getValue(i)));
1055  if (d2 < d) {
1056  d = d2;
1057  n = i - 1;
1058  }
1059  }
1061  d2 = 1/(d*d);
1062  sum1 += d2;
1063  const Vec3R xyz(static_cast<SdfValueT>(ijk[0])+d*static_cast<SdfValueT>(FastSweeping::mOffset[n][0]),
1064  static_cast<SdfValueT>(ijk[1])+d*static_cast<SdfValueT>(FastSweeping::mOffset[n][1]),
1065  static_cast<SdfValueT>(ijk[2])+d*static_cast<SdfValueT>(FastSweeping::mOffset[n][2]));
1066  sum2 += d2*ExtValueT(op(xform.indexToWorld(xyz)));
1067  }
1068  }//look over six cases
1069  ext[voxelIter.pos()] = (SdfValueT(1) / sum1) * sum2;
1070  sdf[voxelIter.pos()] = isAbove ? h / math::Sqrt(sum1) : -h / math::Sqrt(sum1);
1071  }// voxel is neighboring the iso-surface
1072  }// intersecting voxels
1073  }// active voxels
1074  }// loop over voxels
1075  }// loop over leaf nodes
1076  }// FastSweeping::InitExt::operator(const LeafRange& r)
1077 
1078  template<typename RootOrInternalNodeT>
1079  void operator()(const RootOrInternalNodeT& node) const
1080  {
1081  const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();
1082  for (auto it = node.cbeginValueAll(); it; ++it) {
1083  SdfValueT& v = const_cast<SdfValueT&>(*it);
1084  v = v > isoValue ? above : -above;
1085  }//loop over all tiles
1086  }
1087  // Public member data
1088  FastSweeping *mParent;
1089  OpPoolT *mOpPool;
1090  SdfGridT *mSdfGrid;
1091  ExtGridT *mExtGrid;
1092  SdfValueT mIsoValue;
1093  SdfValueT mAboveSign;//sign of distance values above the iso-value
1094 };// FastSweeping::InitExt
1095 
1097 template <typename SdfGridT, typename ExtValueT>
1098 template <typename MaskTreeT>
1099 struct FastSweeping<SdfGridT, ExtValueT>::MaskKernel
1100 {
1101  using LeafRange = typename tree::LeafManager<const MaskTreeT>::LeafRange;
1102  MaskKernel(FastSweeping &parent) : mParent(&parent),
1103  mSdfGrid(parent.mSdfGrid.get()) {}
1104  MaskKernel(const MaskKernel &parent) = default;// for tbb::parallel_for
1105  MaskKernel& operator=(const MaskKernel&) = delete;
1106 
1107  void run(const MaskTreeT &mask)
1108  {
1109 #ifdef BENCHMARK_FAST_SWEEPING
1110  util::CpuTimer timer;
1111 #endif
1112  auto &lsTree = mSdfGrid->tree();
1113 
1114  static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
1115 
1116 #ifdef BENCHMARK_FAST_SWEEPING
1117  timer.restart("Changing background value");
1118 #endif
1119  changeLevelSetBackground(lsTree, Unknown);//multi-threaded
1120 
1121 #ifdef BENCHMARK_FAST_SWEEPING
1122  timer.restart("Union with mask");//multi-threaded
1123 #endif
1124  lsTree.topologyUnion(mask);//multi-threaded
1125 
1126  // ignore active tiles since the input grid is assumed to be a level set
1127  tree::LeafManager<const MaskTreeT> mgr(mask);// super fast
1128 
1129 #ifdef BENCHMARK_FAST_SWEEPING
1130  timer.restart("Initializing grid and sweep mask");
1131 #endif
1132 
1133  mParent->mSweepMask.clear();
1134  mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1135 
1136  using LeafManagerT = tree::LeafManager<SweepMaskTreeT>;
1137  using LeafT = typename SweepMaskTreeT::LeafNodeType;
1138  LeafManagerT leafManager(mParent->mSweepMask);
1139 
1140  auto kernel = [&](LeafT& leaf, size_t /*leafIdx*/) {
1141  static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
1142  SdfAccT acc(mSdfGrid->tree());
1143  // The following hack is safe due to the topoloyUnion in
1144  // init and the fact that SdfValueT is known to be a floating point!
1145  SdfValueT *data = acc.probeLeaf(leaf.origin())->buffer().data();
1146  for (auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {// mask voxels
1147  if (math::Abs( data[voxelIter.pos()] ) < Unknown ) {
1148  // disable boundary voxels from the mask tree
1149  voxelIter.setValue(false);
1150  }
1151  }
1152  };
1153  leafManager.foreach( kernel );
1154 
1155  // cache the leaf node origins for fast lookup in the sweeping kernels
1156  mParent->computeSweepMaskLeafOrigins();
1157 
1158 #ifdef BENCHMARK_FAST_SWEEPING
1159  timer.stop();
1160 #endif
1161  }// FastSweeping::MaskKernel::run
1162 
1163  // Private member data of MaskKernel
1164  FastSweeping *mParent;
1165  SdfGridT *mSdfGrid;//raw pointer, i.e. lock free
1166 };// FastSweeping::MaskKernel
1167 
1169 template <typename SdfGridT, typename ExtValueT>
1170 struct FastSweeping<SdfGridT, ExtValueT>::SweepingKernel
1171 {
1172  SweepingKernel(FastSweeping &parent) : mParent(&parent) {}
1173  SweepingKernel(const SweepingKernel&) = delete;
1175 
1177  template<typename HashOp>
1178  void computeVoxelSlices(HashOp hash)
1179  {
1180 #ifdef BENCHMARK_FAST_SWEEPING
1181  util::CpuTimer timer;
1182 #endif
1183 
1184  // mask of the active voxels to be solved for, i.e. excluding boundary voxels
1185  const SweepMaskTreeT& maskTree = mParent->mSweepMask;
1186 
1187  using LeafManagerT = typename tree::LeafManager<const SweepMaskTreeT>;
1188  using LeafT = typename SweepMaskTreeT::LeafNodeType;
1189  LeafManagerT leafManager(maskTree);
1190 
1191  // compute the leaf node slices that have active voxels in them
1192  // the sliding window of the has keys is -14 to 21 (based on an 8x8x8 leaf node
1193  // and the extrema hash values i-j-k and i+j+k), but we use a larger mask window here to
1194  // easily accomodate any leaf dimension. The mask offset is used to be able to
1195  // store this in a fixed-size byte array
1196  constexpr int maskOffset = LeafT::DIM * 3;
1197  constexpr int maskRange = maskOffset * 2;
1198 
1199  // mark each possible slice in each leaf node that has one or more active voxels in it
1200  std::vector<int8_t> leafSliceMasks(leafManager.leafCount()*maskRange);
1201  auto kernel1 = [&](const LeafT& leaf, size_t leafIdx) {
1202  const size_t leafOffset = leafIdx * maskRange;
1203  for (auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1204  const Coord ijk = LeafT::offsetToLocalCoord(voxelIter.pos());
1205  leafSliceMasks[leafOffset + hash(ijk) + maskOffset] = uint8_t(1);
1206  }
1207  };
1208  leafManager.foreach( kernel1 );
1209 
1210  // compute the voxel slice map using a thread-local-storage hash map
1211  // the key of the hash map is the slice index of the voxel coord (ijk.x() + ijk.y() + ijk.z())
1212  // the values are an array of indices for every leaf that has active voxels with this slice index
1213  using ThreadLocalMap = std::unordered_map</*voxelSliceKey=*/int64_t, /*leafIdx=*/std::deque<size_t>>;
1214  tbb::enumerable_thread_specific<ThreadLocalMap> pool;
1215  auto kernel2 = [&](const LeafT& leaf, size_t leafIdx) {
1216  ThreadLocalMap& map = pool.local();
1217  const Coord& origin = leaf.origin();
1218  const int64_t leafKey = hash(origin);
1219  const size_t leafOffset = leafIdx * maskRange;
1220  for (int sliceIdx = 0; sliceIdx < maskRange; sliceIdx++) {
1221  if (leafSliceMasks[leafOffset + sliceIdx] == uint8_t(1)) {
1222  const int64_t voxelSliceKey = leafKey+sliceIdx-maskOffset;
1223  map[voxelSliceKey].emplace_back(leafIdx);
1224  }
1225  }
1226  };
1227  leafManager.foreach( kernel2 );
1228 
1229  // combine into a single ordered map keyed by the voxel slice key
1230  // note that this is now stored in a map ordered by voxel slice key,
1231  // so sweep slices can be processed in order
1232  for (auto poolIt = pool.begin(); poolIt != pool.end(); ++poolIt) {
1233  const ThreadLocalMap& map = *poolIt;
1234  for (const auto& it : map) {
1235  for (const size_t leafIdx : it.second) {
1236  mVoxelSliceMap[it.first].emplace_back(leafIdx, NodeMaskPtrT());
1237  }
1238  }
1239  }
1240 
1241  // extract the voxel slice keys for random access into the map
1242  mVoxelSliceKeys.reserve(mVoxelSliceMap.size());
1243  for (const auto& it : mVoxelSliceMap) {
1244  mVoxelSliceKeys.push_back(it.first);
1245  }
1246 
1247  // allocate the node masks in parallel, as the map is populated in serial
1248  auto kernel3 = [&](tbb::blocked_range<size_t>& range) {
1249  for (size_t i = range.begin(); i < range.end(); i++) {
1250  const int64_t key = mVoxelSliceKeys[i];
1251  for (auto& it : mVoxelSliceMap[key]) {
1252  it.second = std::make_unique<NodeMaskT>();
1253  }
1254  }
1255  };
1256  tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel3);
1257 
1258  // each voxel slice contains a leafIdx-nodeMask pair,
1259  // this routine populates these node masks to select only the active voxels
1260  // from the mask tree that have the same voxel slice key
1261  // TODO: a small optimization here would be to union this leaf node mask with
1262  // a pre-computed one for this particular slice pattern
1263  auto kernel4 = [&](tbb::blocked_range<size_t>& range) {
1264  for (size_t i = range.begin(); i < range.end(); i++) {
1265  const int64_t voxelSliceKey = mVoxelSliceKeys[i];
1266  LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceKey];
1267  for (LeafSlice& leafSlice : leafSliceArray) {
1268  const size_t leafIdx = leafSlice.first;
1269  NodeMaskPtrT& nodeMask = leafSlice.second;
1270  const LeafT& leaf = leafManager.leaf(leafIdx);
1271  const Coord& origin = leaf.origin();
1272  const int64_t leafKey = hash(origin);
1273  for (auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1274  const Index voxelIdx = voxelIter.pos();
1275  const Coord ijk = LeafT::offsetToLocalCoord(voxelIdx);
1276  const int64_t key = leafKey + hash(ijk);
1277  if (key == voxelSliceKey) {
1278  nodeMask->setOn(voxelIdx);
1279  }
1280  }
1281  }
1282  }
1283  };
1284  tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel4);
1285  }// FastSweeping::SweepingKernel::computeVoxelSlices
1286 
1287  // Private struct for nearest neighbor grid points (very memory light!)
1288  struct NN {
1289  SdfValueT v;
1290  int n;
1291  inline static Coord ijk(const Coord &p, int i) { return p + FastSweeping::mOffset[i]; }
1292  NN() : v(), n() {}
1293  NN(const SdfAccT &a, const Coord &p, int i) : v(math::Abs(a.getValue(ijk(p,i)))), n(i) {}
1294  inline Coord operator()(const Coord &p) const { return ijk(p, n); }
1295  inline bool operator<(const NN &rhs) const { return v < rhs.v; }
1296  inline operator bool() const { return v < SdfValueT(1000); }
1297  };// NN
1298 
1299  void sweep()
1300  {
1301  typename ExtGridT::TreeType *tree2 = mParent->mExtGrid ? &mParent->mExtGrid->tree() : nullptr;
1302 
1303  const SdfValueT h = static_cast<SdfValueT>(mParent->mSdfGrid->voxelSize()[0]);
1304  const SdfValueT sqrt2h = math::Sqrt(SdfValueT(2))*h;
1305 
1306  const std::vector<Coord>& leafNodeOrigins = mParent->mSweepMaskLeafOrigins;
1307 
1308  int64_t voxelSliceIndex(0);
1309 
1310  auto kernel = [&](const tbb::blocked_range<size_t>& range) {
1311  using LeafT = typename SdfGridT::TreeType::LeafNodeType;
1312 
1313  SdfAccT acc1(mParent->mSdfGrid->tree());
1314  auto acc2 = std::unique_ptr<ExtAccT>(tree2 ? new ExtAccT(*tree2) : nullptr);
1315  SdfValueT absV, sign, update, D;
1316  NN d1, d2, d3;//distance values and coordinates of closest neighbor points
1317 
1318  const LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceIndex];
1319 
1320  // Solves Goudonov's scheme: [x-d1]^2 + [x-d2]^2 + [x-d3]^2 = h^2
1321  // where [X] = (X>0?X:0) and ai=min(di+1,di-1)
1322  for (size_t i = range.begin(); i < range.end(); ++i) {
1323 
1324  // iterate over all leafs in the slice and extract the leaf
1325  // and node mask for each slice pattern
1326 
1327  const LeafSlice& leafSlice = leafSliceArray[i];
1328  const size_t leafIdx = leafSlice.first;
1329  const NodeMaskPtrT& nodeMask = leafSlice.second;
1330 
1331  const Coord& origin = leafNodeOrigins[leafIdx];
1332 
1333  Coord ijk;
1334  for (auto indexIter = nodeMask->beginOn(); indexIter; ++indexIter) {
1335 
1336  // Get coordinate of center point of the FD stencil
1337  ijk = origin + LeafT::offsetToLocalCoord(indexIter.pos());
1338 
1339  // Find the closes neighbors in the three axial directions
1340  d1 = std::min(NN(acc1, ijk, 0), NN(acc1, ijk, 1));
1341  d2 = std::min(NN(acc1, ijk, 2), NN(acc1, ijk, 3));
1342  d3 = std::min(NN(acc1, ijk, 4), NN(acc1, ijk, 5));
1343 
1344  if (!(d1 || d2 || d3)) continue;//no valid neighbors
1345 
1346  // Get the center point of the FD stencil (assumed to be an active voxel)
1347  // Note this const_cast is normally unsafe but by design we know the tree
1348  // to be static, of floating-point type and containing active voxels only!
1349  SdfValueT &value = const_cast<SdfValueT&>(acc1.getValue(ijk));
1350 
1351  // Extract the sign
1352  sign = value >= SdfValueT(0) ? SdfValueT(1) : SdfValueT(-1);
1353 
1354  // Absolute value
1355  absV = math::Abs(value);
1356 
1357  // sort values so d1 <= d2 <= d3
1358  if (d2 < d1) std::swap(d1, d2);
1359  if (d3 < d2) std::swap(d2, d3);
1360  if (d2 < d1) std::swap(d1, d2);
1361 
1362  // Test if there is a solution depending on ONE of the neighboring voxels
1363  // if d2 - d1 >= h => d2 >= d1 + h then:
1364  // (x-d1)^2=h^2 => x = d1 + h
1365  update = d1.v + h;
1366  if (update <= d2.v) {
1367  if (update < absV) {
1368  value = sign * update;
1369  if (acc2) acc2->setValue(ijk, acc2->getValue(d1(ijk)));//update ext?
1370  }//update sdf?
1371  continue;
1372  }// one neighbor case
1373 
1374  // Test if there is a solution depending on TWO of the neighboring voxels
1375  // (x-d1)^2 + (x-d2)^2 = h^2
1376  //D = SdfValueT(2) * h * h - math::Pow2(d1.v - d2.v);// = 2h^2-(d1-d2)^2
1377  //if (D >= SdfValueT(0)) {// non-negative discriminant
1378  if (d2.v <= sqrt2h + d1.v) {
1379  D = SdfValueT(2) * h * h - math::Pow2(d1.v - d2.v);// = 2h^2-(d1-d2)^2
1380  update = SdfValueT(0.5) * (d1.v + d2.v + std::sqrt(D));
1381  if (update > d2.v && update <= d3.v) {
1382  if (update < absV) {
1383  value = sign * update;
1384  if (acc2) {
1385  d1.v -= update;
1386  d2.v -= update;
1387  // affine combination of two neighboring extension values
1388  const SdfValueT w = SdfValueT(1)/(d1.v+d2.v);
1389  acc2->setValue(ijk, w*(d1.v*acc2->getValue(d1(ijk)) +
1390  d2.v*acc2->getValue(d2(ijk))));
1391  }//update ext?
1392  }//update sdf?
1393  continue;
1394  }//test for two neighbor case
1395  }//test for non-negative determinant
1396 
1397  // Test if there is a solution depending on THREE of the neighboring voxels
1398  // (x-d1)^2 + (x-d2)^2 + (x-d3)^2 = h^2
1399  // 3x^2 - 2(d1 + d2 + d3)x + d1^2 + d2^2 + d3^2 = h^2
1400  // ax^2 + bx + c=0, a=3, b=-2(d1+d2+d3), c=d1^2 + d2^2 + d3^2 - h^2
1401  const SdfValueT d123 = d1.v + d2.v + d3.v;
1402  D = d123*d123 - SdfValueT(3)*(d1.v*d1.v + d2.v*d2.v + d3.v*d3.v - h * h);
1403  if (D >= SdfValueT(0)) {// non-negative discriminant
1404  update = SdfValueT(1.0/3.0) * (d123 + std::sqrt(D));//always passes test
1405  //if (update > d3.v) {//disabled due to round-off errors
1406  if (update < absV) {
1407  value = sign * update;
1408  if (acc2) {
1409  d1.v -= update;
1410  d2.v -= update;
1411  d3.v -= update;
1412  // affine combination of three neighboring extension values
1413  const SdfValueT w = SdfValueT(1)/(d1.v+d2.v+d3.v);
1414  acc2->setValue(ijk, w*(d1.v*acc2->getValue(d1(ijk)) +
1415  d2.v*acc2->getValue(d2(ijk)) +
1416  d3.v*acc2->getValue(d3(ijk))));
1417  }//update ext?
1418  }//update sdf?
1419  }//test for non-negative determinant
1420  }//loop over coordinates
1421  }
1422  };
1423 
1424 #ifdef BENCHMARK_FAST_SWEEPING
1425  util::CpuTimer timer("Forward sweep");
1426 #endif
1427 
1428  for (size_t i = 0; i < mVoxelSliceKeys.size(); i++) {
1429  voxelSliceIndex = mVoxelSliceKeys[i];
1430  tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1431  }
1432 
1433 #ifdef BENCHMARK_FAST_SWEEPING
1434  timer.restart("Backward sweeps");
1435 #endif
1436  for (size_t i = mVoxelSliceKeys.size(); i > 0; i--) {
1437  voxelSliceIndex = mVoxelSliceKeys[i-1];
1438  tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1439  }
1440 
1441 #ifdef BENCHMARK_FAST_SWEEPING
1442  timer.stop();
1443 #endif
1444  }// FastSweeping::SweepingKernel::sweep
1445 
1446 private:
1447  using NodeMaskT = typename SweepMaskTreeT::LeafNodeType::NodeMaskType;
1448  using NodeMaskPtrT = std::unique_ptr<NodeMaskT>;
1449  // using a unique ptr for the NodeMask allows for parallel allocation,
1450  // but makes this class not copy-constructible
1451  using LeafSlice = std::pair</*leafIdx=*/size_t, /*leafMask=*/NodeMaskPtrT>;
1452  using LeafSliceArray = std::deque<LeafSlice>;
1453  using VoxelSliceMap = std::map</*voxelSliceKey=*/int64_t, LeafSliceArray>;
1454 
1455  // Private member data of SweepingKernel
1456  FastSweeping *mParent;
1457  VoxelSliceMap mVoxelSliceMap;
1458  std::vector<int64_t> mVoxelSliceKeys;
1459 };// FastSweeping::SweepingKernel
1460 
1462 
1463 template<typename GridT>
1464 typename GridT::Ptr
1465 fogToSdf(const GridT &fogGrid,
1466  typename GridT::ValueType isoValue,
1467  int nIter)
1468 {
1470  if (fs.initSdf(fogGrid, isoValue, /*isInputSdf*/false)) fs.sweep(nIter);
1471  return fs.sdfGrid();
1472 }
1473 
1474 template<typename GridT>
1475 typename GridT::Ptr
1476 sdfToSdf(const GridT &sdfGrid,
1477  typename GridT::ValueType isoValue,
1478  int nIter)
1479 {
1481  if (fs.initSdf(sdfGrid, isoValue, /*isInputSdf*/true)) fs.sweep(nIter);
1482  return fs.sdfGrid();
1483 }
1484 
1485 template<typename FogGridT, typename ExtOpT, typename ExtValueT>
1486 typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
1487 fogToExt(const FogGridT &fogGrid,
1488  const ExtOpT &op,
1489  const ExtValueT& background,
1490  typename FogGridT::ValueType isoValue,
1491  int nIter)
1492 {
1494  if (fs.initExt(fogGrid, op, background, isoValue, /*isInputSdf*/false)) fs.sweep(nIter);
1495  return fs.extGrid();
1496 }
1497 
1498 template<typename SdfGridT, typename OpT, typename ExtValueT>
1499 typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
1500 sdfToExt(const SdfGridT &sdfGrid,
1501  const OpT &op,
1502  const ExtValueT &background,
1503  typename SdfGridT::ValueType isoValue,
1504  int nIter)
1505 {
1507  if (fs.initExt(sdfGrid, op, background, isoValue, /*isInputSdf*/true)) fs.sweep(nIter);
1508  return fs.extGrid();
1509 }
1510 
1511 template<typename FogGridT, typename ExtOpT, typename ExtValueT>
1512 std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1513 fogToSdfAndExt(const FogGridT &fogGrid,
1514  const ExtOpT &op,
1515  const ExtValueT &background,
1516  typename FogGridT::ValueType isoValue,
1517  int nIter)
1518 {
1520  if (fs.initExt(fogGrid, op, background, isoValue, /*isInputSdf*/false)) fs.sweep(nIter);
1521  return std::make_pair(fs.sdfGrid(), fs.extGrid());
1522 }
1523 
1524 template<typename SdfGridT, typename ExtOpT, typename ExtValueT>
1525 std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1526 sdfToSdfAndExt(const SdfGridT &sdfGrid,
1527  const ExtOpT &op,
1528  const ExtValueT &background,
1529  typename SdfGridT::ValueType isoValue,
1530  int nIter)
1531 {
1533  if (fs.initExt(sdfGrid, op, background, isoValue, /*isInputSdf*/true)) fs.sweep(nIter);
1534  return std::make_pair(fs.sdfGrid(), fs.extGrid());
1535 }
1536 
1537 template<typename GridT>
1538 typename GridT::Ptr
1539 dilateSdf(const GridT &sdfGrid,
1540  int dilation,
1541  NearestNeighbors nn,
1542  int nIter)
1543 {
1545  if (fs.initDilate(sdfGrid, dilation, nn)) fs.sweep(nIter);
1546  return fs.sdfGrid();
1547 }
1548 
1549 template<typename GridT, typename MaskTreeT>
1550 typename GridT::Ptr
1551 maskSdf(const GridT &sdfGrid,
1552  const Grid<MaskTreeT> &mask,
1553  bool ignoreActiveTiles,
1554  int nIter)
1555 {
1557  if (fs.initMask(sdfGrid, mask, ignoreActiveTiles)) fs.sweep(nIter);
1558  return fs.sdfGrid();
1559 }
1560 
1561 } // namespace tools
1562 } // namespace OPENVDB_VERSION_NAME
1563 } // namespace openvdb
1564 
1565 #endif // OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
openvdb::v7_2::tools::FastSweeping::DilateKernel
Private class of FastSweeping to perform multi-threaded initialization.
Definition: FastSweeping.h:759
openvdb::v7_2::tools::FastSweeping::SweepingKernel::sweep
void sweep()
Definition: FastSweeping.h:1299
openvdb::v7_2::tools::changeAsymmetricLevelSetBackground
void changeAsymmetricLevelSetBackground(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &outsideWidth, const typename TreeOrLeafManagerT::ValueType &insideWidth, bool threaded=true, size_t grainSize=32)
Replace the background values in all the nodes of a floating-point tree containing a possibly asymmet...
Definition: ChangeBackground.h:217
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::operator()
void operator()(const LeafRange &r)
Definition: FastSweeping.h:734
openvdb::v7_2::tree::LeafManager::swapLeafBuffer
bool swapLeafBuffer(size_t bufferIdx, bool serial=false)
Swap each leaf node's buffer with the nth corresponding auxiliary buffer, where n = bufferIdx.
Definition: LeafManager.h:361
openvdb::v7_2::util::CpuTimer::restart
double restart()
Re-start timer.
Definition: CpuTimer.h:153
openvdb::v7_2::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:26
openvdb::v7_2::tools::FastSweeping::DilateKernel::mBackground
const SdfValueT mBackground
Definition: FastSweeping.h:831
openvdb::v7_2::tools::FastSweeping::initExt
bool initExt(const SdfGridT &sdfGrid, const ExtOpT &op, const ExtValueT &background, SdfValueT isoValue, bool isInputSdf)
Initializer used whenever velocity extension is performed in addition to the computation of signed di...
openvdb::v7_2::math::BaseStencil< GradStencil< GridT, true >, GridT, true >::intersectionMask
std::bitset< 6 > intersectionMask(const ValueType &isoValue=zeroVal< ValueType >()) const
Return true a bit-mask where the 6 bits indicates if the center of the stencil intersects the iso-con...
Definition: Stencils.h:188
openvdb::v7_2::tools::sdfToExt
SdfGridT::template ValueConverter< ExtValueT >::Type::Ptr sdfToExt(const SdfGridT &sdfGrid, const OpT &op, const ExtValueT &background, typename SdfGridT::ValueType isoValue, int nIter)
Definition: FastSweeping.h:1500
openvdb::v7_2::tools::FastSweeping::InitSdf::operator()
void operator()(const LeafRange &r) const
Definition: FastSweeping.h:881
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN::operator<
bool operator<(const NN &rhs) const
Definition: FastSweeping.h:1295
openvdb::v7_2::ax::run
void run(const char *ax, openvdb::GridBase &grid)
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
CpuTimer.h
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN::v
SdfValueT v
Definition: FastSweeping.h:1289
openvdb::v7_2::tree::LeafManager::leafRange
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:347
openvdb::v7_2::tools::FastSweeping::InitSdf::mParent
FastSweeping * mParent
Definition: FastSweeping.h:936
openvdb::v7_2::tools::fogToSdfAndExt
std::pair< typename FogGridT::Ptr, typename FogGridT::template ValueConverter< ExtValueT >::Type::Ptr > fogToSdfAndExt(const FogGridT &fogGrid, const ExtOpT &op, const ExtValueT &background, typename FogGridT::ValueType isoValue, int nIter=1)
Computes the signed distance field and the extension of a scalar field, defined by the specified func...
Definition: FastSweeping.h:1513
openvdb::v7_2::tools::sdfToSdf
GridT::Ptr sdfToSdf(const GridT &sdfGrid, typename GridT::ValueType isoValue=0, int nIter=1)
Given an existing approximate SDF it solves the Eikonal equation for all its active voxels....
Definition: FastSweeping.h:1476
openvdb::v7_2::tools::FastSweeping::sweep
void sweep(int nIter=1, bool finalize=true)
Perform nIter iterations of the fast sweeping algorithm.
Definition: FastSweeping.h:659
openvdb::v7_2::tools::FastSweeping::SweepingKernel::SweepingKernel
SweepingKernel(FastSweeping &parent)
Definition: FastSweeping.h:1172
openvdb::v7_2::tools::FastSweeping::DilateKernel::LeafRange
typename tree::LeafManager< SdfTreeT >::LeafRange LeafRange
Definition: FastSweeping.h:760
openvdb::v7_2::tools::FastSweeping::InitSdf::mSdfGrid
SdfGridT * mSdfGrid
Definition: FastSweeping.h:937
openvdb::v7_2::GRID_LEVEL_SET
@ GRID_LEVEL_SET
Definition: openvdb/Types.h:315
openvdb::v7_2::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
openvdb::v7_2::tools::sdfToSdfAndExt
std::pair< typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter< ExtValueT >::Type::Ptr > sdfToSdfAndExt(const SdfGridT &sdfGrid, const ExtOpT &op, const ExtValueT &background, typename SdfGridT::ValueType isoValue=0, int nIter=1)
Computes the signed distance field and the extension of a scalar field, defined by the specified func...
Definition: FastSweeping.h:1526
openvdb::v7_2::math::Sqrt
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:754
openvdb::v7_2::util::CpuTimer::stop
double stop() const
Returns and prints time in milliseconds since construction or start was called.
Definition: CpuTimer.h:131
openvdb::v7_2::tools::FastSweeping::boundaryVoxelCount
size_t boundaryVoxelCount() const
Return the number of voxels that defined the boundary condition.
Definition: FastSweeping.h:510
openvdb::v7_2::math::isApproxZero
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance.
Definition: Math.h:340
openvdb::v7_2::tools::FastSweeping::InitSdf::InitSdf
InitSdf(const InitSdf &)=default
LevelSetUtil.h
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
openvdb::v7_2::Vec3R
math::Vec3< Real > Vec3R
Definition: openvdb/Types.h:50
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::LeafRange
typename LeafMgr::LeafRange LeafRange
Definition: FastSweeping.h:723
openvdb::v7_2::tools::FastSweeping::InitSdf::operator()
void operator()(const RootOrInternalNodeT &node) const
Definition: FastSweeping.h:926
openvdb::v7_2::tools::FastSweeping::sweepingVoxelCount
size_t sweepingVoxelCount() const
Return the number of voxels that will be solved for.
Definition: FastSweeping.h:507
openvdb::v7_2::tools::FastSweeping::DilateKernel::DilateKernel
DilateKernel(FastSweeping &parent)
Definition: FastSweeping.h:761
openvdb::v7_2::tools::FastSweeping::InitSdf::InitSdf
InitSdf(FastSweeping &parent)
Definition: FastSweeping.h:839
openvdb::v7_2::tree::ValueAccessor
Definition: ValueAccessor.h:183
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: openvdb/Exceptions.h:82
openvdb::v7_2::tools::FastSweeping::MinMaxKernel
Definition: FastSweeping.h:721
openvdb::v7_2::tools::FastSweeping::isValid
bool isValid() const
Return true if there are voxels and boundaries to solve for.
Definition: FastSweeping.h:513
openvdb::v7_2::tools::FastSweeping::DilateKernel::DilateKernel
DilateKernel(const DilateKernel &parent)=default
openvdb::v7_2::tools::FastSweeping::InitSdf
Definition: FastSweeping.h:837
openvdb::v7_2::math::BaseStencil< GradStencil< GridT, true >, GridT, true >::getValue
const ValueType & getValue(unsigned int pos=0) const
Return the value from the stencil buffer with linear offset pos.
Definition: Stencils.h:97
openvdb::v7_2::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::mMax
SdfValueT mMax
Definition: FastSweeping.h:751
openvdb::v7_2::tools::FastSweeping::DilateKernel::operator=
DilateKernel & operator=(const DilateKernel &)=delete
openvdb::v7_2::tools::FastSweeping::SweepingKernel
Private class of FastSweeping to perform concurrent fast sweeping in two directions.
Definition: FastSweeping.h:1171
openvdb::v7_2::tools::pruneInactive
void pruneInactive(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with background tiles any nodes whose values are a...
Definition: Prune.h:354
openvdb::v7_2::Grid
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:572
openvdb::v7_2::tools::sdfToExt
SdfGridT::template ValueConverter< ExtValueT >::Type::Ptr sdfToExt(const SdfGridT &sdfGrid, const ExtOpT &op, const ExtValueT &background, typename SdfGridT::ValueType isoValue=0, int nIter=1)
Computes the extension of a scalar field, defined by the specified functor, off an iso-surface from a...
openvdb::v7_2::tools::FastSweeping::InitSdf::operator=
InitSdf & operator=(const InitSdf &)=delete
openvdb::v7_2::tools::FastSweeping::SweepingKernel::SweepingKernel
SweepingKernel(const SweepingKernel &)=delete
openvdb::v7_2::tools::FastSweeping::InitSdf::mAboveSign
SdfValueT mAboveSign
Definition: FastSweeping.h:939
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
openvdb::v7_2::tree::ValueAccessor::getValue
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:219
openvdb::v7_2::tools::FastSweeping::InitSdf::LeafRange
typename tree::LeafManager< SdfTreeT >::LeafRange LeafRange
Definition: FastSweeping.h:838
openvdb::v7_2::math::Pow2
Type Pow2(Type x)
Return x2.
Definition: Math.h:541
openvdb::v7_2::tools::FastSweeping
Computes signed distance values from an initial iso-surface and optionally performs velocty extension...
Definition: FastSweeping.h:351
openvdb::v7_2::tools::FastSweeping::operator=
FastSweeping & operator=(const FastSweeping &)=delete
Disallow copy assignment.
openvdb::v7_2::tools::NearestNeighbors
NearestNeighbors
Voxel topology of nearest neighbors.
Definition: Morphology.h:60
openvdb::v7_2::tree::ValueAccessor::setValueOff
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:266
openvdb::v7_2::Grid::tree
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
Definition: Grid.h:908
openvdb::v7_2::tools::FastSweeping::SweepingKernel::operator=
SweepingKernel & operator=(const SweepingKernel &)=delete
openvdb::v7_2::tools::FastSweeping::initMask
bool initMask(const SdfGridT &sdfGrid, const Grid< MaskTreeT > &mask, bool ignoreActiveTiles=false)
Initializer used for the extamnsion of an exsiting signed distance field into the active values of an...
Definition: FastSweeping.h:628
openvdb::v7_2::math::Vec3d
Vec3< double > Vec3d
Definition: Vec3.h:662
openvdb::v7_2::tools::FastSweeping::clear
void clear()
Clears all the grids and counters so initializtion can be called again.
Definition: FastSweeping.h:556
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::join
void join(const MinMaxKernel &other)
Definition: FastSweeping.h:745
openvdb::v7_2::math::MinMax
Templated class to compute the minimum and maximum values.
Definition: Stats.h:31
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN::NN
NN()
Definition: FastSweeping.h:1292
openvdb::v7_2::tools::FastSweeping::sdfGrid
SdfGridT::Ptr sdfGrid()
Returns a shared pointer to the signed distance field computed by this class.
Definition: FastSweeping.h:388
openvdb::v7_2::tools::NN_FACE
@ NN_FACE
Definition: Morphology.h:60
openvdb::v7_2::tools::fogToExt
FogGridT::template ValueConverter< ExtValueT >::Type::Ptr fogToExt(const FogGridT &fogGrid, const ExtOpT &op, const ExtValueT &background, typename FogGridT::ValueType isoValue, int nIter=1)
Computes the extension of a field, defined by the specified functor, off an iso-surface from an input...
Definition: FastSweeping.h:1487
openvdb::v7_2::tools::dilateSdf
GridT::Ptr dilateSdf(const GridT &sdfGrid, int dilation, NearestNeighbors nn=NN_FACE, int nIter=1)
Dilates an existing signed distance filed by a specified number of voxels.
Definition: FastSweeping.h:1539
openvdb::v7_2::tools::fogToSdf
GridT::Ptr fogToSdf(const GridT &fogGrid, typename GridT::ValueType isoValue, int nIter=1)
Converts a scalar fog volume into a signed distance function. Active input voxels with scalar values ...
Definition: FastSweeping.h:1465
openvdb::v7_2::tree::LeafManager
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
openvdb::v7_2::tools::FastSweeping::DilateKernel::run
void run(int dilation, NearestNeighbors nn)
Definition: FastSweeping.h:768
openvdb::v7_2::tree::NodeManager
To facilitate threading over the nodes of a tree, cache node pointers in linear arrays,...
Definition: NodeManager.h:510
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:147
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN::operator()
Coord operator()(const Coord &p) const
Definition: FastSweeping.h:1294
openvdb::v7_2::tools::maskSdf
GridT::Ptr maskSdf(const GridT &sdfGrid, const Grid< MaskTreeT > &mask, bool ignoreActiveTiles=false, int nIter=1)
Fills mask by extending an existing signed distance field into the active values of this input ree of...
Definition: FastSweeping.h:1551
LeafManager.h
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
openvdb::v7_2::tools::IGNORE_TILES
@ IGNORE_TILES
Definition: Morphology.h:75
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::mMin
SdfValueT mMin
Definition: FastSweeping.h:751
std
Definition: Coord.h:587
openvdb::v7_2::TopologyCopy
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: openvdb/Types.h:542
openvdb::v7_2::tools::FastSweeping::~FastSweeping
~FastSweeping()
Destructor.
Definition: FastSweeping.h:374
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN::NN
NN(const SdfAccT &a, const Coord &p, int i)
Definition: FastSweeping.h:1293
openvdb::v7_2::tools::FastSweeping::InitSdf::mIsoValue
SdfValueT mIsoValue
Definition: FastSweeping.h:938
Morphology.h
Implementation of morphological dilation and erosion.
Statistics.h
Functions to efficiently compute histograms, extremas (min/max) and statistics (mean,...
Stencils.h
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
openvdb::v7_2::tools::FastSweeping::FastSweeping
FastSweeping()
Constructor.
Definition: FastSweeping.h:550
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN::ijk
static Coord ijk(const Coord &p, int i)
Definition: FastSweeping.h:1291
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:95
openvdb::v7_2::math::BaseStencil< GradStencil< GridT, true >, GridT, true >::moveTo
void moveTo(const Coord &ijk)
Initialize the stencil buffer with the values of voxel (i, j, k) and its neighbors.
Definition: Stencils.h:47
openvdb::v7_2::Grid::Ptr
SharedPtr< Grid > Ptr
Definition: Grid.h:574
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::run
math::MinMax< SdfValueT > run(const SdfGridT &grid)
Definition: FastSweeping.h:727
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::MinMaxKernel
MinMaxKernel()
Definition: FastSweeping.h:724
openvdb::v7_2::tools::FastSweeping::InitSdf::run
void run(SdfValueT isoValue, bool isInputSdf)
Definition: FastSweeping.h:844
openvdb::v7_2::util::CpuTimer
Simple timer for basic profiling.
Definition: CpuTimer.h:67
openvdb::v7_2::RuntimeError
Definition: openvdb/Exceptions.h:63
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN
Definition: FastSweeping.h:1288
openvdb::v7_2::tools::FastSweeping::SweepingKernel::computeVoxelSlices
void computeVoxelSlices(HashOp hash)
Main method that performs concurrent bi-directional sweeps.
Definition: FastSweeping.h:1178
openvdb::v7_2::tools::FastSweeping::initSdf
bool initSdf(const SdfGridT &sdfGrid, SdfValueT isoValue, bool isInputSdf)
Initializer for input grids that are either a signed distance field or a scalar fog volume.
Definition: FastSweeping.h:594
openvdb::v7_2::tools::FastSweeping::MinMaxKernel::MinMaxKernel
MinMaxKernel(MinMaxKernel &other, tbb::split)
Definition: FastSweeping.h:725
openvdb::v7_2::tools::sdfInteriorMask
GridOrTreeType::template ValueConverter< bool >::Type::Ptr sdfInteriorMask(const GridOrTreeType &volume, typename GridOrTreeType::ValueType isovalue=lsutilGridZero< GridOrTreeType >())
Threaded method to construct a boolean mask that represents interior regions in a signed distance fie...
Definition: LevelSetUtil.h:2270
openvdb
Definition: openvdb/Exceptions.h:13
openvdb::v7_2::tools::FastSweeping::initDilate
bool initDilate(const SdfGridT &sdfGrid, int dilation, NearestNeighbors nn=NN_FACE)
Initializer used when dilating an exsiting signed distance field.
Definition: FastSweeping.h:617
openvdb::v7_2::tree::LeafManager::LeafRange
Definition: LeafManager.h:102
openvdb::v7_2::tools::FastSweeping::SweepingKernel::NN::n
int n
Definition: FastSweeping.h:1290
openvdb::v7_2::tools::FastSweeping::FastSweeping
FastSweeping(const FastSweeping &)=delete
Disallow copy construction.
openvdb::v7_2::tools::changeLevelSetBackground
void changeLevelSetBackground(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &halfWidth, bool threaded=true, size_t grainSize=32)
Replace the background value in all the nodes of a floating-point tree containing a symmetric narrow-...
Definition: ChangeBackground.h:233
openvdb::v7_2::Index
Index32 Index
Definition: openvdb/Types.h:32
openvdb::v7_2::tools::Abs
MeshToVoxelEdgeData::EdgeData Abs(const MeshToVoxelEdgeData::EdgeData &x)
Definition: MeshToVolume.h:3705
openvdb::v7_2::math::Abs
Coord Abs(const Coord &xyz)
Definition: Coord.h:515
openvdb::v7_2::tools::dilateActiveValues
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
openvdb::v7_2::math::GradStencil
Definition: Stencils.h:1232
openvdb::v7_2::tools::FastSweeping::DilateKernel::mParent
FastSweeping * mParent
Definition: FastSweeping.h:830
openvdb::v7_2::tools::FastSweeping::extGrid
ExtGridT::Ptr extGrid()
Returns a shared pointer to the extension field computed by this class.
Definition: FastSweeping.h:396