12#ifndef OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
13#define OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
25#include <tbb/task_group.h>
48template<
typename Gr
idT>
49typename GridT::template ValueConverter<float>::Type::Ptr
50topologyToLevelSet(
const GridT& grid,
int halfWidth = 3,
int closingSteps = 1,
int dilation = 0,
51 int smoothingSteps = 0);
67template<
typename Gr
idT,
typename InterrupterT>
68typename GridT::template ValueConverter<float>::Type::Ptr
69topologyToLevelSet(
const GridT& grid,
int halfWidth = 3,
int closingSteps = 1,
int dilation = 0,
70 int smoothingSteps = 0, InterrupterT* interrupt =
nullptr);
77namespace ttls_internal {
80template<
typename TreeT>
83 DilateOp(TreeT& t,
int n) : tree(&t), size(n) {}
84 void operator()()
const {
92template<
typename TreeT>
95 ErodeOp(TreeT& t,
int n) : tree(&t), size(n) {}
96 void operator()()
const {
105template<
typename TreeType>
106struct OffsetAndMinComp
108 using LeafNodeType =
typename TreeType::LeafNodeType;
109 using ValueType =
typename TreeType::ValueType;
111 OffsetAndMinComp(std::vector<LeafNodeType*>& lhsNodes,
112 const TreeType& rhsTree, ValueType offset)
113 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes[0]), mRhsTree(&rhsTree), mOffset(offset)
117 void operator()(
const tbb::blocked_range<size_t>& range)
const
119 using Iterator =
typename LeafNodeType::ValueOnIter;
121 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
122 const ValueType offset = mOffset;
124 for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
126 LeafNodeType& lhsNode = *mLhsNodes[n];
127 const LeafNodeType * rhsNodePt = rhsAcc.probeConstLeaf(lhsNode.origin());
128 if (!rhsNodePt)
continue;
130 for (Iterator it = lhsNode.beginValueOn(); it; ++it) {
131 ValueType& val =
const_cast<ValueType&
>(it.getValue());
132 val =
std::min(val, offset + rhsNodePt->getValue(it.pos()));
138 LeafNodeType * *
const mLhsNodes;
139 TreeType
const *
const mRhsTree;
140 ValueType
const mOffset;
144template<
typename Gr
idType,
typename InterrupterType>
146normalizeLevelSet(
GridType& grid,
const int halfWidthInVoxels, InterrupterType* interrupt =
nullptr)
148 LevelSetFilter<GridType, GridType, InterrupterType> filter(grid, interrupt);
150 filter.setNormCount(halfWidthInVoxels);
156template<
typename Gr
idType,
typename InterrupterType>
158smoothLevelSet(
GridType& grid,
int iterations,
int halfBandWidthInVoxels,
159 InterrupterType* interrupt =
nullptr)
161 using ValueType =
typename GridType::ValueType;
162 using TreeType =
typename GridType::TreeType;
163 using LeafNodeType =
typename TreeType::LeafNodeType;
167 LevelSetFilter<GridType, GridType, InterrupterType> filter(filterGrid, interrupt);
170 for (
int n = 0; n < iterations; ++n) {
171 if (interrupt && interrupt->wasInterrupted())
break;
175 std::vector<LeafNodeType*> nodes;
176 grid.tree().getNodes(nodes);
178 const ValueType offset = ValueType(
double(0.5) * grid.transform().voxelSize()[0]);
180 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
181 OffsetAndMinComp<TreeType>(nodes, filterGrid.tree(), -offset));
184 normalizeLevelSet(grid, halfBandWidthInVoxels, interrupt);
192template<
typename Gr
idT,
typename InterrupterT>
193typename GridT::template ValueConverter<float>::Type::Ptr
195 int smoothingSteps, InterrupterT* interrupt)
197 using MaskTreeT =
typename GridT::TreeType::template ValueConverter<ValueMask>::Type;
198 using FloatTreeT =
typename GridT::TreeType::template ValueConverter<float>::Type;
204 closingSteps =
std::max(closingSteps, 0);
207 if (!grid.hasUniformVoxels()) {
221 const float background = float(grid.voxelSize()[0]) * float(halfWidth);
222 typename FloatTreeT::Ptr lsTree(
225 tbb::task_group pool;
226 pool.run( ttls_internal::ErodeOp< MaskTreeT >( maskTree, halfWidth ) );
227 pool.run( ttls_internal::DilateOp<FloatTreeT>( *lsTree , halfWidth ) );
230 lsTree->topologyDifference( maskTree );
234 typename FloatGridT::Ptr lsGrid = FloatGridT::create( lsTree );
235 lsGrid->setTransform( grid.transform().copy() );
240 ttls_internal::normalizeLevelSet(*lsGrid, 3*halfWidth, interrupt);
243 if (smoothingSteps > 0) {
244 ttls_internal::smoothLevelSet(*lsGrid, smoothingSteps, halfWidth, interrupt);
251template<
typename Gr
idT>
252typename GridT::template ValueConverter<float>::Type::Ptr
253topologyToLevelSet(
const GridT& grid,
int halfWidth,
int closingSteps,
int dilation,
int smoothingSteps)
256 return topologyToLevelSet(grid, halfWidth, closingSteps, dilation, smoothingSteps, &interrupt);
265#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
267#ifdef OPENVDB_INSTANTIATE_TOPOLOGYTOLEVELSET
271#define _FUNCTION(TreeT) \
272 Grid<TreeT>::ValueConverter<float>::Type::Ptr topologyToLevelSet(const Grid<TreeT>&, int, int, int, int, \
273 util::NullInterrupter*)
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
Implementation of morphological dilation and erosion.
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:577
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:564
Definition: Exceptions.h:65
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
@ FIRST_BIAS
Definition: FiniteDifference.h:167
@ GRID_LEVEL_SET
Definition: Types.h:337
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Base class for interrupters.
Definition: NullInterrupter.h:26
#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
#define OPENVDB_ALL_TREE_INSTANTIATE(Function)
Definition: version.h.in:151