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>
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();
102 Filter f(
this, mask); f.laplacian();
113 Filter f(
this, mask); f.gaussian(width);
121 Filter f(
this, mask); f.offset(offset);
132 Filter f(
this, mask); f.median(width);
142 Filter f(
this, mask); f.mean(width);
153 using LeafT =
typename TreeType::LeafNodeType;
154 using VoxelIterT =
typename LeafT::ValueOnIter;
155 using VoxelCIterT =
typename LeafT::ValueOnCIter;
158 using LeafIterT =
typename LeafRange::Iterator;
162 Filter(
const Filter&) =
default;
166 void median(
int width);
167 void mean(
int width);
168 void gaussian(
int width);
171 void offset(ValueType
value);
172 void operator()(
const LeafRange& r)
const
174 if (mTask) mTask(
const_cast<Filter*
>(
this), r);
179 const int n = mParent->getGrainSize();
181 tbb::parallel_for(mParent->leafs().leafRange(n), *
this);
183 (*this)(mParent->leafs().leafRange());
185 if (swap) mParent->leafs().swapLeafBuffer(1, n==0);
188 template <
size_t Axis>
191 acc(grid.tree()), width(w), frac(1/
ValueType(2*w+1)) {}
196 for (i -= width; i <= j; ++i) sum += acc.getValue(xyz);
199 typename GridT::ConstAccessor
acc;
204 template<
typename AvgT>
205 void boxImpl(
const LeafRange& r,
Int32 w);
207 void boxXImpl(
const LeafRange& r,
Int32 w) { this->boxImpl<Avg<0> >(r,w); }
208 void boxZImpl(
const LeafRange& r,
Int32 w) { this->boxImpl<Avg<1> >(r,w); }
209 void boxYImpl(
const LeafRange& r,
Int32 w) { this->boxImpl<Avg<2> >(r,w); }
211 void medianImpl(
const LeafRange&,
int);
212 void meanCurvatureImpl(
const LeafRange&);
213 void laplacianImpl(
const LeafRange&);
214 void offsetImpl(
const LeafRange&, ValueType);
216 LevelSetFilter* mParent;
217 const MaskType* mMask;
218 typename std::function<void (Filter*,
const LeafRange&)> mTask;
221 AlphaType mMinMask, mMaxMask;
229template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
231LevelSetFilter<GridT, MaskT, InterruptT>::Filter::median(
int width)
233 mParent->startInterrupter(
"Median-value flow of level set");
235 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
237 mTask = std::bind(&Filter::medianImpl,
238 std::placeholders::_1, std::placeholders::_2,
std::max(1, width));
243 mParent->endInterrupter();
246template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
248LevelSetFilter<GridT, MaskT, InterruptT>::Filter::mean(
int width)
250 mParent->startInterrupter(
"Mean-value flow of level set");
254 mParent->endInterrupter();
257template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
259LevelSetFilter<GridT, MaskT, InterruptT>::Filter::gaussian(
int width)
261 mParent->startInterrupter(
"Gaussian flow of level set");
263 for (
int n=0; n<4; ++n) this->box(width);
265 mParent->endInterrupter();
268template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
270LevelSetFilter<GridT, MaskT, InterruptT>::Filter::box(
int width)
272 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
276 mTask = std::bind(&Filter::boxXImpl, std::placeholders::_1, std::placeholders::_2, width);
279 mTask = std::bind(&Filter::boxYImpl, std::placeholders::_1, std::placeholders::_2, width);
282 mTask = std::bind(&Filter::boxZImpl, std::placeholders::_1, std::placeholders::_2, width);
288template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
292 mParent->startInterrupter(
"Mean-curvature flow of level set");
294 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
296 mTask = std::bind(&Filter::meanCurvatureImpl, std::placeholders::_1, std::placeholders::_2);
301 mParent->endInterrupter();
304template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
308 mParent->startInterrupter(
"Laplacian flow of level set");
310 mParent->leafs().rebuildAuxBuffers(1, mParent->getGrainSize()==0);
312 mTask = std::bind(&Filter::laplacianImpl, std::placeholders::_1, std::placeholders::_2);
317 mParent->endInterrupter();
320template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
322LevelSetFilter<GridT, MaskT, InterruptT>::Filter::offset(ValueType
value)
324 mParent->startInterrupter(
"Offsetting level set");
326 mParent->leafs().removeAuxBuffers();
329 ValueType dist = 0.0;
330 while (offset-dist > ValueType(0.001)*CFL && mParent->checkInterrupter()) {
334 mTask = std::bind(&Filter::offsetImpl,
335 std::placeholders::_1, std::placeholders::_2, copysign(delta,
value));
341 mParent->endInterrupter();
348template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
350LevelSetFilter<GridT, MaskT, InterruptT>::Filter::meanCurvatureImpl(
const LeafRange& range)
352 mParent->checkInterrupter();
354 const ValueType dx = mParent->voxelSize(), dt =
math::Pow2(dx) / ValueType(3.0);
355 math::CurvatureStencil<GridType> stencil(mParent->grid(), dx);
357 typename AlphaMaskT::FloatType a, b;
358 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
359 mParent->maxMask(), mParent->isMaskInverted());
360 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
361 ValueType* buffer = leafIter.buffer(1).data();
362 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
363 if (alpha(iter.getCoord(), a, b)) {
364 stencil.moveTo(iter);
365 const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.meanCurvatureNormGrad();
366 buffer[iter.pos()] = b * phi0 + a * phi1;
371 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
372 ValueType* buffer = leafIter.buffer(1).data();
373 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
374 stencil.moveTo(iter);
375 buffer[iter.pos()] = *iter + dt*stencil.meanCurvatureNormGrad();
388template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
390LevelSetFilter<GridT, MaskT, InterruptT>::Filter::laplacianImpl(
const LeafRange& range)
392 mParent->checkInterrupter();
394 const ValueType dx = mParent->voxelSize(), dt =
math::Pow2(dx) / ValueType(6.0);
395 math::GradStencil<GridType> stencil(mParent->grid(), dx);
397 typename AlphaMaskT::FloatType a, b;
398 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
399 mParent->maxMask(), mParent->isMaskInverted());
400 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
401 ValueType* buffer = leafIter.buffer(1).data();
402 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
403 if (alpha(iter.getCoord(), a, b)) {
404 stencil.moveTo(iter);
405 const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.laplacian();
406 buffer[iter.pos()] = b * phi0 + a * phi1;
411 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
412 ValueType* buffer = leafIter.buffer(1).data();
413 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
414 stencil.moveTo(iter);
415 buffer[iter.pos()] = *iter + dt*stencil.laplacian();
422template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
424LevelSetFilter<GridT, MaskT, InterruptT>::Filter::offsetImpl(
425 const LeafRange& range, ValueType offset)
427 mParent->checkInterrupter();
429 typename AlphaMaskT::FloatType a, b;
430 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
431 mParent->maxMask(), mParent->isMaskInverted());
432 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
433 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
434 if (alpha(iter.getCoord(), a, b)) iter.setValue(*iter + a*offset);
438 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
439 for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) {
440 iter.setValue(*iter + offset);
447template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
449LevelSetFilter<GridT, MaskT, InterruptT>::Filter::medianImpl(
const LeafRange& range,
int width)
451 mParent->checkInterrupter();
452 typename math::DenseStencil<GridType> stencil(mParent->grid(), width);
454 typename AlphaMaskT::FloatType a, b;
455 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
456 mParent->maxMask(), mParent->isMaskInverted());
457 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
458 ValueType* buffer = leafIter.buffer(1).data();
459 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
460 if (alpha(iter.getCoord(), a, b)) {
461 stencil.moveTo(iter);
462 buffer[iter.pos()] = b * (*iter) + a * stencil.median();
467 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
468 ValueType* buffer = leafIter.buffer(1).data();
469 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
470 stencil.moveTo(iter);
471 buffer[iter.pos()] = stencil.median();
478template<
typename Gr
idT,
typename MaskT,
typename InterruptT>
479template <
typename AvgT>
481LevelSetFilter<GridT, MaskT, InterruptT>::Filter::boxImpl(
const LeafRange& range, Int32 w)
483 mParent->checkInterrupter();
484 AvgT avg(mParent->grid(), w);
486 typename AlphaMaskT::FloatType a, b;
487 AlphaMaskT alpha(mParent->grid(), *mMask, mParent->minMask(),
488 mParent->maxMask(), mParent->isMaskInverted());
489 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
490 ValueType* buffer = leafIter.buffer(1).data();
491 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
492 const Coord xyz = iter.getCoord();
493 if (alpha(xyz, a, b)) buffer[iter.pos()] = b * (*iter)+ a * avg(xyz);
497 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
498 ValueType* buffer = leafIter.buffer(1).data();
499 for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) {
500 buffer[iter.pos()] = avg(iter.getCoord());
512#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
514#ifdef OPENVDB_INSTANTIATE_LEVELSETFILTER
#define OPENVDB_INSTANTIATE_CLASS
Definition: ExplicitInstantiation.h:12
ValueT value
Definition: GridBuilder.h:1287
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:25
Definition: LeafManager.h:102
typename CopyConstness< TreeType, NonConstBufferType >::Type BufferType
Definition: LeafManager.h:95
Type Min(Type a, Type b)
Definition: NanoVDB.h:651
T Abs(T x)
Definition: NanoVDB.h:747
T Pow2(T x)
Definition: NanoVDB.h:730
Axis
Definition: Math.h:904
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:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202