OpenVDB 10.0.1
Loading...
Searching...
No Matches
FastSweeping.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: MPL-2.0
3//
4/// @file FastSweeping.h
5///
6/// @author Ken Museth
7///
8/// @brief Defined the six functions {fog,sdf}To{Sdf,Ext,SdfAndExt} in
9/// addition to the two functions maskSdf and dilateSdf. Sdf denotes
10/// a signed-distance field (i.e. negative values are inside), fog
11/// is a scalar fog volume (i.e. higher values are inside), and Ext is
12/// a field (of arbitrary type) that is extended off the iso-surface.
13/// All these functions are implemented with the methods in the class
14/// named FastSweeping.
15///
16/// @note Solves the (simplified) Eikonal Eq: @f$|\nabla \phi|^2 = 1@f$ and
17/// performs velocity extension, @f$\nabla f\nabla \phi = 0@f$, both
18/// by means of the fast sweeping algorithm detailed in:
19/// "A Fast Sweeping Method For Eikonal Equations"
20/// by H. Zhao, Mathematics of Computation, Vol 74(230), pp 603-627, 2004
21///
22/// @details The algorithm used below for parallel fast sweeping was first published in:
23/// "New Algorithm for Sparse and Parallel Fast Sweeping: Efficient
24/// Computation of Sparse Distance Fields" by K. Museth, ACM SIGGRAPH Talk,
25/// 2017, http://www.museth.org/Ken/Publications_files/Museth_SIG17.pdf
26
27#ifndef OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
28#define OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
29
30//#define BENCHMARK_FAST_SWEEPING
31
32#include <openvdb/openvdb.h>
33#include <openvdb/Platform.h>
34#include <openvdb/math/Math.h> // for Abs() and isExactlyEqual()
35#include <openvdb/math/Stencils.h> // for GradStencil
37#include <openvdb/tree/NodeManager.h> // for PruneMinMaxFltKernel
38
39#include "LevelSetUtil.h"
40#include "Morphology.h"
41
42#include "Statistics.h"
43#ifdef BENCHMARK_FAST_SWEEPING
45#endif
46
47#include <tbb/parallel_for.h>
48#include <tbb/enumerable_thread_specific.h>
49#include <tbb/task_group.h>
50
51#include <type_traits>// for static_assert
52#include <cmath>
53#include <limits>
54#include <deque>
55#include <unordered_map>
56#include <utility>// for std::make_pair
57
58namespace openvdb {
60namespace OPENVDB_VERSION_NAME {
61namespace tools {
62
63/// @brief Fast Sweeping update mode. This is useful to determine
64/// narrow-band extension or field extension in one side
65/// of a signed distance field.
67 /// Update all voxels affected by the sweeping algorithm
69 // Update voxels corresponding to an sdf/fog values that are greater than a given isovalue
71 // Update voxels corresponding to an sdf/fog values that are less than a given isovalue
73};
74
75/// @brief Converts a scalar fog volume into a signed distance function. Active input voxels
76/// with scalar values above the given isoValue will have NEGATIVE distance
77/// values on output, i.e. they are assumed to be INSIDE the iso-surface.
78///
79/// @return A shared pointer to a signed-distance field defined on the active values
80/// of the input fog volume.
81///
82/// @param fogGrid Scalar (floating-point) volume from which an
83/// iso-surface can be defined.
84///
85/// @param isoValue A value which defines a smooth iso-surface that
86/// intersects active voxels in @a fogGrid.
87///
88/// @param nIter Number of iterations of the fast sweeping algorithm.
89/// Each iteration performs 2^3 = 8 individual sweeps.
90///
91/// @note Strictly speaking a fog volume is normalized to the range [0,1] but this
92/// method accepts a scalar volume with an arbritary range, as long as the it
93/// includes the @a isoValue.
94///
95/// @details Topology of output grid is identical to that of the input grid, except
96/// active tiles in the input grid will be converted to active voxels
97/// in the output grid!
98///
99/// @warning If @a isoValue does not intersect any active values in
100/// @a fogGrid then the returned grid has all its active values set to
101/// plus or minus infinity, depending on if the input values are larger or
102/// smaller than @a isoValue.
103template<typename GridT>
104typename GridT::Ptr
105fogToSdf(const GridT &fogGrid,
106 typename GridT::ValueType isoValue,
107 int nIter = 1);
108
109/// @brief Given an existing approximate SDF it solves the Eikonal equation for all its
110/// active voxels. Active input voxels with a signed distance value above the
111/// given isoValue will have POSITIVE distance values on output, i.e. they are
112/// assumed to be OUTSIDE the iso-surface.
113///
114/// @return A shared pointer to a signed-distance field defined on the active values
115/// of the input sdf volume.
116///
117/// @param sdfGrid An approximate signed distance field to the specified iso-surface.
118///
119/// @param isoValue A value which defines a smooth iso-surface that
120/// intersects active voxels in @a sdfGrid.
121///
122/// @param nIter Number of iterations of the fast sweeping algorithm.
123/// Each iteration performs 2^3 = 8 individual sweeps.
124///
125/// @note The only difference between this method and fogToSdf, defined above, is the
126/// convention of the sign of the output distance field.
127///
128/// @details Topology of output grid is identical to that of the input grid, except
129/// active tiles in the input grid will be converted to active voxels
130/// in the output grid!
131///
132/// @warning If @a isoValue does not intersect any active values in
133/// @a sdfGrid then the returned grid has all its active values set to
134/// plus or minus infinity, depending on if the input values are larger or
135/// smaller than @a isoValue.
136template<typename GridT>
137typename GridT::Ptr
138sdfToSdf(const GridT &sdfGrid,
139 typename GridT::ValueType isoValue = 0,
140 int nIter = 1);
141
142/// @brief Computes the extension of a field (scalar, vector, or int are supported), defined
143/// by the specified functor, off an iso-surface from an input FOG volume.
144///
145/// @return A shared pointer to the extension field defined from the active values in
146/// the input fog volume.
147///
148/// @param fogGrid Scalar (floating-point) volume from which an
149/// iso-surface can be defined.
150///
151/// @param op Functor with signature [](const Vec3R &xyz)->ExtValueT that
152/// defines the Dirichlet boundary condition, on the iso-surface,
153/// of the field to be extended.
154///
155/// @param background Background value of return grid with the extension field.
156///
157/// @param isoValue A value which defines a smooth iso-surface that
158/// intersects active voxels in @a fogGrid.
159///
160/// @param nIter Number of iterations of the fast sweeping algorithm.
161/// Each iteration performs 2^3 = 8 individual sweeps.
162///
163/// @param mode Determines the mode of updating the extension field. SWEEP_ALL
164/// will update all voxels of the extension field affected by the
165/// fast sweeping algorithm. SWEEP_GREATER_THAN_ISOVALUE will update
166/// all voxels corresponding to fog values that are greater than a given
167/// isovalue. SWEEP_LESS_THAN_ISOVALUE will update all voxels corresponding
168/// to fog values that are less than a given isovalue. If a mode other
169/// than SWEEP_ALL is chosen, a user needs to supply @a extGrid.
170///
171/// @param extGrid Optional parameter required to supply a default value for the extension
172/// field when SWEEP_GREATER_THAN_ISOVALUE or SWEEP_LESS_THAN_ISOVALUE
173/// mode is picked for @a mode. When SWEEP_GREATER_THAN_ISOVALUE is supplied
174/// as an argument for @a mode, the extension field voxel will default
175/// to the value of the @a extGrid in that position if it corresponds to a fog
176/// value that is less than the isovalue. Otherwise, the extension
177/// field voxel value will be computed by the Fast Sweeping algorithm.
178/// The opposite convention is implemented when SWEEP_LESS_THAN_ISOVALUE
179/// is supplied as an argument for @a mode.
180///
181/// @note Strictly speaking a fog volume is normalized to the range [0,1] but this
182/// method accepts a scalar volume with an arbritary range, as long as the it
183/// includes the @a isoValue.
184///
185/// @details Topology of output grid is identical to that of the input grid, except
186/// active tiles in the input grid will be converted to active voxels
187/// in the output grid!
188///
189/// @warning If @a isoValue does not intersect any active values in
190/// @a fogGrid then the returned grid has all its active values set to
191/// @a background.
192template<typename FogGridT, typename ExtOpT, typename ExtValueT>
193typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
194fogToExt(const FogGridT &fogGrid,
195 const ExtOpT &op,
196 const ExtValueT& background,
197 typename FogGridT::ValueType isoValue,
198 int nIter = 1,
199 FastSweepingDomain mode = FastSweepingDomain::SWEEP_ALL,
200 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid = nullptr);
201
202/// @brief Computes the extension of a field (scalar, vector, or int are supported), defined
203/// by the specified functor, off an iso-surface from an input SDF volume.
204///
205/// @return A shared pointer to the extension field defined on the active values in the
206/// input signed distance field.
207///
208/// @param sdfGrid An approximate signed distance field to the specified iso-surface.
209///
210/// @param op Functor with signature [](const Vec3R &xyz)->ExtValueT that
211/// defines the Dirichlet boundary condition, on the iso-surface,
212/// of the field to be extended.
213///
214/// @param background Background value of return grid with the extension field.
215///
216/// @param isoValue A value which defines a smooth iso-surface that
217/// intersects active voxels in @a sdfGrid.
218///
219/// @param nIter Number of iterations of the fast sweeping algorithm.
220/// Each iteration performs 2^3 = 8 individual sweeps.
221///
222/// @param mode Determines the mode of updating the extension field. SWEEP_ALL
223/// will update all voxels of the extension field affected by the
224/// fast sweeping algorithm. SWEEP_GREATER_THAN_ISOVALUE will update
225/// all voxels corresponding to level set values that are greater than a given
226/// isovalue. SWEEP_LESS_THAN_ISOVALUE will update all voxels corresponding
227/// to level set values that are less than a given isovalue. If a mode other
228/// than SWEEP_ALL is chosen, a user needs to supply @a extGrid.
229///
230/// @param extGrid Optional parameter required to supply a default value for the extension
231/// field when SWEEP_GREATER_THAN_ISOVALUE or SWEEP_LESS_THAN_ISOVALUE
232/// mode is picked for @a mode. When SWEEP_GREATER_THAN_ISOVALUE is supplied
233/// as an argument for @a mode, the extension field voxel will default
234/// to the value of the @a extGrid in that position if it corresponds to a level-set
235/// value that is less than the isovalue. Otherwise, the extension
236/// field voxel value will be computed by the Fast Sweeping algorithm.
237/// The opposite convention is implemented when SWEEP_LESS_THAN_ISOVALUE
238/// is supplied as an argument for @a mode.
239///
240/// @note The only difference between this method and fogToExt, defined above, is the
241/// convention of the sign of the signed distance field.
242///
243/// @details Topology of output grid is identical to that of the input grid, except
244/// active tiles in the input grid will be converted to active voxels
245/// in the output grid!
246///
247/// @warning If @a isoValue does not intersect any active values in
248/// @a sdfGrid then the returned grid has all its active values set to
249/// @a background.
250template<typename SdfGridT, typename ExtOpT, typename ExtValueT>
251typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
252sdfToExt(const SdfGridT &sdfGrid,
253 const ExtOpT &op,
254 const ExtValueT &background,
255 typename SdfGridT::ValueType isoValue = 0,
256 int nIter = 1,
257 FastSweepingDomain mode = FastSweepingDomain::SWEEP_ALL,
258 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid = nullptr);
259
260/// @brief Computes the signed distance field and the extension of a field (scalar, vector, or
261/// int are supported), defined by the specified functor, off an iso-surface from an input
262/// FOG volume.
263///
264/// @return An pair of two shared pointers to respectively the SDF and extension field
265///
266/// @param fogGrid Scalar (floating-point) volume from which an
267/// iso-surface can be defined.
268///
269/// @param op Functor with signature [](const Vec3R &xyz)->ExtValueT that
270/// defines the Dirichlet boundary condition, on the iso-surface,
271/// of the field to be extended.
272///
273/// @param background Background value of return grid with the extension field.
274///
275/// @param isoValue A value which defines a smooth iso-surface that
276/// intersects active voxels in @a fogGrid.
277///
278/// @param nIter Number of iterations of the fast sweeping algorithm.
279/// Each iteration performs 2^3 = 8 individual sweeps.
280///
281/// @param mode Determines the mode of updating the extension field. SWEEP_ALL
282/// will update all voxels of the extension field affected by the
283/// fast sweeping algorithm. SWEEP_GREATER_THAN_ISOVALUE will update
284/// all voxels corresponding to fog values that are greater than a given
285/// isovalue. SWEEP_LESS_THAN_ISOVALUE will update all voxels corresponding
286/// to fog values that are less than a given isovalue. If a mode other
287/// than SWEEP_ALL is chosen, a user needs to supply @a extGrid.
288///
289/// @param extGrid Optional parameter required to supply a default value for the extension
290/// field when SWEEP_GREATER_THAN_ISOVALUE or SWEEP_LESS_THAN_ISOVALUE
291/// mode is picked for @a mode. When SWEEP_GREATER_THAN_ISOVALUE is supplied
292/// as an argument for @a mode, the extension field voxel will default
293/// to the value of the @a extGrid in that position if it corresponds to a fog
294/// value that is less than the isovalue. Otherwise, the extension
295/// field voxel value will be computed by the Fast Sweeping algorithm.
296/// The opposite convention is implemented when SWEEP_LESS_THAN_ISOVALUE
297/// is supplied as an argument for @a mode.
298///
299/// @note Strictly speaking a fog volume is normalized to the range [0,1] but this
300/// method accepts a scalar volume with an arbritary range, as long as the it
301/// includes the @a isoValue.
302///
303/// @details Topology of output grids are identical to that of the input grid, except
304/// active tiles in the input grid will be converted to active voxels
305/// in the output grids!
306///
307/// @warning If @a isoValue does not intersect any active values in
308/// @a fogGrid then a pair of the following grids is returned: The first
309/// is a signed distance grid with its active values set to plus or minus
310/// infinity depending of whether its input values are above or below @a isoValue.
311/// The second grid, which represents the extension field, has all its active
312/// values set to @a background.
313template<typename FogGridT, typename ExtOpT, typename ExtValueT>
314std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
315fogToSdfAndExt(const FogGridT &fogGrid,
316 const ExtOpT &op,
317 const ExtValueT &background,
318 typename FogGridT::ValueType isoValue,
319 int nIter = 1,
320 FastSweepingDomain mode = FastSweepingDomain::SWEEP_ALL,
321 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid = nullptr);
322
323/// @brief Computes the signed distance field and the extension of a field (scalar, vector, or
324/// int are supported), defined by the specified functor, off an iso-surface from an input
325/// SDF volume.
326///
327/// @return A pair of two shared pointers to respectively the SDF and extension field
328///
329/// @param sdfGrid Scalar (floating-point) volume from which an
330/// iso-surface can be defined.
331///
332/// @param op Functor with signature [](const Vec3R &xyz)->ExtValueT that
333/// defines the Dirichlet boundary condition, on the iso-surface,
334/// of the field to be extended.
335///
336/// @param background Background value of return grid with the extension field.
337///
338/// @param isoValue A value which defines a smooth iso-surface that
339/// intersects active voxels in @a sdfGrid.
340///
341/// @param nIter Number of iterations of the fast sweeping algorithm.
342/// Each iteration performs 2^3 = 8 individual sweeps.
343///
344/// @param mode Determines the mode of updating the extension field. SWEEP_ALL
345/// will update all voxels of the extension field affected by the
346/// fast sweeping algorithm. SWEEP_GREATER_THAN_ISOVALUE will update
347/// all voxels corresponding to level set values that are greater than a given
348/// isovalue. SWEEP_LESS_THAN_ISOVALUE will update all voxels corresponding
349/// to level set values that are less than a given isovalue. If a mode other
350/// than SWEEP_ALL is chosen, a user needs to supply @a extGrid.
351///
352/// @param extGrid Optional parameter required to supply a default value for the extension
353/// field when SWEEP_GREATER_THAN_ISOVALUE or SWEEP_LESS_THAN_ISOVALUE
354/// mode is picked for @a mode. When SWEEP_GREATER_THAN_ISOVALUE is supplied
355/// as an argument for @a mode, the extension field voxel will default
356/// to the value of the @a extGrid in that position if it corresponds to a level-set
357/// value that is less than the isovalue. Otherwise, the extension
358/// field voxel value will be computed by the Fast Sweeping algorithm.
359/// The opposite convention is implemented when SWEEP_LESS_THAN_ISOVALUE
360/// is supplied as an argument for @a mode.
361///
362/// @note Strictly speaking a fog volume is normalized to the range [0,1] but this
363/// method accepts a scalar volume with an arbritary range, as long as the it
364/// includes the @a isoValue.
365///
366/// @details Topology of output grids are identical to that of the input grid, except
367/// active tiles in the input grid will be converted to active voxels
368/// in the output grids!
369///
370/// @warning If @a isoValue does not intersect any active values in
371/// @a sdfGrid then a pair of the following grids is returned: The first
372/// is a signed distance grid with its active values set to plus or minus
373/// infinity depending of whether its input values are above or below @a isoValue.
374/// The second grid, which represents the extension field, has all its active
375/// values set to @a background.
376template<typename SdfGridT, typename ExtOpT, typename ExtValueT>
377std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
378sdfToSdfAndExt(const SdfGridT &sdfGrid,
379 const ExtOpT &op,
380 const ExtValueT &background,
381 typename SdfGridT::ValueType isoValue = 0,
382 int nIter = 1,
383 FastSweepingDomain mode = FastSweepingDomain::SWEEP_ALL,
384 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid = nullptr);
385
386/// @brief Dilates the narrow band of an existing signed distance field by
387/// a specified number of voxels (like adding "onion-rings").
388///
389/// @note This operation is not to be confused with morphological dilation
390/// of a level set, which is implemented in LevelSetFilter::offset,
391/// and involves actual interface tracking of the narrow band.
392///
393/// @return A shared pointer to the dilated signed distance field.
394///
395/// @param sdfGrid Input signed distance field to be dilated.
396///
397/// @param dilation Numer of voxels that the narrow band of the input SDF will be dilated.
398///
399/// @param nn Stencil-pattern used for dilation
400///
401/// @param nIter Number of iterations of the fast sweeping algorithm.
402/// Each iteration performs 2^3 = 8 individual sweeps.
403///
404/// @param mode Determines the direction of the dilation. SWEEP_ALL
405/// will dilate in both sides of the signed distance function,
406/// SWEEP_GREATER_THAN_ISOVALUE will dilate in the positive
407/// side of the iso-surface, SWEEP_LESS_THAN_ISOVALUE will dilate
408/// in the negative side of the iso-surface.
409///
410/// @details Topology will change as a result of this dilation. E.g. if
411/// sdfGrid has a width of 3 and @a dilation = 6 then the grid
412/// returned by this method is a narrow band signed distance field
413/// with a total width of 9 units.
414template<typename GridT>
415typename GridT::Ptr
416dilateSdf(const GridT &sdfGrid,
417 int dilation,
418 NearestNeighbors nn = NN_FACE,
419 int nIter = 1,
420 FastSweepingDomain mode = FastSweepingDomain::SWEEP_ALL);
421
422/// @brief Fills mask by extending an existing signed distance field into
423/// the active values of this input ree of arbitrary value type.
424///
425/// @return A shared pointer to the masked signed distance field.
426///
427/// @param sdfGrid Input signed distance field to be extended into the mask.
428///
429/// @param mask Mask used to identify the topology of the output SDF.
430/// Note this mask is assume to overlap with the sdfGrid.
431///
432/// @param ignoreActiveTiles If false, active tiles in the mask are treated
433/// as active voxels. Else they are ignored.
434///
435/// @param nIter Number of iterations of the fast sweeping algorithm.
436/// Each iteration performs 2^3 = 8 individual sweeps.
437///
438/// @details Topology of the output SDF is determined by the union of the active
439/// voxels (or optionally values) in @a sdfGrid and @a mask.
440template<typename GridT, typename MaskTreeT>
441typename GridT::Ptr
442maskSdf(const GridT &sdfGrid,
443 const Grid<MaskTreeT> &mask,
444 bool ignoreActiveTiles = false,
445 int nIter = 1);
446
447////////////////////////////////////////////////////////////////////////////////
448/// @brief Computes signed distance values from an initial iso-surface and
449/// optionally performs velocity extension at the same time. This is
450/// done by means of a novel sparse and parallel fast sweeping
451/// algorithm based on a first order Godunov's scheme.
452///
453/// Solves: @f$|\nabla \phi|^2 = 1 @f$
454///
455/// @warning Note, it is important to call one of the initialization methods before
456/// called the sweep function. Failure to do so will throw a RuntimeError.
457