39 #ifndef OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED 40 #define OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED 42 #include <tbb/parallel_for.h> 57 #include <type_traits> 66 template<
typename Gr
idT,
typename InterruptT = util::NullInterrupter>
72 using LeafType =
typename TreeType::LeafNodeType;
75 using LeafRange =
typename LeafManagerType::LeafRange;
77 using MaskTreeType =
typename TreeType::template ValueConverter<ValueMask>::Type;
78 static_assert(std::is_floating_point<ValueType>::value,
79 "LevelSetTracker requires a level set grid with floating-point values");
86 : spatialScheme(s), temporalScheme(t), normCount(n), grainSize(g) {}
101 template <
typename MaskType>
105 void normalize() { this->normalize<MaskTreeType>(
nullptr); }
129 void dilate(
int iterations = 1);
133 void erode(
int iterations = 1);
177 void startInterrupter(
const char* msg);
179 void endInterrupter();
182 bool checkInterrupter();
202 void operator()(
const LeafRange& r)
const;
203 LevelSetTracker& mTracker;
213 using StencilT =
typename SchemeT::template ISStencil<GridType>::StencilType;
214 using MaskLeafT =
typename MaskT::LeafNodeType;
215 using MaskIterT =
typename MaskLeafT::ValueOnCIter;
216 using VoxelIterT =
typename LeafType::ValueOnCIter;
218 Normalizer(LevelSetTracker& tracker,
const MaskT* mask);
220 void operator()(
const LeafRange& r)
const {mTask(const_cast<Normalizer*>(
this), r);}
221 void cook(
const char* msg,
int swapBuffer=0);
222 template <
int Nominator,
int Denominator>
223 void euler(
const LeafRange& range,
Index phiBuffer,
Index resultBuffer);
224 inline void euler01(
const LeafRange& r) {this->euler<0,1>(r, 0, 1);}
225 inline void euler12(
const LeafRange& r) {this->euler<1,2>(r, 1, 1);}
226 inline void euler34(
const LeafRange& r) {this->euler<3,4>(r, 1, 2);}
227 inline void euler13(
const LeafRange& r) {this->euler<1,3>(r, 1, 2);}
228 template <
int Nominator,
int Denominator>
229 void eval(StencilT& stencil,
const ValueType* phi, ValueType* result,
Index n)
const;
230 LevelSetTracker& mTracker;
232 const ValueType mDt, mInvDx;
233 typename std::function<void (Normalizer*, const LeafRange&)> mTask;
236 template<math::BiasedGradientScheme SpatialScheme,
typename MaskT>
237 void normalize1(
const MaskT* mask);
241 void normalize2(
const MaskT* mask);
248 LeafManagerType* mLeafs;
249 InterruptT* mInterrupter;
254 template<
typename Gr
idT,
typename InterruptT>
255 LevelSetTracker<GridT, InterruptT>::
256 LevelSetTracker(GridT& grid, InterruptT* interrupt):
259 mInterrupter(interrupt),
260 mDx(static_cast<
ValueType>(grid.voxelSize()[0])),
263 if ( !
grid.hasUniformVoxels() ) {
265 "The transform must have uniform scale for the LevelSetTracker to function");
269 "LevelSetTracker expected a level set, got a grid of class \"" 270 +
grid.gridClassToString(
grid.getGridClass())
271 +
"\" [hint: Grid::setGridClass(openvdb::GRID_LEVEL_SET)]");
275 template<
typename Gr
idT,
typename InterruptT>
280 this->startInterrupter(
"Pruning Level Set");
290 mLeafs->rebuildLeafArray();
291 this->endInterrupter();
294 template<
typename Gr
idT,
typename InterruptT>
309 template<
typename Gr
idT,
typename InterruptT>
314 if (this->getNormCount() == 0) {
315 for (
int i=0; i < iterations; ++i) {
320 for (
int i=0; i < iterations; ++i) {
325 mask.topologyDifference(mask0);
331 template<
typename Gr
idT,
typename InterruptT>
337 mLeafs->rebuildLeafArray();
338 const ValueType background = mGrid->background() - iterations*mDx;
342 template<
typename Gr
idT,
typename InterruptT>
347 const int wOld =
static_cast<int>(
math::RoundDown(this->getHalfWidth()));
348 const int wNew =
static_cast<int>(halfWidth);
350 this->dilate(wNew - wOld);
351 }
else if (wOld > wNew) {
352 this->erode(wOld - wNew);
357 template<
typename Gr
idT,
typename InterruptT>
362 if (mInterrupter) mInterrupter->start(msg);
365 template<
typename Gr
idT,
typename InterruptT>
370 if (mInterrupter) mInterrupter->end();
373 template<
typename Gr
idT,
typename InterruptT>
379 tbb::task::self().cancel_group_execution();
385 template<
typename Gr
idT,
typename InterruptT>
386 template<
typename MaskT>
391 switch (this->getSpatialScheme()) {
393 this->normalize1<math::FIRST_BIAS , MaskT>(mask);
break;
395 this->normalize1<math::SECOND_BIAS, MaskT>(mask);
break;
397 this->normalize1<math::THIRD_BIAS, MaskT>(mask);
break;
399 this->normalize1<math::WENO5_BIAS, MaskT>(mask);
break;
401 this->normalize1<math::HJWENO5_BIAS, MaskT>(mask);
break;
408 template<
typename Gr
idT,
typename InterruptT>
409 template<math::BiasedGradientScheme SpatialScheme,
typename MaskT>
414 switch (this->getTemporalScheme()) {
416 this->normalize2<SpatialScheme, math::TVD_RK1, MaskT>(mask);
break;
418 this->normalize2<SpatialScheme, math::TVD_RK2, MaskT>(mask);
break;
420 this->normalize2<SpatialScheme, math::TVD_RK3, MaskT>(mask);
break;
427 template<
typename Gr
idT,
typename InterruptT>
432 LevelSetTracker<GridT, InterruptT>::
433 normalize2(
const MaskT* mask)
435 Normalizer<SpatialScheme, TemporalScheme, MaskT> tmp(*
this, mask);
441 template<
typename Gr
idT,
typename InterruptT>
443 LevelSetTracker<GridT, InterruptT>::
446 const int grainSize = mTracker.getGrainSize();
447 const LeafRange range = mTracker.leafs().leafRange(grainSize);
450 tbb::parallel_for(range, *
this);
457 template<
typename Gr
idT,
typename InterruptT>
459 LevelSetTracker<GridT, InterruptT>::
460 Trim::operator()(
const LeafRange& range)
const 462 using VoxelIterT =
typename LeafType::ValueOnIter;
463 mTracker.checkInterrupter();
464 const ValueType gamma = mTracker.mGrid->background();
466 for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
467 LeafType &leaf = *leafIter;
468 for (VoxelIterT iter = leaf.beginValueOn(); iter; ++iter) {
469 const ValueType val = *iter;
471 leaf.setValueOff(iter.pos(), -gamma);
472 else if (val >= gamma)
473 leaf.setValueOff(iter.pos(), gamma);
480 template<
typename Gr
idT,
typename InterruptT>
485 LevelSetTracker<GridT, InterruptT>::
486 Normalizer<SpatialScheme, TemporalScheme, MaskT>::
487 Normalizer(LevelSetTracker& tracker,
const MaskT* mask)
490 , mDt(tracker.voxelSize()*(TemporalScheme == math::
TVD_RK1 ? 0.3f :
491 TemporalScheme == math::
TVD_RK2 ? 0.9f : 1.0f))
492 , mInvDx(1.0f/tracker.voxelSize())
497 template<
typename Gr
idT,
typename InterruptT>
506 namespace ph = std::placeholders;
509 mTracker.mLeafs->rebuildAuxBuffers(TemporalScheme ==
math::TVD_RK3 ? 2 : 1);
511 for (
int n=0, e=mTracker.getNormCount(); n < e; ++n) {
514 switch(TemporalScheme) {
518 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
521 this->cook(
"Normalizing level set using TVD_RK1", 1);
526 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
529 this->cook(
"Normalizing level set using TVD_RK1 (step 1 of 2)", 1);
533 mTask = std::bind(&Normalizer::euler12, ph::_1, ph::_2);
536 this->cook(
"Normalizing level set using TVD_RK1 (step 2 of 2)", 1);
541 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
544 this->cook(
"Normalizing level set using TVD_RK3 (step 1 of 3)", 1);
548 mTask = std::bind(&Normalizer::euler34, ph::_1, ph::_2);
551 this->cook(
"Normalizing level set using TVD_RK3 (step 2 of 3)", 2);
555 mTask = std::bind(&Normalizer::euler13, ph::_1, ph::_2);
558 this->cook(
"Normalizing level set using TVD_RK3 (step 3 of 3)", 2);
562 OPENVDB_THROW(ValueError,
"Temporal integration scheme not supported!");
566 mTracker.mLeafs->removeAuxBuffers();
571 template<
typename Gr
idT,
typename InterruptT>
576 LevelSetTracker<GridT, InterruptT>::
577 Normalizer<SpatialScheme, TemporalScheme, MaskT>::
578 cook(
const char* msg,
int swapBuffer)
580 mTracker.startInterrupter( msg );
582 const int grainSize = mTracker.getGrainSize();
583 const LeafRange range = mTracker.leafs().leafRange(grainSize);
585 grainSize>0 ? tbb::parallel_for(range, *
this) : (*this)(range);
587 mTracker.leafs().swapLeafBuffer(swapBuffer, grainSize==0);
589 mTracker.endInterrupter();
592 template<
typename Gr
idT,
typename InterruptT>
596 template <
int Nominator,
int Denominator>
598 LevelSetTracker<GridT, InterruptT>::
599 Normalizer<SpatialScheme, TemporalScheme, MaskT>::
600 eval(StencilT& stencil,
const ValueType* phi, ValueType* result,
Index n)
const 602 using GradientT =
typename math::ISGradientNormSqrd<SpatialScheme>;
603 static const ValueType alpha = ValueType(Nominator)/ValueType(Denominator);
604 static const ValueType beta = ValueType(1) - alpha;
606 const ValueType normSqGradPhi = GradientT::result(stencil);
607 const ValueType phi0 = stencil.getValue();
610 v = phi0 - mDt * v * (
math::Sqrt(normSqGradPhi) * mInvDx - 1.0f);
611 result[n] = Nominator ? alpha * phi[n] + beta * v : v;
614 template<
typename Gr
idT,
typename InterruptT>
618 template <
int Nominator,
int Denominator>
620 LevelSetTracker<GridT,InterruptT>::
621 Normalizer<SpatialScheme, TemporalScheme, MaskT>::
622 euler(
const LeafRange& range,
Index phiBuffer,
Index resultBuffer)
624 using VoxelIterT =
typename LeafType::ValueOnCIter;
626 mTracker.checkInterrupter();
628 StencilT stencil(mTracker.grid());
630 for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
631 const ValueType* phi = leafIter.buffer(phiBuffer).data();
632 ValueType* result = leafIter.buffer(resultBuffer).data();
633 if (mMask ==
nullptr) {
634 for (VoxelIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
635 stencil.moveTo(iter);
636 this->eval<Nominator, Denominator>(stencil, phi, result, iter.pos());
638 }
else if (
const MaskLeafT* mask = mMask->probeLeaf(leafIter->origin())) {
639 const ValueType* phi0 = leafIter->buffer().data();
640 for (MaskIterT iter = mask->cbeginValueOn(); iter; ++iter) {
641 const Index i = iter.pos();
642 stencil.moveTo(iter.getCoord(), phi0[i]);
643 this->eval<Nominator, Denominator>(stencil, phi, result, i);
653 #endif // OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED
Definition: FiniteDifference.h:262
Definition: FiniteDifference.h:195
Definition: FiniteDifference.h:193
Definition: FiniteDifference.h:198
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
TemporalIntegrationScheme
Temporal integration schemes.
Definition: FiniteDifference.h:261
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
Efficient multi-threaded replacement of the background values in tree.
Definition: FiniteDifference.h:194
Type Pow2(Type x)
Return x2.
Definition: Math.h:502
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:515
Defined various multi-threaded utility functions for trees.
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
Definition: FiniteDifference.h:263
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
Definition: Exceptions.h:92
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
Implementation of morphological dilation and erosion.
Definition: Exceptions.h:40
BiasedGradientScheme
Biased Gradients are limited to non-centered differences.
Definition: FiniteDifference.h:192
float RoundDown(float x)
Return x rounded down to the nearest integer.
Definition: Math.h:757
Definition: FiniteDifference.h:264
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:715
static T value()
Definition: Math.h:117
Definition: FiniteDifference.h:265
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
Index32 Index
Definition: Types.h:61
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
Definition: Operators.h:153
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:280
Definition: FiniteDifference.h:197
Definition: FiniteDifference.h:196
Definition: Exceptions.h:90