12 #ifndef OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED
13 #define OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED
30 #include <tbb/parallel_for.h>
33 #include <type_traits>
56 template<
typename Gr
idT,
typename InterruptT = util::NullInterrupter>
64 using LeafType =
typename TreeType::LeafNodeType;
67 using LeafRange =
typename LeafManagerType::LeafRange;
71 "LevelSetTracker requires a level set grid with floating-point values");
77 int n = static_cast<int>(LEVEL_SET_HALF_WIDTH),
int g = 1)
93 template <
typename MaskType>
97 void normalize() { this->normalize<MaskTreeType>(
nullptr); }
124 void dilate(
int iterations = 1);
128 void erode(
int iterations = 1);
132 bool resize(
Index halfWidth = static_cast<Index>(LEVEL_SET_HALF_WIDTH));
200 template<TrimMode Trimming>
215 using SchemeT = math::BIAS_SCHEME<SpatialScheme>;
216 using StencilT =
typename SchemeT::template ISStencil<GridType>::StencilType;
217 using MaskLeafT =
typename MaskT::LeafNodeType;
218 using MaskIterT =
typename MaskLeafT::ValueOnCIter;
219 using VoxelIterT =
typename LeafType::ValueOnCIter;
223 void operator()(
const LeafRange&
r)
const {mTask(const_cast<Normalizer*>(
this), r);}
224 void cook(
const char* msg,
int swapBuffer=0);
225 template <
int Nominator,
int Denominator>
227 inline void euler01(
const LeafRange& r) {this->euler<0,1>(
r, 0, 1);}
228 inline void euler12(
const LeafRange& r) {this->euler<1,2>(
r, 1, 1);}
229 inline void euler34(
const LeafRange& r) {this->euler<3,4>(
r, 1, 2);}
230 inline void euler13(
const LeafRange& r) {this->euler<1,3>(
r, 1, 2);}
231 template <
int Nominator,
int Denominator>
236 typename std::function<void (Normalizer*, const LeafRange&)> mTask;
239 template<math::BiasedGradientScheme SpatialScheme,
typename MaskT>
240 void normalize1(
const MaskT*
mask);
244 void normalize2(
const MaskT*
mask);
252 InterruptT* mInterrupter;
255 TrimMode mTrimMode = TrimMode::kAll;
258 template<
typename Gr
idT,
typename InterruptT>
263 mInterrupter(interrupt),
264 mDx(static_cast<
ValueType>(grid.voxelSize()[0])),
267 if ( !grid.hasUniformVoxels() ) {
269 "The transform must have uniform scale for the LevelSetTracker to function");
273 "LevelSetTracker expected a level set, got a grid of class \""
274 + grid.gridClassToString(grid.getGridClass())
275 +
"\" [hint: Grid::setGridClass(openvdb::GRID_LEVEL_SET)]");
279 template<
typename Gr
idT,
typename InterruptT>
284 this->startInterrupter(
"Pruning Level Set");
288 case TrimMode::kNone:
break;
289 case TrimMode::kInterior: Trim<TrimMode::kInterior>(*this).trim();
break;
290 case TrimMode::kExterior: Trim<TrimMode::kExterior>(*this).trim();
break;
291 case TrimMode::kAll: Trim<TrimMode::kAll>(*this).trim();
break;
298 mLeafs->rebuildLeafArray();
299 this->endInterrupter();
302 template<
typename Gr
idT,
typename InterruptT>
317 template<
typename Gr
idT,
typename InterruptT>
322 if (this->getNormCount() == 0) {
323 for (
int i=0; i < iterations; ++i) {
328 for (
int i=0; i < iterations; ++i) {
333 mask.topologyDifference(mask0);
339 template<
typename Gr
idT,
typename InterruptT>
346 mLeafs->rebuildLeafArray();
351 template<
typename Gr
idT,
typename InterruptT>
356 const int wOld =
static_cast<int>(
math::RoundDown(this->getHalfWidth()));
357 const int wNew =
static_cast<int>(halfWidth);
359 this->
dilate(wNew - wOld);
360 }
else if (wOld > wNew) {
361 this->
erode(wOld - wNew);
366 template<
typename Gr
idT,
typename InterruptT>
371 if (mInterrupter) mInterrupter->start(msg);
374 template<
typename Gr
idT,
typename InterruptT>
379 if (mInterrupter) mInterrupter->end();
382 template<
typename Gr
idT,
typename InterruptT>
388 thread::cancelGroupExecution();
394 template<
typename Gr
idT,
typename InterruptT>
395 template<
typename MaskT>
400 switch (this->getSpatialScheme()) {
402 this->normalize1<math::FIRST_BIAS , MaskT>(
mask);
break;
404 this->normalize1<math::SECOND_BIAS, MaskT>(
mask);
break;
406 this->normalize1<math::THIRD_BIAS, MaskT>(
mask);
break;
408 this->normalize1<math::WENO5_BIAS, MaskT>(
mask);
break;
410 this->normalize1<math::HJWENO5_BIAS, MaskT>(
mask);
break;
413 OPENVDB_THROW(ValueError,
"Spatial difference scheme not supported!");
417 template<
typename Gr
idT,
typename InterruptT>
418 template<math::BiasedGradientScheme SpatialScheme,
typename MaskT>
423 switch (this->getTemporalScheme()) {
425 this->normalize2<SpatialScheme, math::TVD_RK1, MaskT>(
mask);
break;
427 this->normalize2<SpatialScheme, math::TVD_RK2, MaskT>(
mask);
break;
429 this->normalize2<SpatialScheme, math::TVD_RK3, MaskT>(
mask);
break;
432 OPENVDB_THROW(ValueError,
"Temporal integration scheme not supported!");
436 template<
typename Gr
idT,
typename InterruptT>
441 LevelSetTracker<GridT, InterruptT>::
442 normalize2(
const MaskT* mask)
444 Normalizer<SpatialScheme, TemporalScheme, MaskT> tmp(*
this, mask);
452 template<
typename Gr
idT,
typename InterruptT>
453 template<lstrack::TrimMode Trimming>
458 if (Trimming != TrimMode::kNone) {
459 const int grainSize = mTracker.getGrainSize();
460 const LeafRange
range = mTracker.leafs().leafRange(grainSize);
473 template<
typename Gr
idT,
typename InterruptT>
474 template<lstrack::TrimMode Trimming>
476 LevelSetTracker<GridT, InterruptT>::Trim<Trimming>::operator()(
const LeafRange& range)
const
478 mTracker.checkInterrupter();
479 const ValueType gamma = mTracker.mGrid->background();
482 for (
auto leafIter = range.begin(); leafIter; ++leafIter) {
483 auto& leaf = *leafIter;
484 for (
auto iter = leaf.beginValueOn(); iter; ++iter) {
485 const auto val = *iter;
487 case TrimMode::kNone:
489 case TrimMode::kInterior:
490 if (
val <= -gamma) { leaf.setValueOff(iter.pos(), -gamma); }
492 case TrimMode::kExterior:
493 if (
val >= gamma) { leaf.setValueOff(iter.pos(), gamma); }
497 leaf.setValueOff(iter.pos(), -gamma);
498 }
else if (
val >= gamma) {
499 leaf.setValueOff(iter.pos(), gamma);
511 template<
typename Gr
idT,
typename InterruptT>
516 LevelSetTracker<GridT, InterruptT>::
517 Normalizer<SpatialScheme, TemporalScheme, MaskT>::
518 Normalizer(LevelSetTracker& tracker,
const MaskT* mask)
521 , mDt(tracker.voxelSize()*(TemporalScheme == math::
TVD_RK1 ? 0.3
f :
522 TemporalScheme == math::
TVD_RK2 ? 0.9
f : 1.0
f))
523 , mInvDx(1.0
f/tracker.voxelSize())
528 template<
typename Gr
idT,
typename InterruptT>
537 namespace ph = std::placeholders;
540 mTracker.mLeafs->rebuildAuxBuffers(TemporalScheme ==
math::TVD_RK3 ? 2 : 1);
542 for (
int n=0, e=mTracker.getNormCount();
n < e; ++
n) {
545 switch(TemporalScheme) {
549 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
552 this->cook(
"Normalizing level set using TVD_RK1", 1);
557 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
560 this->cook(
"Normalizing level set using TVD_RK1 (step 1 of 2)", 1);
564 mTask = std::bind(&Normalizer::euler12, ph::_1, ph::_2);
567 this->cook(
"Normalizing level set using TVD_RK1 (step 2 of 2)", 1);
572 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
575 this->cook(
"Normalizing level set using TVD_RK3 (step 1 of 3)", 1);
579 mTask = std::bind(&Normalizer::euler34, ph::_1, ph::_2);
582 this->cook(
"Normalizing level set using TVD_RK3 (step 2 of 3)", 2);
586 mTask = std::bind(&Normalizer::euler13, ph::_1, ph::_2);
589 this->cook(
"Normalizing level set using TVD_RK3 (step 3 of 3)", 2);
593 OPENVDB_THROW(ValueError,
"Temporal integration scheme not supported!");
597 mTracker.mLeafs->removeAuxBuffers();
602 template<
typename Gr
idT,
typename InterruptT>
607 LevelSetTracker<GridT, InterruptT>::
608 Normalizer<SpatialScheme, TemporalScheme, MaskT>::
609 cook(
const char* msg,
int swapBuffer)
611 mTracker.startInterrupter( msg );
613 const int grainSize = mTracker.getGrainSize();
614 const LeafRange range = mTracker.leafs().leafRange(grainSize);
618 mTracker.leafs().swapLeafBuffer(swapBuffer, grainSize==0);
620 mTracker.endInterrupter();
623 template<
typename Gr
idT,
typename InterruptT>
627 template <
int Nominator,
int Denominator>
633 using GradientT =
typename math::ISGradientNormSqrd<SpatialScheme>;
634 static const ValueType
alpha = ValueType(Nominator)/ValueType(Denominator);
635 static const ValueType beta = ValueType(1) -
alpha;
638 const ValueType phi0 = stencil.getValue();
641 v = phi0 - mDt * v * (
math::Sqrt(normSqGradPhi) * mInvDx - 1.0f);
642 result[
n] = Nominator ? alpha * phi[
n] + beta * v :
v;
645 template<
typename Gr
idT,
typename InterruptT>
649 template <
int Nominator,
int Denominator>
651 LevelSetTracker<GridT,InterruptT>::
652 Normalizer<SpatialScheme, TemporalScheme, MaskT>::
653 euler(
const LeafRange& range,
Index phiBuffer,
Index resultBuffer)
655 mTracker.checkInterrupter();
657 StencilT
stencil(mTracker.grid());
659 for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
660 const ValueType* phi = leafIter.buffer(phiBuffer).data();
661 ValueType* result = leafIter.buffer(resultBuffer).data();
662 if (mMask ==
nullptr) {
663 for (
auto iter = leafIter->cbeginValueOn(); iter; ++iter) {
664 stencil.moveTo(iter);
665 this->eval<Nominator, Denominator>(
stencil, phi,
result, iter.pos());
667 }
else if (
const MaskLeafT* mask = mMask->probeLeaf(leafIter->origin())) {
668 const ValueType* phi0 = leafIter->buffer().data();
669 for (MaskIterT iter = mask->cbeginValueOn(); iter; ++iter) {
670 const Index i = iter.pos();
671 stencil.moveTo(iter.getCoord(), phi0[i]);
684 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
686 #ifdef OPENVDB_INSTANTIATE_LEVELSETTRACKER
693 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
700 #endif // OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
TemporalIntegrationScheme
Temporal integration schemes.
Type Pow2(Type x)
Return x2.
GLsizei const GLfloat * value
#define OPENVDB_USE_VERSION_NAMESPACE
**But if you need a or simply need to know when the task has note that the like this
**But if you need a result
float RoundDown(float x)
Return x rounded down to the nearest integer.
BiasedGradientScheme
Biased Gradients are limited to non-centered differences.
#define OPENVDB_INSTANTIATE_CLASS
ValueAccessors are designed to help accelerate accesses into the OpenVDB Tree structures by storing c...
ImageBuf OIIO_API dilate(const ImageBuf &src, int width=3, int height=-1, ROI roi={}, int nthreads=0)
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Efficient multi-threaded replacement of the background values in tree.
ImageBuf OIIO_API erode(const ImageBuf &src, int width=3, int height=-1, ROI roi={}, int nthreads=0)
float Sqrt(float x)
Return the square root of a floating-point value.
Defined various multi-threaded utility functions for trees.
GLfloat GLfloat GLfloat alpha
HUSD_API bool eval(VtValue &val, T &ret_val)
void trim(std::string &s)
Implementation of morphological dilation and erosion.
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
GLint GLfloat GLint stencil
bool wasInterrupted(T *i, int percent=-1)
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
#define OPENVDB_THROW(exception, message)