12 #ifndef OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
13 #define OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_HAS_BEEN_INCLUDED
23 #include <tbb/task_group.h>
46 template<
typename Gr
idT>
47 inline typename GridT::template ValueConverter<float>::Type::Ptr
48 topologyToLevelSet(
const GridT& grid,
int halfWidth = 3,
int closingSteps = 1,
int dilation = 0,
49 int smoothingSteps = 0);
65 template<
typename Gr
idT,
typename InterrupterT>
66 inline typename GridT::template ValueConverter<float>::Type::Ptr
67 topologyToLevelSet(
const GridT& grid,
int halfWidth = 3,
int closingSteps = 1,
int dilation = 0,
68 int smoothingSteps = 0, InterrupterT* interrupt =
nullptr);
75 namespace ttls_internal {
78 template<
typename TreeT>
81 DilateOp(TreeT&
t,
int n) : tree(&t),
size(n) {}
82 void operator()()
const {
90 template<
typename TreeT>
93 ErodeOp(TreeT&
t,
int n) : tree(&t),
size(n) {}
94 void operator()()
const {
103 template<
typename TreeType>
104 struct OffsetAndMinComp
106 using LeafNodeType =
typename TreeType::LeafNodeType;
107 using ValueType =
typename TreeType::ValueType;
109 OffsetAndMinComp(std::vector<LeafNodeType*>& lhsNodes,
110 const TreeType& rhsTree, ValueType
offset)
111 : mLhsNodes(lhsNodes.empty() ? nullptr : &lhsNodes[0]), mRhsTree(&rhsTree), mOffset(offset)
115 void operator()(
const tbb::blocked_range<size_t>&
range)
const
117 using Iterator =
typename LeafNodeType::ValueOnIter;
119 tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
120 const ValueType
offset = mOffset;
122 for (
size_t n = range.begin(),
N = range.
end();
n <
N; ++
n) {
124 LeafNodeType& lhsNode = *mLhsNodes[
n];
125 const LeafNodeType * rhsNodePt = rhsAcc.probeConstLeaf(lhsNode.origin());
126 if (!rhsNodePt)
continue;
128 for (Iterator it = lhsNode.beginValueOn(); it; ++it) {
129 ValueType&
val =
const_cast<ValueType&
>(it.getValue());
130 val =
std::min(val, offset + rhsNodePt->getValue(it.pos()));
136 LeafNodeType * *
const mLhsNodes;
137 TreeType
const *
const mRhsTree;
138 ValueType
const mOffset;
142 template<
typename Gr
idType,
typename InterrupterType>
144 normalizeLevelSet(GridType& grid,
const int halfWidthInVoxels, InterrupterType* interrupt =
nullptr)
146 LevelSetFilter<GridType, GridType, InterrupterType>
filter(grid, interrupt);
148 filter.setNormCount(halfWidthInVoxels);
154 template<
typename Gr
idType,
typename InterrupterType>
156 smoothLevelSet(GridType& grid,
int iterations,
int halfBandWidthInVoxels,
157 InterrupterType* interrupt =
nullptr)
159 using ValueType =
typename GridType::ValueType;
160 using TreeType =
typename GridType::TreeType;
161 using LeafNodeType =
typename TreeType::LeafNodeType;
163 GridType filterGrid(grid);
165 LevelSetFilter<GridType, GridType, InterrupterType>
filter(filterGrid, interrupt);
168 for (
int n = 0;
n < iterations; ++
n) {
169 if (interrupt && interrupt->wasInterrupted())
break;
173 std::vector<LeafNodeType*> nodes;
174 grid.tree().getNodes(nodes);
176 const ValueType offset = ValueType(
double(0.5) * grid.transform().voxelSize()[0]);
179 OffsetAndMinComp<TreeType>(nodes, filterGrid.tree(), -
offset));
182 normalizeLevelSet(grid, halfBandWidthInVoxels, interrupt);
190 template<
typename Gr
idT,
typename InterrupterT>
191 inline typename GridT::template ValueConverter<float>::Type::Ptr
193 int smoothingSteps, InterrupterT* interrupt)
202 closingSteps =
std::max(closingSteps, 0);
205 if (!grid.hasUniformVoxels()) {
206 OPENVDB_THROW(ValueError,
"Non-uniform voxels are not supported!");
210 MaskTreeT maskTree( grid.tree(),
false, openvdb::TopologyCopy() );
219 const float background = float(grid.voxelSize()[0]) *
float(halfWidth);
220 typename FloatTreeT::Ptr lsTree(
221 new FloatTreeT( maskTree, background, -background, openvdb::TopologyCopy() ) );
223 tbb::task_group
pool;
224 pool.run( ttls_internal::ErodeOp< MaskTreeT >( maskTree, halfWidth ) );
225 pool.run( ttls_internal::DilateOp<FloatTreeT>( *lsTree , halfWidth ) );
228 lsTree->topologyDifference( maskTree );
232 typename FloatGridT::Ptr lsGrid = FloatGridT::create( lsTree );
233 lsGrid->setTransform( grid.transform().copy() );
238 ttls_internal::normalizeLevelSet(*lsGrid, 3*halfWidth, interrupt);
241 if (smoothingSteps > 0) {
242 ttls_internal::smoothLevelSet(*lsGrid, smoothingSteps, halfWidth, interrupt);
249 template<
typename Gr
idT>
250 inline typename GridT::template ValueConverter<float>::Type::Ptr
251 topologyToLevelSet(
const GridT& grid,
int halfWidth,
int closingSteps,
int dilation,
int smoothingSteps)
254 return topologyToLevelSet(grid, halfWidth, closingSteps, dilation, smoothingSteps, &interrupt);
262 #endif // OPENVDB_TOOLS_TOPOLOGY_TO_LEVELSET_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))
#define OPENVDB_USE_VERSION_NAMESPACE
Dummy NOOP interrupter class defining interface.
SYS_FORCE_INLINE const_iterator end() const
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Container class that associates a tree with a transform and metadata.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
GA_API const UT_StringHolder N
Implementation of morphological dilation and erosion.
Performs various types of level set deformations with interface tracking. These unrestricted deformat...
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
#define OPENVDB_THROW(exception, message)
**Note that the tasks the is the thread number *for the pool