15#ifndef OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
16#define OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED
36template<
typename GridT,
37 typename MaskT =
typename GridT::template ValueConverter<float>::Type,
38 typename InterruptT = util::NullInterrupter>
48 static_assert(std::is_floating_point<AlphaType>::value,
49 "LevelSetFilter requires a mask grid with floating-point values");
89 void invertMask(
bool invert=
true) { mInvertMask = invert; }
95 Filter f(
this, mask); f.meanCurvature();
112 Filter f(
this, mask); f.fillet();
119 Filter f(
this, mask); f.laplacian();
130 Filter f(
this, mask); f.gaussian(width);
138 Filter f(
this, mask); f.offset(
offset);
149 Filter f(
this, mask); f.median(width);
159 Filter f(
this, mask); f.mean(width);
170 using LeafT =
typename TreeType::LeafNodeType;
171 using VoxelIterT =
typename LeafT::ValueOnIter;
172 using VoxelCIterT =
typename LeafT::ValueOnCIter;
175 using LeafIterT =
typename LeafRange::Iterator;
179 Filter(
const Filter&) =
default;
183 void median(
int width);
184 void mean(
int width);
185 void gaussian(
int width);
187 void meanCurvature();
189 void offset(ValueType value);
190 void operator()(
const LeafRange& r)
const
192 if (mTask) mTask(
const_cast<Filter*
>(
this), r);
197 const int n = mParent->getGrainSize();
199 tbb::parallel_for(mParent->leafs().leafRange(n), *
this);
201 (*this)(mParent->leafs().leafRange());
203 if (swap) mParent->leafs().swapLeafBuffer(1, n==0);
206 template <
size_t Axis>
214 for (i -=
width; i <= j; ++i) sum +=
acc.getValue(xyz);
217 typename GridT::ConstAccessor
acc;
222 template<
typename AvgT>
223 void boxImpl(
const LeafRange& r,
Int32 w);
225 void boxXImpl(
const LeafRange& r,
Int32 w) { this->boxImpl<Avg<0> >(r,w); }
226 void boxZImpl(
const LeafRange& r,
Int32 w) { this->boxImpl<Avg<1> >(r,w); }
227 void boxYImpl(
const LeafRange& r,
Int32 w) { this->boxImpl<Avg<2> >(r,w); }
229 void medianImpl(
const LeafRange&,
int);
230 void meanCurvatureImpl(
const LeafRange&);
231 void filletImpl(
const LeafRange&);
232 void laplacianImpl(
const LeafRange&);
233 void offsetImpl(
const LeafRange&, ValueType);
235 LevelSetFilter* mParent;
236 const MaskType* mMask;
237 typename std::function<void (Filter*,
const LeafRange&)> mTask;
240 AlphaType mMinMask, mMaxMask;
248template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
250LevelSetFilter<GridT, MaskT, InterruptT>::Filter::median(
int width)
252 mParent->startInterrupter(
"Median-value flow of level set");
254 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
256 mTask = std::bind(&Filter::medianImpl,
257 std::placeholders::_1, std::placeholders::_2, std::max(1, width));
262 mParent->endInterrupter();
265template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
267LevelSetFilter<GridT, MaskT, InterruptT>::Filter::mean(
int width)
269 mParent->startInterrupter(
"Mean-value flow of level set");
273 mParent->endInterrupter();
276template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
278LevelSetFilter<GridT, MaskT, InterruptT>::Filter::gaussian(
int width)
280 mParent->startInterrupter(
"Gaussian flow of level set");
282 for (
int n=0; n<4; ++n) this->box(width);
284 mParent->endInterrupter();
287template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
289LevelSetFilter<GridT, MaskT, InterruptT>::Filter::box(
int width)
291 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
293 width = std::max(1, width);
295 mTask = std::bind(&Filter::boxXImpl, std::placeholders::_1, std::placeholders::_2, width);
298 mTask = std::bind(&Filter::boxYImpl, std::placeholders::_1, std::placeholders::_2, width);
301 mTask = std::bind(&Filter::boxZImpl, std::placeholders::_1, std::placeholders::_2, width);
307template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
309LevelSetFilter<GridT, MaskT, InterruptT>::Filter::meanCurvature()
311 mParent->startInterrupter(
"Mean-curvature flow of level set");
313 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
315 mTask = std::bind(&Filter::meanCurvatureImpl, std::placeholders::_1, std::placeholders::_2);
320 mParent->endInterrupter();
323template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
325LevelSetFilter<GridT, MaskT, InterruptT>::Filter::fillet()
327 mParent->startInterrupter(
"Filleting level set");
329 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
331 mTask = std::bind(&Filter::filletImpl, std::placeholders::_1, std::placeholders::_2);
336 mParent->endInterrupter();
339template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
341LevelSetFilter<GridT, MaskT, InterruptT>::Filter::laplacian()
343 mParent->startInterrupter(
"Laplacian flow of level set");
345 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
347 mTask = std::bind(&Filter::laplacianImpl, std::placeholders::_1, std::placeholders::_2);
352 mParent->endInterrupter();
355template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
357LevelSetFilter<GridT, MaskT, InterruptT>::Filter::offset(ValueType value)
359 mParent->startInterrupter(
"Offsetting level set");
361 mParent->leafs().removeAuxBuffers();
363 const ValueType CFL = ValueType(0.5) * mParent->voxelSize(), offset = openvdb::math::Abs(value);
364 ValueType dist = 0.0;
365 while (offset-dist > ValueType(0.001)*CFL && mParent->checkInterrupter()) {
366 const ValueType delta = openvdb::math::Min(offset-dist, CFL);
369 mTask = std::bind(&Filter::offsetImpl,
370 std::placeholders::_1, std::placeholders::_2, copysign(delta, value));
376 mParent->endInterrupter();
383template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
385LevelSetFilter<GridT, MaskT, InterruptT>::Filter::meanCurvatureImpl(
const LeafRange& range)
387 mParent->checkInterrupter();
389 const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(3.0);
390 math::CurvatureStencil<GridType> stencil(mParent->grid(), dx);
392 typename AlphaMaskT::FloatType a, b;
393 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
394 mParent->maxMask(), mParent->isMaskInverted());
395 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
396 ValueType* buffer = leafIter.buffer(1).data();
397 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
398 if (alpha(iter.getCoord(), a, b)) {
399 stencil.moveTo(iter);
400 const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.meanCurvatureNormGrad();
401 buffer[iter.pos()] = b * phi0 + a * phi1;
406 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
407 ValueType* buffer = leafIter.buffer(1).data();
408 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
409 stencil.moveTo(iter);
410 buffer[iter.pos()] = *iter + dt*stencil.meanCurvatureNormGrad();
420template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
422LevelSetFilter<GridT, MaskT, InterruptT>::Filter::filletImpl(
const LeafRange& range)
424 mParent->checkInterrupter();
426 const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(3);
427 math::CurvatureStencil<GridType> stencil(mParent->grid(), dx);
430 typename AlphaMaskT::FloatType a, b;
431 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
432 mParent->maxMask(), mParent->isMaskInverted());
433 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
434 ValueType* buffer = leafIter.buffer(1).data();
435 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
436 if (alpha(iter.getCoord(), a, b)) {
437 stencil.moveTo(iter);
439 const ValueType kappa = stencil.principalCurvatures().first;
441 const ValueType phi0 = *iter,
442 phi1 = phi0 + math::Min(ValueType(0), dt*kappa);
443 buffer[iter.pos()] = b * phi0 + a * phi1;
448 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
449 ValueType* buffer = leafIter.buffer(1).data();
450 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
451 stencil.moveTo(iter);
453 const ValueType kappa = stencil.principalCurvatures().first;
455 if (math::isNegative(kappa))
456 buffer[iter.pos()] = *iter + dt*kappa;
469template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
471LevelSetFilter<GridT, MaskT, InterruptT>::Filter::laplacianImpl(
const LeafRange& range)
473 mParent->checkInterrupter();
475 const ValueType dx = mParent->voxelSize(), dt = math::Pow2(dx) / ValueType(6.0);
476 math::GradStencil<GridType> stencil(mParent->grid(), dx);
478 typename AlphaMaskT::FloatType a, b;
479 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
480 mParent->maxMask(), mParent->isMaskInverted());
481 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
482 ValueType* buffer = leafIter.buffer(1).data();
483 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
484 if (alpha(iter.getCoord(), a, b)) {
485 stencil.moveTo(iter);
486 const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.laplacian();
487 buffer[iter.pos()] = b * phi0 + a * phi1;
492 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
493 ValueType* buffer = leafIter.buffer(1).data();
494 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
495 stencil.moveTo(iter);
496 buffer[iter.pos()] = *iter + dt*stencil.laplacian();
503template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
505LevelSetFilter<GridT, MaskT, InterruptT>::Filter::offsetImpl(
506 const LeafRange& range, ValueType offset)
508 mParent->checkInterrupter();
510 typename AlphaMaskT::FloatType a, b;
511 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
512 mParent->maxMask(), mParent->isMaskInverted());
513 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
514 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
515 if (alpha(iter.getCoord(), a, b)) iter.setValue(*iter + a*offset);
519 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
520 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
521 iter.setValue(*iter + offset);
528template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
530LevelSetFilter<GridT, MaskT, InterruptT>::Filter::medianImpl(
const LeafRange& range,
int width)
532 mParent->checkInterrupter();
533 typename math::DenseStencil<GridType> stencil(mParent->grid(), width);
535 typename AlphaMaskT::FloatType a, b;
536 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
537 mParent->maxMask(), mParent->isMaskInverted());
538 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
539 ValueType* buffer = leafIter.buffer(1).data();
540 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
541 if (alpha(iter.getCoord(), a, b)) {
542 stencil.moveTo(iter);
543 buffer[iter.pos()] = b * (*iter) + a * stencil.median();
548 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
549 ValueType* buffer = leafIter.buffer(1).data();
550 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
551 stencil.moveTo(iter);
552 buffer[iter.pos()] = stencil.median();
559template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
560template <
typename AvgT>
562LevelSetFilter<GridT, MaskT, InterruptT>::Filter::boxImpl(
const LeafRange& range, Int32 w)
564 mParent->checkInterrupter();
565 AvgT avg(mParent->grid(), w);
567 typename AlphaMaskT::FloatType a, b;
568 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
569 mParent->maxMask(), mParent->isMaskInverted());
570 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
571 ValueType* buffer = leafIter.buffer(1).data();
572 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
573 const Coord xyz = iter.getCoord();
574 if (alpha(xyz, a, b)) buffer[iter.pos()] = b * (*iter)+ a * avg(xyz);
578 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
579 ValueType* buffer = leafIter.buffer(1).data();
580 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
581 buffer[iter.pos()] = avg(iter.getCoord());
593#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
595#ifdef OPENVDB_INSTANTIATE_LEVELSETFILTER
Performs multi-threaded interface tracking of narrow band level sets. This is the building-block for ...
Definition Exceptions.h:65
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Definition LeafManager.h:103
typename CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition LeafManager.h:96
Definition PointDataGrid.h:170
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
int32_t Int32
Definition Types.h:56
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218
#define OPENVDB_INSTANTIATE_CLASS
Definition version.h.in:158