OpenVDB  9.0.1
LevelSetRebuild.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #ifndef OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED
5 #define OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED
6 
7 #include <openvdb/Grid.h>
8 #include <openvdb/Exceptions.h>
9 #include <openvdb/math/Math.h>
10 #include <openvdb/math/Transform.h>
14 #include <openvdb/util/Util.h>
15 #include <openvdb/openvdb.h>
16 #include <tbb/blocked_range.h>
17 #include <tbb/parallel_for.h>
18 #include <type_traits>
19 
20 
21 namespace openvdb {
23 namespace OPENVDB_VERSION_NAME {
24 namespace tools {
25 
26 
27 /// @brief Return a new grid of type @c GridType that contains a narrow-band level set
28 /// representation of an isosurface of a given grid.
29 ///
30 /// @param grid a scalar, floating-point grid with one or more disjoint,
31 /// closed isosurfaces at the given @a isovalue
32 /// @param isovalue the isovalue that defines the implicit surface (defaults to zero,
33 /// which is typical if the input grid is already a level set or a SDF).
34 /// @param halfWidth half the width of the narrow band, in voxel units
35 /// (defaults to 3 voxels, which is required for some level set operations)
36 /// @param xform optional transform for the output grid
37 /// (if not provided, the transform of the input @a grid will be matched)
38 ///
39 /// @throw TypeError if @a grid is not scalar or not floating-point
40 ///
41 /// @note If the input grid contains overlapping isosurfaces, interior edges will be lost.
42 template<class GridType>
43 typename GridType::Ptr
44 levelSetRebuild(const GridType& grid, float isovalue = 0,
45  float halfWidth = float(LEVEL_SET_HALF_WIDTH), const math::Transform* xform = nullptr);
46 
47 
48 /// @brief Return a new grid of type @c GridType that contains a narrow-band level set
49 /// representation of an isosurface of a given grid.
50 ///
51 /// @param grid a scalar, floating-point grid with one or more disjoint,
52 /// closed isosurfaces at the given @a isovalue
53 /// @param isovalue the isovalue that defines the implicit surface
54 /// @param exBandWidth the exterior narrow-band width in voxel units
55 /// @param inBandWidth the interior narrow-band width in voxel units
56 /// @param xform optional transform for the output grid
57 /// (if not provided, the transform of the input @a grid will be matched)
58 ///
59 /// @throw TypeError if @a grid is not scalar or not floating-point
60 ///
61 /// @note If the input grid contains overlapping isosurfaces, interior edges will be lost.
62 template<class GridType>
63 typename GridType::Ptr
64 levelSetRebuild(const GridType& grid, float isovalue, float exBandWidth, float inBandWidth,
65  const math::Transform* xform = nullptr);
66 
67 
68 /// @brief Return a new grid of type @c GridType that contains a narrow-band level set
69 /// representation of an isosurface of a given grid.
70 ///
71 /// @param grid a scalar, floating-point grid with one or more disjoint,
72 /// closed isosurfaces at the given @a isovalue
73 /// @param isovalue the isovalue that defines the implicit surface
74 /// @param exBandWidth the exterior narrow-band width in voxel units
75 /// @param inBandWidth the interior narrow-band width in voxel units
76 /// @param xform optional transform for the output grid
77 /// (if not provided, the transform of the input @a grid will be matched)
78 /// @param interrupter optional interrupter object
79 ///
80 /// @throw TypeError if @a grid is not scalar or not floating-point
81 ///
82 /// @note If the input grid contains overlapping isosurfaces, interior edges will be lost.
83 template<class GridType, typename InterruptT>
84 typename GridType::Ptr
85 levelSetRebuild(const GridType& grid, float isovalue, float exBandWidth, float inBandWidth,
86  const math::Transform* xform = nullptr, InterruptT* interrupter = nullptr);
87 
88 
89 ////////////////////////////////////////
90 
91 /// @cond OPENVDB_DOCS_INTERNAL
92 
93 // Internal utility objects and implementation details
94 
95 namespace internal {
96 
97 class PointListTransform
98 {
99 public:
100  PointListTransform(const PointList& pointsIn, std::vector<Vec3s>& pointsOut,
101  const math::Transform& xform)
102  : mPointsIn(pointsIn)
103  , mPointsOut(&pointsOut)
104  , mXform(xform)
105  {
106  }
107 
108  void runParallel()
109  {
110  tbb::parallel_for(tbb::blocked_range<size_t>(0, mPointsOut->size()), *this);
111  }
112 
113  void runSerial()
114  {
115  (*this)(tbb::blocked_range<size_t>(0, mPointsOut->size()));
116  }
117 
118  inline void operator()(const tbb::blocked_range<size_t>& range) const
119  {
120  for (size_t n = range.begin(); n < range.end(); ++n) {
121  (*mPointsOut)[n] = Vec3s(mXform.worldToIndex(mPointsIn[n]));
122  }
123  }
124 
125 private:
126  const PointList& mPointsIn;
127  std::vector<Vec3s> * const mPointsOut;
128  const math::Transform& mXform;
129 };
130 
131 
132 class PrimCpy
133 {
134 public:
135  PrimCpy(const PolygonPoolList& primsIn, const std::vector<size_t>& indexList,
136  std::vector<Vec4I>& primsOut)
137  : mPrimsIn(primsIn)
138  , mIndexList(indexList)
139  , mPrimsOut(&primsOut)
140  {
141  }
142 
143  void runParallel()
144  {
145  tbb::parallel_for(tbb::blocked_range<size_t>(0, mIndexList.size()), *this);
146  }
147 
148  void runSerial()
149  {
150  (*this)(tbb::blocked_range<size_t>(0, mIndexList.size()));
151  }
152 
153  inline void operator()(const tbb::blocked_range<size_t>& range) const
154  {
155  openvdb::Vec4I quad;
156  quad[3] = openvdb::util::INVALID_IDX;
157  std::vector<Vec4I>& primsOut = *mPrimsOut;
158 
159  for (size_t n = range.begin(); n < range.end(); ++n) {
160  size_t index = mIndexList[n];
161  PolygonPool& polygons = mPrimsIn[n];
162 
163  // Copy quads
164  for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
165  primsOut[index++] = polygons.quad(i);
166  }
167  polygons.clearQuads();
168 
169  // Copy triangles (adaptive mesh)
170  for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
171  const openvdb::Vec3I& triangle = polygons.triangle(i);
172  quad[0] = triangle[0];
173  quad[1] = triangle[1];
174  quad[2] = triangle[2];
175  primsOut[index++] = quad;
176  }
177 
178  polygons.clearTriangles();
179  }
180  }
181 
182 private:
183  const PolygonPoolList& mPrimsIn;
184  const std::vector<size_t>& mIndexList;
185  std::vector<Vec4I> * const mPrimsOut;
186 };
187 
188 } // namespace internal
189 
190 /// @endcond
191 
192 ////////////////////////////////////////
193 
194 
195 //{
196 /// @cond OPENVDB_DOCS_INTERNAL
197 
198 /// The normal entry points for level set rebuild are the levelSetRebuild() functions.
199 /// doLevelSetRebuild() is mainly for internal use, but when the isovalue and half band
200 /// widths are given in ValueType units (for example, if they are queried from
201 /// a grid), it might be more convenient to call this function directly.
202 ///
203 /// @internal This overload is enabled only for grids with a scalar, floating-point ValueType.
204 template<class GridType, typename InterruptT>
205 inline typename std::enable_if<
207 doLevelSetRebuild(const GridType& grid, typename GridType::ValueType iso,
208  typename GridType::ValueType exWidth, typename GridType::ValueType inWidth,
209  const math::Transform* xform, InterruptT* interrupter)
210 {
211  const float
212  isovalue = float(iso),
213  exBandWidth = float(exWidth),
214  inBandWidth = float(inWidth);
215 
216  tools::VolumeToMesh mesher(isovalue);
217  mesher(grid);
218 
219  math::Transform::Ptr transform = (xform != nullptr) ? xform->copy() : grid.transform().copy();
220 
221  std::vector<Vec3s> points(mesher.pointListSize());
222 
223  { // Copy and transform (required for MeshToVolume) points to grid space.
224  internal::PointListTransform ptnXForm(mesher.pointList(), points, *transform);
225  ptnXForm.runParallel();
226  mesher.pointList().reset(nullptr);
227  }
228 
229  std::vector<Vec4I> primitives;
230 
231  { // Copy primitives.
232  PolygonPoolList& polygonPoolList = mesher.polygonPoolList();
233 
234  size_t numPrimitives = 0;
235  std::vector<size_t> indexlist(mesher.polygonPoolListSize());
236 
237  for (size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) {
238  const openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
239  indexlist[n] = numPrimitives;
240  numPrimitives += polygons.numQuads();
241  numPrimitives += polygons.numTriangles();
242  }
243 
244  primitives.resize(numPrimitives);
245  internal::PrimCpy primCpy(polygonPoolList, indexlist, primitives);
246  primCpy.runParallel();
247  }
248 
249  QuadAndTriangleDataAdapter<Vec3s, Vec4I> mesh(points, primitives);
250 
251  if (interrupter) {
252  return meshToVolume<GridType>(*interrupter, mesh, *transform, exBandWidth, inBandWidth,
253  DISABLE_RENORMALIZATION, nullptr);
254  }
255 
256  return meshToVolume<GridType>(mesh, *transform, exBandWidth, inBandWidth,
257  DISABLE_RENORMALIZATION, nullptr);
258 }
259 
260 
261 /// @internal This overload is enabled only for grids that do not have a scalar,
262 /// floating-point ValueType.
263 template<class GridType, typename InterruptT>
264 inline typename std::enable_if<
265  !std::is_floating_point<typename GridType::ValueType>::value, typename GridType::Ptr>::type
266 doLevelSetRebuild(const GridType&, typename GridType::ValueType /*isovalue*/,
267  typename GridType::ValueType /*exWidth*/, typename GridType::ValueType /*inWidth*/,
268  const math::Transform*, InterruptT*)
269 {
270  OPENVDB_THROW(TypeError,
271  "level set rebuild is supported only for scalar, floating-point grids");
272 }
273 
274 /// @endcond
275 //}
276 
277 
278 ////////////////////////////////////////
279 
280 
281 template<class GridType, typename InterruptT>
282 typename GridType::Ptr
283 levelSetRebuild(const GridType& grid, float iso, float exWidth, float inWidth,
284  const math::Transform* xform, InterruptT* interrupter)
285 {
286  using ValueT = typename GridType::ValueType;
287  ValueT
288  isovalue(zeroVal<ValueT>() + ValueT(iso)),
289  exBandWidth(zeroVal<ValueT>() + ValueT(exWidth)),
290  inBandWidth(zeroVal<ValueT>() + ValueT(inWidth));
291 
292  return doLevelSetRebuild(grid, isovalue, exBandWidth, inBandWidth, xform, interrupter);
293 }
294 
295 
296 template<class GridType>
297 typename GridType::Ptr
298 levelSetRebuild(const GridType& grid, float iso, float exWidth, float inWidth,
299  const math::Transform* xform)
300 {
301  using ValueT = typename GridType::ValueType;
302  ValueT
303  isovalue(zeroVal<ValueT>() + ValueT(iso)),
304  exBandWidth(zeroVal<ValueT>() + ValueT(exWidth)),
305  inBandWidth(zeroVal<ValueT>() + ValueT(inWidth));
306 
307  return doLevelSetRebuild<GridType, util::NullInterrupter>(
308  grid, isovalue, exBandWidth, inBandWidth, xform, nullptr);
309 }
310 
311 
312 template<class GridType>
313 typename GridType::Ptr
314 levelSetRebuild(const GridType& grid, float iso, float halfVal, const math::Transform* xform)
315 {
316  using ValueT = typename GridType::ValueType;
317  ValueT
318  isovalue(zeroVal<ValueT>() + ValueT(iso)),
319  halfWidth(zeroVal<ValueT>() + ValueT(halfVal));
320 
321  return doLevelSetRebuild<GridType, util::NullInterrupter>(
322  grid, isovalue, halfWidth, halfWidth, xform, nullptr);
323 }
324 
325 
326 ////////////////////////////////////////
327 
328 
329 // Explicit Template Instantiation
330 
331 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
332 
333 #ifdef OPENVDB_INSTANTIATE_LEVELSETREBUILD
335 #endif
336 
337 #define _FUNCTION(TreeT) \
338  Grid<TreeT>::Ptr levelSetRebuild(const Grid<TreeT>&, float, float, const math::Transform*)
340 #undef _FUNCTION
341 
342 #define _FUNCTION(TreeT) \
343  Grid<TreeT>::Ptr levelSetRebuild(const Grid<TreeT>&, float, float, float, const math::Transform*)
345 #undef _FUNCTION
346 
347 #define _FUNCTION(TreeT) \
348  Grid<TreeT>::Ptr levelSetRebuild(const Grid<TreeT>&, float, float, float, const math::Transform*, \
349  util::NullInterrupter*)
351 #undef _FUNCTION
352 
353 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
354 
355 
356 } // namespace tools
357 } // namespace OPENVDB_VERSION_NAME
358 } // namespace openvdb
359 
360 #endif // OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
OPENVDB_API const Index32 INVALID_IDX
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Definition: Transform.h:39
Extract polygonal surfaces from scalar volumes.
Definition: Mat4.h:24
GridType::Ptr levelSetRebuild(const GridType &grid, float isovalue, float exBandWidth, float inBandWidth, const math::Transform *xform=nullptr, InterruptT *interrupter=nullptr)
Return a new grid of type GridType that contains a narrow-band level set representation of an isosurf...
Definition: LevelSetRebuild.h:283
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
Definition: Exceptions.h:13
ValueT value
Definition: GridBuilder.h:1287
std::unique_ptr< PolygonPool[]> PolygonPoolList
Point and primitive list types.
Definition: VolumeToMesh.h:152
std::unique_ptr< openvdb::Vec3s[]> PointList
Point and primitive list types.
Definition: VolumeToMesh.h:151
Definition: Mat.h:187
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
Vec3< float > Vec3s
Definition: Vec3.h:667
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:422
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202