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