OpenVDB 12.0.0
 
Loading...
Searching...
No Matches
LevelSetMeasure.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3//
4/// @author Ken Museth
5///
6/// @file LevelSetMeasure.h
7
8#ifndef OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED
9#define OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED
10
11#include <openvdb/Types.h>
12#include <openvdb/Grid.h>
15#include <openvdb/math/Math.h>
20#include <openvdb/thread/Threading.h>
21#include <openvdb/openvdb.h>
22
23#include <tbb/parallel_for.h>
24#include <tbb/parallel_sort.h>
25#include <tbb/parallel_invoke.h>
26
27#include <type_traits>
28
29namespace openvdb {
31namespace OPENVDB_VERSION_NAME {
32namespace tools {
33
34/// @brief Return the surface area of a narrow-band level set.
35///
36/// @param grid a scalar, floating-point grid with one or more disjoint,
37/// closed level set surfaces
38/// @param useWorldSpace if true the area is computed in
39/// world space units, else in voxel units.
40///
41/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set or empty.
42template<class GridType>
43Real
44levelSetArea(const GridType& grid, bool useWorldSpace = true);
45
46/// @brief Return the volume of a narrow-band level set surface.
47///
48/// @param grid a scalar, floating-point grid with one or more disjoint,
49/// closed level set surfaces
50/// @param useWorldSpace if true the volume is computed in
51/// world space units, else in voxel units.
52///
53/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set or empty.
54template<class GridType>
55Real
56levelSetVolume(const GridType& grid, bool useWorldSpace = true);
57
58/// @brief Return the Euler Characteristics of a narrow-band level set surface (possibly disconnected).
59///
60/// @param grid a scalar, floating-point grid with one or more disjoint,
61/// closed level set surfaces
62///
63/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set or empty.
64template<class GridType>
65int
66levelSetEulerCharacteristic(const GridType& grid);
67
68/// @brief Return the genus of a narrow-band level set surface.
69///
70/// @param grid a scalar, floating-point grid with one or more disjoint,
71/// closed level set surfaces
72/// @warning The genus is only well defined for a single connected surface
73///
74/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set or empty.
75template<class GridType>
76int
77levelSetGenus(const GridType& grid);
78
79////////////////////////////////////////////////////////////////////////////////////////
80
81/// @brief Smeared-out and continuous Dirac Delta function.
82template<typename RealT>
84{
85public:
86 // eps is the half-width of the dirac delta function in units of phi
87 DiracDelta(RealT eps) : mC(0.5/eps), mD(2*math::pi<RealT>()*mC), mE(eps) {}
88 // values of the dirac delta function are in units of one over the units of phi
89 inline RealT operator()(RealT phi) const { return math::Abs(phi) > mE ? 0 : mC*(1+cos(mD*phi)); }
90private:
91 const RealT mC, mD, mE;
92};// DiracDelta functor
93
94
95/// @brief Multi-threaded computation of surface area, volume and
96/// average mean-curvature for narrow band level sets.
97///
98/// @details To reduce the risk of round-off errors (primarily due to
99/// catastrophic cancellation) and guarantee determinism during
100/// multi-threading this class is implemented using parallel_for, and
101/// delayed reduction of a sorted list.
102template<typename GridT, typename InterruptT = util::NullInterrupter>
104{
105public:
106 using GridType = GridT;
107 using TreeType = typename GridType::TreeType;
108 using ValueType = typename TreeType::ValueType;
110
111 static_assert(std::is_floating_point<ValueType>::value,
112 "level set measure is supported only for scalar, floating-point grids");
113
114 /// @brief Main constructor from a grid
115 /// @param grid The level set to be measured.
116 /// @param interrupt Optional interrupter.
117 /// @throw RuntimeError if the grid is not a level set or if it's empty.
118 LevelSetMeasure(const GridType& grid, InterruptT* interrupt = nullptr);
119
120 /// @brief Re-initialize using the specified grid.
121 /// @param grid The level set to be measured.
122 /// @throw RuntimeError if the grid is not a level set or if it's empty.
123 void init(const GridType& grid);
124
125 /// @brief Destructor
126 virtual ~LevelSetMeasure() {}
127
128 /// @return the grain-size used for multi-threading
129 int getGrainSize() const { return mGrainSize; }
130
131 /// @brief Set the grain-size used for multi-threading.
132 /// @note A grain size of 0 or less disables multi-threading!
133 void setGrainSize(int grainsize) { mGrainSize = grainsize; }
134
135 /// @brief Compute the surface area of the level set.
136 /// @param useWorldUnits Specifies if the result is in world or voxel units.
137 /// @note Performs internal caching so only the initial call incurs actual computation.
138 Real area(bool useWorldUnits = true);
139
140 /// @brief Compute the volume of the level set surface.
141 /// @param useWorldUnits Specifies if the result is in world or voxel units.
142 /// @note Performs internal caching so only the initial call incurs actual computation.
143 Real volume(bool useWorldUnits = true);
144
145 /// @brief Compute the total mean curvature of the level set surface.
146 /// @param useWorldUnits Specifies if the result is in world or voxel units.
147 /// @note Performs internal caching so only the initial call incurs actual computation.
148 Real totMeanCurvature(bool useWorldUnits = true);
149
150 /// @brief Compute the total gaussian curvature of the level set surface.
151 /// @param useWorldUnits Specifies if the result is in world or voxel units.
152 /// @note Performs internal caching so only the initial call incurs actual computation.
153 Real totGaussianCurvature(bool useWorldUnits = true);
154
155 /// @brief Compute the average mean curvature of the level set surface.
156 /// @param useWorldUnits Specifies if the result is in world or voxel units.
157 /// @note Performs internal caching so only the initial call incurs actual computation.
158 Real avgMeanCurvature(bool useWorldUnits = true) {return this->totMeanCurvature(useWorldUnits) / this->area(useWorldUnits);}
159
160 /// @brief Compute the average gaussian curvature of the level set surface.
161 /// @param useWorldUnits Specifies if the result is in world or voxel units.
162 /// @note Performs internal caching so only the initial call incurs actual computation.
163 Real avgGaussianCurvature(bool useWorldUnits = true) {return this->totGaussianCurvature(useWorldUnits) / this->area(useWorldUnits); }
164
165 /// @brief Compute the Euler characteristic of the level set surface.
166 /// @note Performs internal caching so only the initial call incurs actual computation.
167 int eulerCharacteristic();
168
169 /// @brief Compute the genus of the level set surface.
170 /// @warning The genus is only well defined for a single connected surface.
171 /// @note Performs internal caching so only the initial call incurs actual computation.
172 int genus() { return 1 - this->eulerCharacteristic()/2;}
173
174private:
175
176 using LeafT = typename TreeType::LeafNodeType;
177 using VoxelCIterT = typename LeafT::ValueOnCIter;
178 using LeafRange = typename ManagerType::LeafRange;
179 using LeafIterT = typename LeafRange::Iterator;
180 using ManagerPtr = std::unique_ptr<ManagerType>;
181 using BufferPtr = std::unique_ptr<double[]>;
182
183 // disallow copy construction and copy by assignment!
184 LevelSetMeasure(const LevelSetMeasure&);// not implemented
185 LevelSetMeasure& operator=(const LevelSetMeasure&);// not implemented
186
187 const GridType *mGrid;
188 ManagerPtr mLeafs;
189 BufferPtr mBuffer;
190 InterruptT *mInterrupter;
191 double mDx, mArea, mVolume, mTotMeanCurvature, mTotGausCurvature;
192 int mGrainSize;
193 bool mUpdateArea, mUpdateCurvature;
194
195 // @brief Return false if the process was interrupted
196 bool checkInterrupter();
197
198 struct MeasureArea
199 {
200 MeasureArea(LevelSetMeasure* parent) : mParent(parent), mStencil(*mParent->mGrid)
201 {
202 if (parent->mInterrupter) parent->mInterrupter->start("Measuring area and volume of level set");
203 if (parent->mGrainSize>0) {
204 tbb::parallel_for(parent->mLeafs->leafRange(parent->mGrainSize), *this);
205 } else {
206 (*this)(parent->mLeafs->leafRange());
207 }
208 tbb::parallel_invoke([&](){parent->mArea = parent->reduce(0);},
209 [&](){parent->mVolume = parent->reduce(1)/3.0;});
210 parent->mUpdateArea = false;
211 if (parent->mInterrupter) parent->mInterrupter->end();
212 }
213 MeasureArea(const MeasureArea& other) : mParent(other.mParent), mStencil(*mParent->mGrid) {}
214 void operator()(const LeafRange& range) const;
215 LevelSetMeasure* mParent;
216 mutable math::GradStencil<GridT, false> mStencil;
217 };// MeasureArea
218
219 struct MeasureCurvatures
220 {
221 MeasureCurvatures(LevelSetMeasure* parent) : mParent(parent), mStencil(*mParent->mGrid)
222 {
223 if (parent->mInterrupter) parent->mInterrupter->start("Measuring curvatures of level set");
224 if (parent->mGrainSize>0) {
225 tbb::parallel_for(parent->mLeafs->leafRange(parent->mGrainSize), *this);
226 } else {
227 (*this)(parent->mLeafs->leafRange());
228 }
229 tbb::parallel_invoke([&](){parent->mTotMeanCurvature = parent->reduce(0);},
230 [&](){parent->mTotGausCurvature = parent->reduce(1);});
231 parent->mUpdateCurvature = false;
232 if (parent->mInterrupter) parent->mInterrupter->end();
233 }
234 MeasureCurvatures(const MeasureCurvatures& other) : mParent(other.mParent), mStencil(*mParent->mGrid) {}
235 void operator()(const LeafRange& range) const;
236 LevelSetMeasure* mParent;
237 mutable math::CurvatureStencil<GridT, false> mStencil;
238 };// MeasureCurvatures
239
240 double reduce(int offset)
241 {
242 double *first = mBuffer.get() + offset*mLeafs->leafCount(), *last = first + mLeafs->leafCount();
243 tbb::parallel_sort(first, last);// mitigates catastrophic cancellation
244 Real sum = 0.0;
245 while(first != last) sum += *first++;
246 return sum;
247 }
248
249}; // end of LevelSetMeasure class
250
251
252template<typename GridT, typename InterruptT>
253inline
255 : mInterrupter(interrupt)
256 , mGrainSize(1)
257{
258 this->init(grid);
259}
260
261template<typename GridT, typename InterruptT>
262inline void
264{
265 if (!grid.hasUniformVoxels()) {
267 "The transform must have uniform scale for the LevelSetMeasure to function");
268 }
269 if (grid.getGridClass() != GRID_LEVEL_SET) {
271 "LevelSetMeasure only supports level sets;"
272 " try setting the grid class to \"level set\"");
273 }
274 if (grid.empty()) {
276 "LevelSetMeasure does not support empty grids;");
277 }
278 mGrid = &grid;
279 mDx = grid.voxelSize()[0];
280 mLeafs = std::make_unique<ManagerType>(mGrid->tree());
281 mBuffer = std::make_unique<double[]>(2*mLeafs->leafCount());
282 mUpdateArea = mUpdateCurvature = true;
283}
284
285template<typename GridT, typename InterruptT>
286inline Real
288{
289 if (mUpdateArea) {MeasureArea m(this);};
290 double area = mArea;
291 if (useWorldUnits) area *= math::Pow2(mDx);
292 return area;
293}
294
295template<typename GridT, typename InterruptT>
296inline Real
298{
299 if (mUpdateArea) {MeasureArea m(this);};
300 double volume = mVolume;
301 if (useWorldUnits) volume *= math::Pow3(mDx) ;
302 return volume;
303}
304
305template<typename GridT, typename InterruptT>
306inline Real
308{
309 if (mUpdateCurvature) {MeasureCurvatures m(this);};
310 return mTotMeanCurvature * (useWorldUnits ? mDx : 1);
311}
312
313template<typename GridT, typename InterruptT>
314inline Real
316{
317 if (mUpdateCurvature) {MeasureCurvatures m(this);};
318 return mTotGausCurvature;
319}
320
321template<typename GridT, typename InterruptT>
322inline int
324{
325 const Real x = this->totGaussianCurvature(true) / (2.0*math::pi<Real>());
326 return int(math::Round( x ));
327}
328
329///////////////////////// PRIVATE METHODS //////////////////////
330
331template<typename GridT, typename InterruptT>
332inline bool
333LevelSetMeasure<GridT, InterruptT>::checkInterrupter()
334{
335 if (util::wasInterrupted(mInterrupter)) {
336 thread::cancelGroupExecution();
337 return false;
338 }
339 return true;
340}
341
342template<typename GridT, typename InterruptT>
343inline void
344LevelSetMeasure<GridT, InterruptT>::
345MeasureArea::operator()(const LeafRange& range) const
346{
347 using Vec3T = math::Vec3<ValueType>;
348 // computations are performed in index space where dV = 1
349 mParent->checkInterrupter();
350 const Real invDx = 1.0/mParent->mDx;
351 const DiracDelta<Real> DD(1.5);// dirac delta function is 3 voxel units wide
352 const size_t leafCount = mParent->mLeafs->leafCount();
353 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
354 Real sumA = 0, sumV = 0;//reduce risk of catastrophic cancellation
355 for (VoxelCIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
356 const Real dd = DD(invDx * (*voxelIter));
357 if (dd > 0.0) {
358 mStencil.moveTo(voxelIter);
359 const Coord& p = mStencil.getCenterCoord();// in voxel units
360 const Vec3T g = mStencil.gradient();// in world units
361 sumA += dd*g.length();// \delta(\phi)*|\nabla\phi|
362 sumV += dd*(g[0]*Real(p[0]) + g[1]*Real(p[1]) + g[2]*Real(p[2]));// \delta(\phi)\vec{x}\cdot\nabla\phi
363 }
364 }
365 double* ptr = mParent->mBuffer.get() + leafIter.pos();
366 *ptr = sumA;
367 ptr += leafCount;
368 *ptr = sumV;
369 }
370}
371
372template<typename GridT, typename InterruptT>
373inline void
375MeasureCurvatures::operator()(const LeafRange& range) const
376{
377 using Vec3T = math::Vec3<ValueType>;
378 // computations are performed in index space where dV = 1
379 mParent->checkInterrupter();
380 const Real dx = mParent->mDx, dx2=dx*dx, invDx = 1.0/dx;
381 const DiracDelta<Real> DD(1.5);// dirac delta function is 3 voxel units wide
382 ValueType mean, gauss;
383 const size_t leafCount = mParent->mLeafs->leafCount();
384 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
385 Real sumM = 0, sumG = 0;//reduce risk of catastrophic cancellation
386 for (VoxelCIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
387 const Real dd = DD(invDx * (*voxelIter));
388 if (dd > 0.0) {
389 mStencil.moveTo(voxelIter);
390 const Vec3T g = mStencil.gradient();
391 const Real dA = dd*g.length();// \delta(\phi)*\delta(\phi)
392 mStencil.curvatures(mean, gauss);
393 sumM += dA*mean*dx;// \delta(\phi)*\delta(\phi)*MeanCurvature
394 sumG += dA*gauss*dx2;// \delta(\phi)*\delta(\phi)*GaussCurvature
395 }
396 }
397 double* ptr = mParent->mBuffer.get() + leafIter.pos();
398 *ptr = sumM;
399 ptr += leafCount;
400 *ptr = sumG;
401 }
402}
403
404////////////////////////////////////////
405
406//{
407/// @cond OPENVDB_DOCS_INTERNAL
408
409template<class GridT>
410inline
411typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, Real>::type
412doLevelSetArea(const GridT& grid, bool useWorldUnits)
413{
415 return m.area(useWorldUnits);
416}
417
418template<class GridT>
419inline
420typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, Real>::type
421doLevelSetArea(const GridT&, bool)
422{
423 OPENVDB_THROW(TypeError,
424 "level set area is supported only for scalar, floating-point grids");
425}
426
427/// @endcond
428//}
429
430template<class GridT>
431Real
432levelSetArea(const GridT& grid, bool useWorldUnits)
433{
434 return doLevelSetArea<GridT>(grid, useWorldUnits);
435}
436
437////////////////////////////////////////
438
439//{
440/// @cond OPENVDB_DOCS_INTERNAL
441
442template<class GridT>
443inline
444typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, Real>::type
445doLevelSetVolume(const GridT& grid, bool useWorldUnits)
446{
447 LevelSetMeasure<GridT> m(grid);
448 return m.volume(useWorldUnits);
449}
450
451template<class GridT>
452inline
453typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, Real>::type
454doLevelSetVolume(const GridT&, bool)
455{
457 "level set volume is supported only for scalar, floating-point grids");
458}
459
460/// @endcond
461//}
462
463template<class GridT>
464Real
465levelSetVolume(const GridT& grid, bool useWorldUnits)
466{
467 return doLevelSetVolume<GridT>(grid, useWorldUnits);
468}
469
470////////////////////////////////////////
471
472//{
473/// @cond OPENVDB_DOCS_INTERNAL
474
475template<class GridT>
476inline
477typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, int>::type
478doLevelSetEulerCharacteristic(const GridT& grid)
479{
480 LevelSetMeasure<GridT> m(grid);
481 return m.eulerCharacteristic();
482}
483
484template<class GridT>
485inline
486typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, int>::type
487doLevelSetEulerCharacteristic(const GridT&)
488{
490 "level set euler characteristic is supported only for scalar, floating-point grids");
491}
492
493/// @endcond
494//}
495
496
497template<class GridT>
498int
500{
501 return doLevelSetEulerCharacteristic(grid);
502}
503
504////////////////////////////////////////
505
506//{
507/// @cond OPENVDB_DOCS_INTERNAL
508
509template<class GridT>
510inline
511typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, int>::type
512doLevelSetEuler(const GridT& grid)
513{
514 LevelSetMeasure<GridT> m(grid);
515 return m.eulerCharacteristics();
516
517}
518
519template<class GridT>
520inline
521typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, int>::type
522doLevelSetGenus(const GridT& grid)
523{
524 LevelSetMeasure<GridT> m(grid);
525 return m.genus();
526}
527
528template<class GridT>
529inline
530typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, int>::type
531doLevelSetGenus(const GridT&)
532{
533 OPENVDB_THROW(TypeError,
534 "level set genus is supported only for scalar, floating-point grids");
535}
536
537/// @endcond
538//}
539
540template<class GridT>
541int
542levelSetGenus(const GridT& grid)
543{
544 return doLevelSetGenus(grid);
545}
546
547
548////////////////////////////////////////
549
550
551// Explicit Template Instantiation
552
553#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
554
555#ifdef OPENVDB_INSTANTIATE_LEVELSETMEASURE
557#endif
558
559#define _FUNCTION(TreeT) \
560 Real levelSetArea(const Grid<TreeT>&, bool)
562#undef _FUNCTION
563
564#define _FUNCTION(TreeT) \
565 Real levelSetVolume(const Grid<TreeT>&, bool)
567#undef _FUNCTION
568
569#define _FUNCTION(TreeT) \
570 int levelSetEulerCharacteristic(const Grid<TreeT>&)
572#undef _FUNCTION
573
574#define _FUNCTION(TreeT) \
575 int levelSetGenus(const Grid<TreeT>&)
577#undef _FUNCTION
578
579OPENVDB_INSTANTIATE_CLASS LevelSetMeasure<FloatGrid, util::NullInterrupter>;
580OPENVDB_INSTANTIATE_CLASS LevelSetMeasure<DoubleGrid, util::NullInterrupter>;
581
582#endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
583
584
585} // namespace tools
586} // namespace OPENVDB_VERSION_NAME
587} // namespace openvdb
588
589#endif // OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
ValueAccessors are designed to help accelerate accesses into the OpenVDB Tree structures by storing c...
Definition Exceptions.h:63
Definition Exceptions.h:64
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Definition Stencils.h:1232
Definition Vec3.h:25
Smeared-out and continuous Dirac Delta function.
Definition LevelSetMeasure.h:84
DiracDelta(RealT eps)
Definition LevelSetMeasure.h:87
RealT operator()(RealT phi) const
Definition LevelSetMeasure.h:89
Multi-threaded computation of surface area, volume and average mean-curvature for narrow band level s...
Definition LevelSetMeasure.h:104
int genus()
Compute the genus of the level set surface.
Definition LevelSetMeasure.h:172
Real avgGaussianCurvature(bool useWorldUnits=true)
Compute the average gaussian curvature of the level set surface.
Definition LevelSetMeasure.h:163
int eulerCharacteristic()
Compute the Euler characteristic of the level set surface.
Definition LevelSetMeasure.h:323
virtual ~LevelSetMeasure()
Destructor.
Definition LevelSetMeasure.h:126
void init(const GridType &grid)
Re-initialize using the specified grid.
Definition LevelSetMeasure.h:263
typename TreeType::ValueType ValueType
Definition LevelSetMeasure.h:108
LevelSetMeasure(const GridType &grid, InterruptT *interrupt=nullptr)
Main constructor from a grid.
Definition LevelSetMeasure.h:254
typename tree::LeafManager< const TreeType > ManagerType
Definition LevelSetMeasure.h:109
Real totGaussianCurvature(bool useWorldUnits=true)
Compute the total gaussian curvature of the level set surface.
Definition LevelSetMeasure.h:315
void setGrainSize(int grainsize)
Set the grain-size used for multi-threading.
Definition LevelSetMeasure.h:133
int getGrainSize() const
Definition LevelSetMeasure.h:129
typename GridType::TreeType TreeType
Definition LevelSetMeasure.h:107
Real area(bool useWorldUnits=true)
Compute the surface area of the level set.
Definition LevelSetMeasure.h:287
Real volume(bool useWorldUnits=true)
Compute the volume of the level set surface.
Definition LevelSetMeasure.h:297
Real avgMeanCurvature(bool useWorldUnits=true)
Compute the average mean curvature of the level set surface.
Definition LevelSetMeasure.h:158
Real totMeanCurvature(bool useWorldUnits=true)
Compute the total mean curvature of the level set surface.
Definition LevelSetMeasure.h:307
GridT GridType
Definition LevelSetMeasure.h:106
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
T reduce(RangeT range, const T &identity, const FuncT &func, const JoinT &join)
Definition Reduce.h:43
Definition Types.h:28
constexpr T pi()
Pi constant taken from Boost to match old behaviour.
Definition Math.h:119
Coord Abs(const Coord &xyz)
Definition Coord.h:518
float Round(float x)
Return x rounded to the nearest integer.
Definition Math.h:819
Type Pow3(Type x)
Return x3.
Definition Math.h:552
Type Pow2(Type x)
Return x2.
Definition Math.h:548
Real levelSetArea(const GridType &grid, bool useWorldSpace=true)
Return the surface area of a narrow-band level set.
if(shared)
Definition ValueTransformer.h:596
int levelSetGenus(const GridType &grid)
Return the genus of a narrow-band level set surface.
int levelSetEulerCharacteristic(const GridType &grid)
Return the Euler Characteristics of a narrow-band level set surface (possibly disconnected).
Real levelSetVolume(const GridType &grid, bool useWorldSpace=true)
Return the volume of a narrow-band level set surface.
bool wasInterrupted(T *i, int percent=-1)
Definition NullInterrupter.h:49
double Real
Definition Types.h:60
@ GRID_LEVEL_SET
Definition Types.h:455
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218
#define OPENVDB_INSTANTIATE_CLASS
Definition version.h.in:158
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition version.h.in:162