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>
226 void euler(
const LeafRange&
range, Index phiBuffer, Index resultBuffer);
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>;
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.
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)