OpenVDB 12.0.0
 
Loading...
Searching...
No Matches
LevelSetTracker.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @author Ken Museth
5///
6/// @file tools/LevelSetTracker.h
7///
8/// @brief Performs multi-threaded interface tracking of narrow band
9/// level sets. This is the building-block for most level set
10/// computations that involve dynamic topology, e.g. advection.
11
12#ifndef OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED
13#define OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED
14
15#include <openvdb/Types.h>
16#include <openvdb/Grid.h>
17#include <openvdb/math/Math.h>
23#include <openvdb/thread/Threading.h>
26#include "ChangeBackground.h"// for changeLevelSetBackground
27#include "Morphology.h"//for dilateActiveValues
28#include "Prune.h"// for pruneLevelSet
29
30#include <tbb/parallel_for.h>
31
32#include <functional>
33#include <type_traits>
34
35namespace openvdb {
37namespace OPENVDB_VERSION_NAME {
38namespace tools {
39
40namespace lstrack {
41
42/// @brief How to handle voxels that fall outside the narrow band
43/// @sa @link LevelSetTracker::trimming() trimming@endlink,
44/// @link LevelSetTracker::setTrimming() setTrimming@endlink
45enum class TrimMode {
46 kNone, ///< Leave out-of-band voxels intact
47 kInterior, ///< Set out-of-band interior voxels to the background value
48 kExterior, ///< Set out-of-band exterior voxels to the background value
49 kAll ///< Set all out-of-band voxels to the background value
50};
51
52} // namespace lstrack
53
54
55/// @brief Performs multi-threaded interface tracking of narrow band level sets
56template<typename GridT, typename InterruptT = util::NullInterrupter>
58{
59public:
61
62 using GridType = GridT;
63 using TreeType = typename GridT::TreeType;
64 using LeafType = typename TreeType::LeafNodeType;
65 using ValueType = typename TreeType::ValueType;
66 using LeafManagerType = typename tree::LeafManager<TreeType>; // leafs + buffers
67 using LeafRange = typename LeafManagerType::LeafRange;
68 using BufferType = typename LeafManagerType::BufferType;
69 using MaskTreeType = typename TreeType::template ValueConverter<ValueMask>::Type;
70 static_assert(std::is_floating_point<ValueType>::value,
71 "LevelSetTracker requires a level set grid with floating-point values");
72
73 /// Lightweight struct that stores the state of the LevelSetTracker
84
85 /// @brief Main constructor
86 /// @throw RuntimeError if the grid is not a level set
87 LevelSetTracker(GridT& grid, InterruptT* interrupt = nullptr);
88
89 virtual ~LevelSetTracker() { delete mLeafs; }
90
91 /// @brief Iterative normalization, i.e. solving the Eikonal equation
92 /// @note The mask it optional and by default it is ignored.
93 template <typename MaskType>
94 void normalize(const MaskType* mask);
95
96 /// @brief Iterative normalization, i.e. solving the Eikonal equation
97 void normalize() { this->normalize<MaskTreeType>(nullptr); }
98
99 /// @brief Track the level set interface, i.e. rebuild and normalize the
100 /// narrow band of the level set.
101 void track();
102
103 /// @brief Set voxels that are outside the narrow band to the background value
104 /// (if trimming is enabled) and prune the grid.
105 /// @details Pruning is done automatically as a step in tracking.
106 /// @sa @link setTrimming() setTrimming@endlink, @link trimming() trimming@endlink
107 void prune();
108
109 /// @brief Fast but approximate dilation of the narrow band - one
110 /// layer at a time. Normally we recommend using the resize method below
111 /// which internally calls dilate (or erode) with the correct
112 /// number of @a iterations to achieve the desired half voxel width
113 /// of the narrow band (3 is recommended for most level set applications).
114 ///
115 /// @note Since many level set applications perform
116 /// interface-tracking, which in turn rebuilds the narrow-band
117 /// accurately, this dilate method can often be used with a
118 /// single iterations of low-order re-normalization. This
119 /// effectively allows very narrow bands to be created from points
120 /// or polygons (e.g. with a half voxel width of 1), followed by a
121 /// fast but approximate dilation (typically with a half voxel
122 /// width of 3). This can be significantly faster than generating
123 /// the final width of the narrow band from points or polygons.
124 void dilate(int iterations = 1);
125
126 /// @brief Erodes the width of the narrow-band and update the background values
127 /// @throw ValueError if @a iterations is larger than the current half-width.
128 void erode(int iterations = 1);
129
130 /// @brief Resize the width of the narrow band, i.e. perform
131 /// dilation and renormalization or erosion as required.
132 bool resize(Index halfWidth = static_cast<Index>(LEVEL_SET_HALF_WIDTH));
133
134 /// @brief Return the half width of the narrow band in floating-point voxel units.
135 ValueType getHalfWidth() const { return mGrid->background()/mDx; }
136
137 /// @brief Return the state of the tracker (see struct defined above)
138 State getState() const { return mState; }
139
140 /// @brief Set the state of the tracker (see struct defined above)
141 void setState(const State& s) { mState = s; }
142
143 /// @return the spatial finite difference scheme
144 math::BiasedGradientScheme getSpatialScheme() const { return mState.spatialScheme; }
145
146 /// @brief Set the spatial finite difference scheme
147 void setSpatialScheme(math::BiasedGradientScheme s) { mState.spatialScheme = s; }
148
149 /// @return the temporal integration scheme
150 math::TemporalIntegrationScheme getTemporalScheme() const { return mState.temporalScheme; }
151
152 /// @brief Set the spatial finite difference scheme
153 void setTemporalScheme(math::TemporalIntegrationScheme s) { mState.temporalScheme = s;}
154
155 /// @return The number of normalizations performed per track or
156 /// normalize call.
157 int getNormCount() const { return mState.normCount; }
158
159 /// @brief Set the number of normalizations performed per track or
160 /// normalize call.
161 void setNormCount(int n) { mState.normCount = n; }
162
163 /// @return the grain-size used for multi-threading
164 int getGrainSize() const { return mState.grainSize; }
165
166 /// @brief Set the grain-size used for multi-threading.
167 /// @note A grainsize of 0 or less disables multi-threading!
168 void setGrainSize(int grainsize) { mState.grainSize = grainsize; }
169
170 /// @brief Return the trimming mode for voxels outside the narrow band.
171 /// @details Trimming is enabled by default and is applied automatically prior to pruning.
172 /// @sa @link setTrimming() setTrimming@endlink, @link prune() prune@endlink
173 TrimMode trimming() const { return mTrimMode; }
174 /// @brief Specify whether to trim voxels outside the narrow band prior to pruning.
175 /// @sa @link trimming() trimming@endlink, @link prune() prune@endlink
176 void setTrimming(TrimMode mode) { mTrimMode = mode; }
177
178 ValueType voxelSize() const { return mDx; }
179
180 void startInterrupter(const char* msg);
181
183
184 /// @return false if the process was interrupted
186
187 const GridType& grid() const { return *mGrid; }
188
189 LeafManagerType& leafs() { return *mLeafs; }
190
191 const LeafManagerType& leafs() const { return *mLeafs; }
192
193private:
194 // disallow copy construction and copy by assignment!
195 LevelSetTracker(const LevelSetTracker&);// not implemented
196 LevelSetTracker& operator=(const LevelSetTracker&);// not implemented
197
198 // Private class to perform multi-threaded trimming of
199 // voxels that are too far away from the zero-crossing.
200 template<TrimMode Trimming>
201 struct Trim
202 {
203 Trim(LevelSetTracker& tracker) : mTracker(tracker) {}
204 void trim();
205 void operator()(const LeafRange& r) const;
206 LevelSetTracker& mTracker;
207 };// Trim
208
209 // Private struct to perform multi-threaded normalization
210 template<math::BiasedGradientScheme SpatialScheme,
211 math::TemporalIntegrationScheme TemporalScheme,
212 typename MaskT>
213 struct Normalizer
214 {
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;
220
221 Normalizer(LevelSetTracker& tracker, const MaskT* mask);
222 void normalize();
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>
232 void eval(StencilT& stencil, const ValueType* phi, ValueType* result, Index n) const;
233 LevelSetTracker& mTracker;
234 const MaskT* mMask;
235 const ValueType mDt, mInvDx;
236 typename std::function<void (Normalizer*, const LeafRange&)> mTask;
237 }; // Normalizer struct
238
239 template<math::BiasedGradientScheme SpatialScheme, typename MaskT>
240 void normalize1(const MaskT* mask);
241
242 template<math::BiasedGradientScheme SpatialScheme,
243 math::TemporalIntegrationScheme TemporalScheme, typename MaskT>
244 void normalize2(const MaskT* mask);
245
246 // Throughout the methods below mLeafs is always assumed to contain
247 // a list of the current LeafNodes! The auxiliary buffers on the
248 // other hand always have to be allocated locally, since some
249 // methods need them and others don't!
250 GridType* mGrid;
251 LeafManagerType* mLeafs;
252 InterruptT* mInterrupter;
253 const ValueType mDx;
254 State mState;
255 TrimMode mTrimMode = TrimMode::kAll;
256}; // end of LevelSetTracker class
257
258template<typename GridT, typename InterruptT>
260LevelSetTracker(GridT& grid, InterruptT* interrupt):
261 mGrid(&grid),
262 mLeafs(new LeafManagerType(grid.tree())),
263 mInterrupter(interrupt),
264 mDx(static_cast<ValueType>(grid.voxelSize()[0])),
265 mState()
266{
267 if ( !grid.hasUniformVoxels() ) {
268 OPENVDB_THROW(RuntimeError,
269 "The transform must have uniform scale for the LevelSetTracker to function");
270 }
271 if ( grid.getGridClass() != GRID_LEVEL_SET) {
272 OPENVDB_THROW(RuntimeError,
273 "LevelSetTracker expected a level set, got a grid of class \""
274 + grid.gridClassToString(grid.getGridClass())
275 + "\" [hint: Grid::setGridClass(openvdb::GRID_LEVEL_SET)]");
276 }
277}
278
279template<typename GridT, typename InterruptT>
280void
282prune()
283{
284 this->startInterrupter("Pruning Level Set");
285
286 // Set voxels that are too far away from the zero crossing to the background value.
287 switch (mTrimMode) {
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;
292 }
293
294 // Remove inactive nodes from tree
295 tools::pruneLevelSet(mGrid->tree());
296
297 // The tree topology has changes so rebuild the list of leafs
298 mLeafs->rebuildLeafArray();
299 this->endInterrupter();
300}
301
302template<typename GridT, typename InterruptT>
303void
305track()
306{
307 // Dilate narrow-band (this also rebuilds the leaf array!)
309
310 // Compute signed distances in dilated narrow-band
311 this->normalize();
312
313 // Remove voxels that are outside the narrow band
314 this->prune();
315}
316
317template<typename GridT, typename InterruptT>
318void
320dilate(int iterations)
321{
322 if (this->getNormCount() == 0) {
323 for (int i=0; i < iterations; ++i) {
325 tools::changeLevelSetBackground(this->leafs(), mDx + mGrid->background());
326 }
327 } else {
328 for (int i=0; i < iterations; ++i) {
329 MaskTreeType mask0(mGrid->tree(), false, TopologyCopy());
331 tools::changeLevelSetBackground(this->leafs(), mDx + mGrid->background());
332 MaskTreeType mask(mGrid->tree(), false, TopologyCopy());
333 mask.topologyDifference(mask0);
334 this->normalize(&mask);
335 }
336 }
337}
338
339template<typename GridT, typename InterruptT>
340void
342erode(int iterations)
343{
345 tools::pruneLevelSet(mLeafs->tree());
346 mLeafs->rebuildLeafArray();
347 const ValueType background = mGrid->background() - ValueType(iterations) * mDx;
348 tools::changeLevelSetBackground(this->leafs(), background);
349}
350
351template<typename GridT, typename InterruptT>
352bool
354resize(Index halfWidth)
355{
356 const int wOld = static_cast<int>(math::RoundDown(this->getHalfWidth()));
357 const int wNew = static_cast<int>(halfWidth);
358 if (wOld < wNew) {
359 this->dilate(wNew - wOld);
360 } else if (wOld > wNew) {
361 this->erode(wOld - wNew);
362 }
363 return wOld != wNew;
364}
365
366template<typename GridT, typename InterruptT>
367inline void
369startInterrupter(const char* msg)
370{
371 if (mInterrupter) mInterrupter->start(msg);
372}
373
374template<typename GridT, typename InterruptT>
375inline void
378{
379 if (mInterrupter) mInterrupter->end();
380}
381
382template<typename GridT, typename InterruptT>
383inline bool
386{
387 if (util::wasInterrupted(mInterrupter)) {
388 thread::cancelGroupExecution();
389 return false;
390 }
391 return true;
392}
393
394template<typename GridT, typename InterruptT>
395template<typename MaskT>
396void
398normalize(const MaskT* mask)
399{
400 switch (this->getSpatialScheme()) {
401 case math::FIRST_BIAS:
402 this->normalize1<math::FIRST_BIAS , MaskT>(mask); break;
404 this->normalize1<math::SECOND_BIAS, MaskT>(mask); break;
405 case math::THIRD_BIAS:
406 this->normalize1<math::THIRD_BIAS, MaskT>(mask); break;
407 case math::WENO5_BIAS:
408 this->normalize1<math::WENO5_BIAS, MaskT>(mask); break;
410 this->normalize1<math::HJWENO5_BIAS, MaskT>(mask); break;
412 default:
413 OPENVDB_THROW(ValueError, "Spatial difference scheme not supported!");
414 }
415}
416
417template<typename GridT, typename InterruptT>
418template<math::BiasedGradientScheme SpatialScheme, typename MaskT>
419void
421normalize1(const MaskT* mask)
422{
423 switch (this->getTemporalScheme()) {
424 case math::TVD_RK1:
425 this->normalize2<SpatialScheme, math::TVD_RK1, MaskT>(mask); break;
426 case math::TVD_RK2:
427 this->normalize2<SpatialScheme, math::TVD_RK2, MaskT>(mask); break;
428 case math::TVD_RK3:
429 this->normalize2<SpatialScheme, math::TVD_RK3, MaskT>(mask); break;
431 default:
432 OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!");
433 }
434}
435
436template<typename GridT, typename InterruptT>
437template<math::BiasedGradientScheme SpatialScheme,
438 math::TemporalIntegrationScheme TemporalScheme,
439 typename MaskT>
440void
441LevelSetTracker<GridT, InterruptT>::
442normalize2(const MaskT* mask)
443{
444 Normalizer<SpatialScheme, TemporalScheme, MaskT> tmp(*this, mask);
445 tmp.normalize();
446}
447
448
449////////////////////////////////////////////////////////////////////////////
450
451
452template<typename GridT, typename InterruptT>
453template<lstrack::TrimMode Trimming>
454void
455LevelSetTracker<GridT, InterruptT>::Trim<Trimming>::trim()
456{
458 if (Trimming != TrimMode::kNone) {
459 const int grainSize = mTracker.getGrainSize();
460 const LeafRange range = mTracker.leafs().leafRange(grainSize);
461
462 if (grainSize>0) {
463 tbb::parallel_for(range, *this);
464 } else {
465 (*this)(range);
466 }
467 }
469}
470
471
472/// Trim away voxels that have moved outside the narrow band
473template<typename GridT, typename InterruptT>
474template<lstrack::TrimMode Trimming>
475inline void
476LevelSetTracker<GridT, InterruptT>::Trim<Trimming>::operator()(const LeafRange& range) const
477{
478 mTracker.checkInterrupter();
479 const ValueType gamma = mTracker.mGrid->background();
480
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;
486 switch (Trimming) { // resolved at compile time
487 case TrimMode::kNone:
488 break;
489 case TrimMode::kInterior:
490 if (val <= -gamma) { leaf.setValueOff(iter.pos(), -gamma); }
491 break;
492 case TrimMode::kExterior:
493 if (val >= gamma) { leaf.setValueOff(iter.pos(), gamma); }
494 break;
495 case TrimMode::kAll:
496 if (val <= -gamma) {
497 leaf.setValueOff(iter.pos(), -gamma);
498 } else if (val >= gamma) {
499 leaf.setValueOff(iter.pos(), gamma);
500 }
501 break;
502 }
503 }
504 }
506}
507
508
509////////////////////////////////////////////////////////////////////////////
510
511template<typename GridT, typename InterruptT>
512template<math::BiasedGradientScheme SpatialScheme,
513 math::TemporalIntegrationScheme TemporalScheme,
514 typename MaskT>
515inline
518Normalizer(LevelSetTracker& tracker, const MaskT* mask)
519 : mTracker(tracker)
520 , mMask(mask)
521 , mDt(tracker.voxelSize()*(TemporalScheme == math::TVD_RK1 ? 0.3f :
522 TemporalScheme == math::TVD_RK2 ? 0.9f : 1.0f))
523 , mInvDx(1.0f/tracker.voxelSize())
524 , mTask(nullptr)
525{
526}
527
528template<typename GridT, typename InterruptT>
529template<math::BiasedGradientScheme SpatialScheme,
530 math::TemporalIntegrationScheme TemporalScheme,
531 typename MaskT>
532inline void
535normalize()
536{
537 namespace ph = std::placeholders;
538
539 /// Make sure we have enough temporal auxiliary buffers
540 mTracker.mLeafs->rebuildAuxBuffers(TemporalScheme == math::TVD_RK3 ? 2 : 1);
541
542 for (int n=0, e=mTracker.getNormCount(); n < e; ++n) {
543
545 switch(TemporalScheme) {//switch is resolved at compile-time
546 case math::TVD_RK1:
547 // Perform one explicit Euler step: t1 = t0 + dt
548 // Phi_t1(0) = Phi_t0(0) - dt * VdotG_t0(1)
549 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
550
551 // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1)
552 this->cook("Normalizing level set using TVD_RK1", 1);
553 break;
554 case math::TVD_RK2:
555 // Perform one explicit Euler step: t1 = t0 + dt
556 // Phi_t1(1) = Phi_t0(0) - dt * VdotG_t0(1)
557 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
558
559 // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1)
560 this->cook("Normalizing level set using TVD_RK1 (step 1 of 2)", 1);
561
562 // Convex combine explicit Euler step: t2 = t0 + dt
563 // Phi_t2(1) = 1/2 * Phi_t0(1) + 1/2 * (Phi_t1(0) - dt * V.Grad_t1(0))
564 mTask = std::bind(&Normalizer::euler12, ph::_1, ph::_2);
565
566 // Cook and swap buffer 0 and 1 such that Phi_t2(0) and Phi_t1(1)
567 this->cook("Normalizing level set using TVD_RK1 (step 2 of 2)", 1);
568 break;
569 case math::TVD_RK3:
570 // Perform one explicit Euler step: t1 = t0 + dt
571 // Phi_t1(1) = Phi_t0(0) - dt * VdotG_t0(1)
572 mTask = std::bind(&Normalizer::euler01, ph::_1, ph::_2);
573
574 // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1)
575 this->cook("Normalizing level set using TVD_RK3 (step 1 of 3)", 1);
576
577 // Convex combine explicit Euler step: t2 = t0 + dt/2
578 // Phi_t2(2) = 3/4 * Phi_t0(1) + 1/4 * (Phi_t1(0) - dt * V.Grad_t1(0))
579 mTask = std::bind(&Normalizer::euler34, ph::_1, ph::_2);
580
581 // Cook and swap buffer 0 and 2 such that Phi_t2(0) and Phi_t1(2)
582 this->cook("Normalizing level set using TVD_RK3 (step 2 of 3)", 2);
583
584 // Convex combine explicit Euler step: t3 = t0 + dt
585 // Phi_t3(2) = 1/3 * Phi_t0(1) + 2/3 * (Phi_t2(0) - dt * V.Grad_t2(0)
586 mTask = std::bind(&Normalizer::euler13, ph::_1, ph::_2);
587
588 // Cook and swap buffer 0 and 2 such that Phi_t3(0) and Phi_t2(2)
589 this->cook("Normalizing level set using TVD_RK3 (step 3 of 3)", 2);
590 break;
592 default:
593 OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!");
594 }
596 }
597 mTracker.mLeafs->removeAuxBuffers();
598}
599
600/// Private method to perform the task (serial or threaded) and
601/// subsequently swap the leaf buffers.
602template<typename GridT, typename InterruptT>
603template<math::BiasedGradientScheme SpatialScheme,
604 math::TemporalIntegrationScheme TemporalScheme,
605 typename MaskT>
606inline void
609cook(const char* msg, int swapBuffer)
610{
611 mTracker.startInterrupter( msg );
612
613 const int grainSize = mTracker.getGrainSize();
614 const LeafRange range = mTracker.leafs().leafRange(grainSize);
615
616 grainSize>0 ? tbb::parallel_for(range, *this) : (*this)(range);
617
618 mTracker.leafs().swapLeafBuffer(swapBuffer, grainSize==0);
619
620 mTracker.endInterrupter();
621}
622
623template<typename GridT, typename InterruptT>
624template<math::BiasedGradientScheme SpatialScheme,
625 math::TemporalIntegrationScheme TemporalScheme,
626 typename MaskT>
627template <int Nominator, int Denominator>
628inline void
631eval(StencilT& stencil, const ValueType* phi, ValueType* result, Index n) const
632{
633 using GradientT = typename math::ISGradientNormSqrd<SpatialScheme>;
634 static const ValueType alpha = ValueType(Nominator)/ValueType(Denominator);
635 static const ValueType beta = ValueType(1) - alpha;
636
637 const ValueType normSqGradPhi = GradientT::result(stencil);
638 const ValueType phi0 = stencil.getValue();
639 ValueType v = phi0 / ( math::Sqrt(math::Pow2(phi0) + normSqGradPhi) +
641 v = phi0 - mDt * v * (math::Sqrt(normSqGradPhi) * mInvDx - 1.0f);
642 result[n] = Nominator ? alpha * phi[n] + beta * v : v;
643}
644
645template<typename GridT, typename InterruptT>
646template<math::BiasedGradientScheme SpatialScheme,
647 math::TemporalIntegrationScheme TemporalScheme,
648 typename MaskT>
649template <int Nominator, int Denominator>
650inline void
653euler(const LeafRange& range, Index phiBuffer, Index resultBuffer)
654{
655 mTracker.checkInterrupter();
656
657 StencilT stencil(mTracker.grid());
658
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());
666 }//loop over active voxels in the leaf of the level set
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]);
672 this->eval<Nominator, Denominator>(stencil, phi, result, i);
673 }//loop over active voxels in the leaf of the mask
674 }
675 }//loop over leafs of the level set
676}
677
678
679////////////////////////////////////////
680
681
682// Explicit Template Instantiation
683
684#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
685
686#ifdef OPENVDB_INSTANTIATE_LEVELSETTRACKER
688#endif
689
692
693#endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
694
695
696} // namespace tools
697} // namespace OPENVDB_VERSION_NAME
698} // namespace openvdb
699
700#endif // OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED
Efficient multi-threaded replacement of the background values in tree.
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Implementation of morphological dilation and erosion.
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition Platform.h:141
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition Platform.h:140
Defined various multi-threaded utility functions for trees.
ValueAccessors are designed to help accelerate accesses into the OpenVDB Tree structures by storing c...
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:683
Definition Exceptions.h:65
Performs multi-threaded interface tracking of narrow band level sets.
Definition LevelSetTracker.h:58
bool checkInterrupter()
Definition LevelSetTracker.h:385
ValueType getHalfWidth() const
Return the half width of the narrow band in floating-point voxel units.
Definition LevelSetTracker.h:135
typename TreeType::ValueType ValueType
Definition LevelSetTracker.h:65
void setTemporalScheme(math::TemporalIntegrationScheme s)
Set the spatial finite difference scheme.
Definition LevelSetTracker.h:153
ValueType voxelSize() const
Definition LevelSetTracker.h:178
void erode(int iterations=1)
Erodes the width of the narrow-band and update the background values.
Definition LevelSetTracker.h:342
const LeafManagerType & leafs() const
Definition LevelSetTracker.h:191
void setState(const State &s)
Set the state of the tracker (see struct defined above)
Definition LevelSetTracker.h:141
LevelSetTracker(GridT &grid, InterruptT *interrupt=nullptr)
Main constructor.
Definition LevelSetTracker.h:260
math::TemporalIntegrationScheme getTemporalScheme() const
Definition LevelSetTracker.h:150
typename tree::LeafManager< TreeType > LeafManagerType
Definition LevelSetTracker.h:66
void prune()
Set voxels that are outside the narrow band to the background value (if trimming is enabled) and prun...
Definition LevelSetTracker.h:282
math::BiasedGradientScheme getSpatialScheme() const
Definition LevelSetTracker.h:144
void endInterrupter()
Definition LevelSetTracker.h:377
void normalize(const MaskType *mask)
Iterative normalization, i.e. solving the Eikonal equation.
void setGrainSize(int grainsize)
Set the grain-size used for multi-threading.
Definition LevelSetTracker.h:168
void setSpatialScheme(math::BiasedGradientScheme s)
Set the spatial finite difference scheme.
Definition LevelSetTracker.h:147
TrimMode trimming() const
Return the trimming mode for voxels outside the narrow band.
Definition LevelSetTracker.h:173
int getGrainSize() const
Definition LevelSetTracker.h:164
void setNormCount(int n)
Set the number of normalizations performed per track or normalize call.
Definition LevelSetTracker.h:161
State getState() const
Return the state of the tracker (see struct defined above)
Definition LevelSetTracker.h:138
void startInterrupter(const char *msg)
Definition LevelSetTracker.h:369
typename TreeType::template ValueConverter< ValueMask >::Type MaskTreeType
Definition LevelSetTracker.h:69
typename LeafManagerType::LeafRange LeafRange
Definition LevelSetTracker.h:67
typename GridT::TreeType TreeType
Definition LevelSetTracker.h:63
bool resize(Index halfWidth=static_cast< Index >(LEVEL_SET_HALF_WIDTH))
Resize the width of the narrow band, i.e. perform dilation and renormalization or erosion as required...
Definition LevelSetTracker.h:354
typename LeafManagerType::BufferType BufferType
Definition LevelSetTracker.h:68
const GridType & grid() const
Definition LevelSetTracker.h:187
lstrack::TrimMode TrimMode
Definition LevelSetTracker.h:60
void setTrimming(TrimMode mode)
Specify whether to trim voxels outside the narrow band prior to pruning.
Definition LevelSetTracker.h:176
void normalize()
Iterative normalization, i.e. solving the Eikonal equation.
Definition LevelSetTracker.h:97
LeafManagerType & leafs()
Definition LevelSetTracker.h:189
void dilate(int iterations=1)
Fast but approximate dilation of the narrow band - one layer at a time. Normally we recommend using t...
Definition LevelSetTracker.h:320
typename TreeType::LeafNodeType LeafType
Definition LevelSetTracker.h:64
int getNormCount() const
Definition LevelSetTracker.h:157
virtual ~LevelSetTracker()
Definition LevelSetTracker.h:89
void track()
Track the level set interface, i.e. rebuild and normalize the narrow band of the level set.
Definition LevelSetTracker.h:305
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:219
TemporalIntegrationScheme
Temporal integration schemes.
Definition FiniteDifference.h:233
@ TVD_RK1
Definition FiniteDifference.h:235
@ UNKNOWN_TIS
Definition FiniteDifference.h:234
@ TVD_RK2
Definition FiniteDifference.h:236
@ TVD_RK3
Definition FiniteDifference.h:237
float Sqrt(float x)
Return the square root of a floating-point value.
Definition Math.h:761
BiasedGradientScheme
Biased Gradients are limited to non-centered differences.
Definition FiniteDifference.h:164
@ FIRST_BIAS
Definition FiniteDifference.h:166
@ THIRD_BIAS
Definition FiniteDifference.h:168
@ WENO5_BIAS
Definition FiniteDifference.h:169
@ UNKNOWN_BIAS
Definition FiniteDifference.h:165
@ SECOND_BIAS
Definition FiniteDifference.h:167
@ HJWENO5_BIAS
Definition FiniteDifference.h:170
float RoundDown(float x)
Return x rounded down to the nearest integer.
Definition Math.h:803
Type Pow2(Type x)
Return x2.
Definition Math.h:548
State
Definition IndexIterator.h:41
Definition LevelSetTracker.h:40
TrimMode
How to handle voxels that fall outside the narrow band.
Definition LevelSetTracker.h:45
@ kInterior
Set out-of-band interior voxels to the background value.
Definition LevelSetTracker.h:47
@ kAll
Set all out-of-band voxels to the background value.
Definition LevelSetTracker.h:49
@ kNone
Leave out-of-band voxels intact.
Definition LevelSetTracker.h:46
@ kExterior
Set out-of-band exterior voxels to the background value.
Definition LevelSetTracker.h:48
@ NN_FACE
Definition Morphology.h:60
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition Prune.h:390
if(shared)
Definition ValueTransformer.h:596
void erodeActiveValues(TreeOrLeafManagerT &tree, const int iterations=1, const NearestNeighbors nn=NN_FACE, const TilePolicy mode=PRESERVE_TILES, const bool threaded=true)
Topologically erode all active values (i.e. both voxels and tiles) in a tree using one of three neare...
Definition Morphology.h:1134
void dilateActiveValues(TreeOrLeafManagerT &tree, const int iterations=1, const NearestNeighbors nn=NN_FACE, const TilePolicy mode=PRESERVE_TILES, const bool threaded=true)
Topologically dilate all active values (i.e. both voxels and tiles) in a tree using one of three near...
Definition Morphology.h:1057
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition Prune.h:335
@ IGNORE_TILES
Definition Morphology.h:82
void changeLevelSetBackground(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &halfWidth, bool threaded=true, size_t grainSize=32)
Replace the background value in all the nodes of a floating-point tree containing a symmetric narrow-...
Definition ChangeBackground.h:234
GridType::Ptr normalize(const GridType &grid, bool threaded, InterruptT *interrupt)
Normalize the vectors of the given vector-valued grid.
Definition GridOperators.h:1069
Definition PointDataGrid.h:170
bool wasInterrupted(T *i, int percent=-1)
Definition NullInterrupter.h:49
static const Real LEVEL_SET_HALF_WIDTH
Definition Types.h:461
Index32 Index
Definition Types.h:54
@ GRID_LEVEL_SET
Definition Types.h:455
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
Definition Operators.h:129
static T value()
Definition Math.h:148
math::BiasedGradientScheme spatialScheme
Definition LevelSetTracker.h:79
int grainSize
Definition LevelSetTracker.h:82
math::TemporalIntegrationScheme temporalScheme
Definition LevelSetTracker.h:80
int normCount
Definition LevelSetTracker.h:81
State(math::BiasedGradientScheme s=math::HJWENO5_BIAS, math::TemporalIntegrationScheme t=math::TVD_RK1, int n=static_cast< int >(LEVEL_SET_HALF_WIDTH), int g=1)
Definition LevelSetTracker.h:75
#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