OpenVDB 7.0.0

LevelSetMeasure.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
7
8 #ifndef OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED
9 #define OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED
10
11 #include <openvdb/math/Math.h>
12 #include <openvdb/Types.h>
13 #include <openvdb/Grid.h>
14 #include <openvdb/tree/LeafManager.h>
15 #include <openvdb/tree/ValueAccessor.h>
16 #include <openvdb/math/FiniteDifference.h>
17 #include <openvdb/math/Operators.h>
18 #include <openvdb/math/Stencils.h>
19 #include <openvdb/util/NullInterrupter.h>
20 #include <boost/math/constants/constants.hpp>//for Pi
21 #include <tbb/parallel_for.h>
22 #include <tbb/parallel_sort.h>
23 #include <tbb/parallel_invoke.h>
24 #include <type_traits>
25
26 namespace openvdb {
27 OPENVDB_USE_VERSION_NAMESPACE
28 namespace OPENVDB_VERSION_NAME {
29 namespace tools {
30
39 template<class GridType>
40 inline Real
41 levelSetArea(const GridType& grid, bool useWorldSpace = true);
42
51 template<class GridType>
52 inline Real
53 levelSetVolume(const GridType& grid, bool useWorldSpace = true);
54
61 template<class GridType>
62 inline int
63 levelSetEulerCharacteristic(const GridType& grid);
64
72 template<class GridType>
73 inline int
74 levelSetGenus(const GridType& grid);
75
77
79 template<typename RealT>
80 class DiracDelta
81 {
82 public:
83 // eps is the half-width of the dirac delta function in units of phi
84 DiracDelta(RealT eps) : mC(0.5/eps), mD(2*boost::math::constants::pi<RealT>()*mC), mE(eps) {}
85 // values of the dirac delta function are in units of one over the units of phi
86 inline RealT operator()(RealT phi) const { return math::Abs(phi) > mE ? 0 : mC*(1+cos(mD*phi)); }
87 private:
88 const RealT mC, mD, mE;
89 };// DiracDelta functor
90
91
99 template<typename GridT, typename InterruptT = util::NullInterrupter>
100 class LevelSetMeasure
101 {
102 public:
103 using GridType = GridT;
104 using TreeType = typename GridType::TreeType;
105 using ValueType = typename TreeType::ValueType;
106 using ManagerType = typename tree::LeafManager<const TreeType>;
107
108 static_assert(std::is_floating_point<ValueType>::value,
109 "level set measure is supported only for scalar, floating-point grids");
110
115 LevelSetMeasure(const GridType& grid, InterruptT* interrupt = nullptr);
116
120 void init(const GridType& grid);
121
123 virtual ~LevelSetMeasure() {}
124
126 int getGrainSize() const { return mGrainSize; }
127
130 void setGrainSize(int grainsize) { mGrainSize = grainsize; }
131
135 Real area(bool useWorldUnits = true);
136
140 Real volume(bool useWorldUnits = true);
141
145 Real totMeanCurvature(bool useWorldUnits = true);
146
150 Real totGaussianCurvature(bool useWorldUnits = true);
151
155 Real avgMeanCurvature(bool useWorldUnits = true) {return this->totMeanCurvature(useWorldUnits) / this->area(useWorldUnits);}
156
160 Real avgGaussianCurvature(bool useWorldUnits = true) {return this->totGaussianCurvature(useWorldUnits) / this->area(useWorldUnits); }
161
164 int eulerCharacteristic();
165
169 int genus() { return 1 - this->eulerCharacteristic()/2;}
170
171 private:
172
173 using LeafT = typename TreeType::LeafNodeType;
174 using VoxelCIterT = typename LeafT::ValueOnCIter;
175 using LeafRange = typename ManagerType::LeafRange;
176 using LeafIterT = typename LeafRange::Iterator;
177 using ManagerPtr = std::unique_ptr<ManagerType>;
178 using BufferPtr = std::unique_ptr<double[]>;
179
180 // disallow copy construction and copy by assignment!
181 LevelSetMeasure(const LevelSetMeasure&);// not implemented
182 LevelSetMeasure& operator=(const LevelSetMeasure&);// not implemented
183
184 const GridType *mGrid;
185 ManagerPtr mLeafs;
186 BufferPtr mBuffer;
187 InterruptT *mInterrupter;
188 double mDx, mArea, mVolume, mTotMeanCurvature, mTotGausCurvature;
189 int mGrainSize;
190 bool mUpdateArea, mUpdateCurvature;
191
192 // @brief Return false if the process was interrupted
193 bool checkInterrupter();
194
195 struct MeasureArea
196 {
197 MeasureArea(LevelSetMeasure* parent) : mParent(parent), mStencil(*mParent->mGrid)
198 {
199 if (parent->mInterrupter) parent->mInterrupter->start("Measuring area and volume of level set");
200 if (parent->mGrainSize>0) {
201 tbb::parallel_for(parent->mLeafs->leafRange(parent->mGrainSize), *this);
202 } else {
203 (*this)(parent->mLeafs->leafRange());
204 }
205 tbb::parallel_invoke([&](){parent->mArea = parent->reduce(0);},
206 [&](){parent->mVolume = parent->reduce(1)/3.0;});
207 parent->mUpdateArea = false;
208 if (parent->mInterrupter) parent->mInterrupter->end();
209 }
210 MeasureArea(const MeasureArea& other) : mParent(other.mParent), mStencil(*mParent->mGrid) {}
211 void operator()(const LeafRange& range) const;
212 LevelSetMeasure* mParent;
213 mutable math::GradStencil<GridT, false> mStencil;
214 };// MeasureArea
215
216 struct MeasureCurvatures
217 {
218 MeasureCurvatures(LevelSetMeasure* parent) : mParent(parent), mStencil(*mParent->mGrid)
219 {
220 if (parent->mInterrupter) parent->mInterrupter->start("Measuring curvatures of level set");
221 if (parent->mGrainSize>0) {
222 tbb::parallel_for(parent->mLeafs->leafRange(parent->mGrainSize), *this);
223 } else {
224 (*this)(parent->mLeafs->leafRange());
225 }
226 tbb::parallel_invoke([&](){parent->mTotMeanCurvature = parent->reduce(0);},
227 [&](){parent->mTotGausCurvature = parent->reduce(1);});
228 parent->mUpdateCurvature = false;
229 if (parent->mInterrupter) parent->mInterrupter->end();
230 }
231 MeasureCurvatures(const MeasureCurvatures& other) : mParent(other.mParent), mStencil(*mParent->mGrid) {}
232 void operator()(const LeafRange& range) const;
233 LevelSetMeasure* mParent;
234 mutable math::CurvatureStencil<GridT, false> mStencil;
235 };// MeasureCurvatures
236
237 double reduce(int offset)
238 {
239 double *first = mBuffer.get() + offset*mLeafs->leafCount(), *last = first + mLeafs->leafCount();
240 tbb::parallel_sort(first, last);// mitigates catastrophic cancellation
241 Real sum = 0.0;
242 while(first != last) sum += *first++;
243 return sum;
244 }
245
246 }; // end of LevelSetMeasure class
247
248
249 template<typename GridT, typename InterruptT>
250 inline
251 LevelSetMeasure<GridT, InterruptT>::LevelSetMeasure(const GridType& grid, InterruptT* interrupt)
252 : mInterrupter(interrupt)
253 , mGrainSize(1)
254 {
255 this->init(grid);
256 }
257
258 template<typename GridT, typename InterruptT>
259 inline void
260 LevelSetMeasure<GridT, InterruptT>::init(const GridType& grid)
261 {
262 if (!grid.hasUniformVoxels()) {
263 OPENVDB_THROW(RuntimeError,
264 "The transform must have uniform scale for the LevelSetMeasure to function");
265 }
266 if (grid.getGridClass() != GRID_LEVEL_SET) {
267 OPENVDB_THROW(RuntimeError,
268 "LevelSetMeasure only supports level sets;"
269 " try setting the grid class to \"level set\"");
270 }
271 if (grid.empty()) {
272 OPENVDB_THROW(RuntimeError,
273 "LevelSetMeasure does not support empty grids;");
274 }
275 mGrid = &grid;
276 mDx = grid.voxelSize()[0];
277 mLeafs = std::make_unique<ManagerType>(mGrid->tree());
278 mBuffer = std::make_unique<double[]>(2*mLeafs->leafCount());
279 mUpdateArea = mUpdateCurvature = true;
280 }
281
282 template<typename GridT, typename InterruptT>
283 inline Real
284 LevelSetMeasure<GridT, InterruptT>::area(bool useWorldUnits)
285 {
286 if (mUpdateArea) {MeasureArea m(this);};
287 double area = mArea;
288 if (useWorldUnits) area *= math::Pow2(mDx);
289 return area;
290 }
291
292 template<typename GridT, typename InterruptT>
293 inline Real
294 LevelSetMeasure<GridT, InterruptT>::volume(bool useWorldUnits)
295 {
296 if (mUpdateArea) {MeasureArea m(this);};
297 double volume = mVolume;
298 if (useWorldUnits) volume *= math::Pow3(mDx) ;
299 return volume;
300 }
301
302 template<typename GridT, typename InterruptT>
303 inline Real
304 LevelSetMeasure<GridT, InterruptT>::totMeanCurvature(bool useWorldUnits)
305 {
306 if (mUpdateCurvature) {MeasureCurvatures m(this);};
307 return mTotMeanCurvature * (useWorldUnits ? mDx : 1);
308 }
309
310 template<typename GridT, typename InterruptT>
311 inline Real
312 LevelSetMeasure<GridT, InterruptT>::totGaussianCurvature(bool)
313 {
314 if (mUpdateCurvature) {MeasureCurvatures m(this);};
315 return mTotGausCurvature;
316 }
317
318 template<typename GridT, typename InterruptT>
319 inline int
320 LevelSetMeasure<GridT, InterruptT>::eulerCharacteristic()
321 {
322 const Real x = this->totGaussianCurvature(true) / (2.0*boost::math::constants::pi<Real>());
323 return int(math::Round( x ));
324 }
325
327
328 template<typename GridT, typename InterruptT>
329 inline bool
330 LevelSetMeasure<GridT, InterruptT>::checkInterrupter()
331 {
332 if (util::wasInterrupted(mInterrupter)) {
333 tbb::task::self().cancel_group_execution();
334 return false;
335 }
336 return true;
337 }
338
339 template<typename GridT, typename InterruptT>
340 inline void
341 LevelSetMeasure<GridT, InterruptT>::
342 MeasureArea::operator()(const LeafRange& range) const
343 {
344 using Vec3T = math::Vec3<ValueType>;
345 // computations are performed in index space where dV = 1
346 mParent->checkInterrupter();
347 const Real invDx = 1.0/mParent->mDx;
348 const DiracDelta<Real> DD(1.5);// dirac delta function is 3 voxel units wide
349 const size_t leafCount = mParent->mLeafs->leafCount();
350 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
351 Real sumA = 0, sumV = 0;//reduce risk of catastrophic cancellation
352 for (VoxelCIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
353 const Real dd = DD(invDx * (*voxelIter));
354 if (dd > 0.0) {
355 mStencil.moveTo(voxelIter);
356 const Coord& p = mStencil.getCenterCoord();// in voxel units
357 const Vec3T g = mStencil.gradient();// in world units
358 sumA += dd*g.length();// \delta(\phi)*|\nabla\phi|
359 sumV += dd*(g[0]*Real(p[0]) + g[1]*Real(p[1]) + g[2]*Real(p[2]));// \delta(\phi)\vec{x}\cdot\nabla\phi
360 }
361 }
362 double* ptr = mParent->mBuffer.get() + leafIter.pos();
363 *ptr = sumA;
364 ptr += leafCount;
365 *ptr = sumV;
366 }
367 }
368
369 template<typename GridT, typename InterruptT>
370 inline void
371 LevelSetMeasure<GridT, InterruptT>::
372 MeasureCurvatures::operator()(const LeafRange& range) const
373 {
374 using Vec3T = math::Vec3<ValueType>;
375 // computations are performed in index space where dV = 1
376 mParent->checkInterrupter();
377 const Real dx = mParent->mDx, dx2=dx*dx, invDx = 1.0/dx;
378 const DiracDelta<Real> DD(1.5);// dirac delta function is 3 voxel units wide
379 ValueType mean, gauss;
380 const size_t leafCount = mParent->mLeafs->leafCount();
381 for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) {
382 Real sumM = 0, sumG = 0;//reduce risk of catastrophic cancellation
383 for (VoxelCIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
384 const Real dd = DD(invDx * (*voxelIter));
385 if (dd > 0.0) {
386 mStencil.moveTo(voxelIter);
387 const Vec3T g = mStencil.gradient();
388 const Real dA = dd*g.length();// \delta(\phi)*\delta(\phi)
389 mStencil.curvatures(mean, gauss);
390 sumM += dA*mean*dx;// \delta(\phi)*\delta(\phi)*MeanCurvature
391 sumG += dA*gauss*dx2;// \delta(\phi)*\delta(\phi)*GaussCurvature
392 }
393 }
394 double* ptr = mParent->mBuffer.get() + leafIter.pos();
395 *ptr = sumM;
396 ptr += leafCount;
397 *ptr = sumG;
398 }
399 }
400
402
403 //{
405
406 template<class GridT>
407 inline
408 typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, Real>::type
409 doLevelSetArea(const GridT& grid, bool useWorldUnits)
410 {
411 LevelSetMeasure<GridT> m(grid);
412 return m.area(useWorldUnits);
413 }
414
415 template<class GridT>
416 inline
417 typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, Real>::type
418 doLevelSetArea(const GridT&, bool)
419 {
420 OPENVDB_THROW(TypeError,
421 "level set area is supported only for scalar, floating-point grids");
422 }
423
425 //}
426
427 template<class GridT>
428 inline Real
429 levelSetArea(const GridT& grid, bool useWorldUnits)
430 {
431 return doLevelSetArea<GridT>(grid, useWorldUnits);
432 }
433
435
436 //{
438
439 template<class GridT>
440 inline
441 typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, Real>::type
442 doLevelSetVolume(const GridT& grid, bool useWorldUnits)
443 {
444 LevelSetMeasure<GridT> m(grid);
445 return m.volume(useWorldUnits);
446 }
447
448 template<class GridT>
449 inline
450 typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, Real>::type
451 doLevelSetVolume(const GridT&, bool)
452 {
453 OPENVDB_THROW(TypeError,
454 "level set volume is supported only for scalar, floating-point grids");
455 }
456
458 //}
459
460 template<class GridT>
461 inline Real
462 levelSetVolume(const GridT& grid, bool useWorldUnits)
463 {
464 return doLevelSetVolume<GridT>(grid, useWorldUnits);
465 }
466
468
469 //{
471
472 template<class GridT>
473 inline
474 typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, int>::type
475 doLevelSetEulerCharacteristic(const GridT& grid)
476 {
477 LevelSetMeasure<GridT> m(grid);
478 return m.eulerCharacteristic();
479 }
480
481 template<class GridT>
482 inline
483 typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, int>::type
484 doLevelSetEulerCharacteristic(const GridT&)
485 {
486 OPENVDB_THROW(TypeError,
487 "level set euler characteristic is supported only for scalar, floating-point grids");
488 }
489
491 //}
492
493
494 template<class GridT>
495 inline int
496 levelSetEulerCharacteristic(const GridT& grid)
497 {
498 return doLevelSetEulerCharacteristic(grid);
499 }
500
502
503 //{
505
506 template<class GridT>
507 inline
508 typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, int>::type
509 doLevelSetEuler(const GridT& grid)
510 {
511 LevelSetMeasure<GridT> m(grid);
512 return m.eulerCharacteristics();
513
514 }
515
516 template<class GridT>
517 inline
518 typename std::enable_if<std::is_floating_point<typename GridT::ValueType>::value, int>::type
519 doLevelSetGenus(const GridT& grid)
520 {
521 LevelSetMeasure<GridT> m(grid);
522 return m.genus();
523 }
524
525 template<class GridT>
526 inline
527 typename std::enable_if<!std::is_floating_point<typename GridT::ValueType>::value, int>::type
528 doLevelSetGenus(const GridT&)
529 {
530 OPENVDB_THROW(TypeError,
531 "level set genus is supported only for scalar, floating-point grids");
532 }
533
535 //}
536
537 template<class GridT>
538 inline int
539 levelSetGenus(const GridT& grid)
540 {
541 return doLevelSetGenus(grid);
542 }
543
545
547 template<class GridT>
548 OPENVDB_DEPRECATED
549 inline void
550 levelSetMeasure(const GridT& grid, Real& area, Real& volume, Real& avgCurvature,
551 bool useWorldUnits = true)
552 {
553 LevelSetMeasure<GridT> m(grid);
554 area = m.area(useWorldUnits);
555 volume = m.volume(useWorldUnits);
556 avgCurvature = m.avgMeanCurvature(useWorldUnits);
557 }
558
559 } // namespace tools
560 } // namespace OPENVDB_VERSION_NAME
561 } // namespace openvdb
562
563 #endif // OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED
openvdb::v7_0::tools::LevelSetMeasure::totMeanCurvature
Real totMeanCurvature(bool useWorldUnits=true)
Compute the total mean curvature of the level set surface.
Definition: LevelSetMeasure.h:304
openvdb::v7_0::tools::LevelSetMeasure::ManagerType
typename tree::LeafManager< const TreeType > ManagerType
Definition: LevelSetMeasure.h:106
openvdb::v7_0::tools::levelSetGenus
int levelSetGenus(const GridT &grid)
Definition: LevelSetMeasure.h:539
openvdb::v7_0::tools::LevelSetMeasure::TreeType
typename GridType::TreeType TreeType
Definition: LevelSetMeasure.h:104
openvdb::v7_0::tools::levelSetMeasure
OPENVDB_DEPRECATED void levelSetMeasure(const GridT &grid, Real &area, Real &volume, Real &avgCurvature, bool useWorldUnits=true)
Definition: LevelSetMeasure.h:550
openvdb::v7_0::tools::LevelSetMeasure::GridType
GridT GridType
Definition: LevelSetMeasure.h:103
Types.h
openvdb::v7_0::tools::DiracDelta
Smeared-out and continuous Dirac Delta function.
Definition: LevelSetMeasure.h:80
openvdb::v7_0::tools::LevelSetMeasure::genus
int genus()
Compute the genus of the level set surface.
Definition: LevelSetMeasure.h:169
openvdb::v7_0::math::Round
float Round(float x)
Return x rounded to the nearest integer.
Definition: Math.h:766
openvdb::v7_0::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
openvdb::v7_0::tools::LevelSetMeasure::avgGaussianCurvature
Real avgGaussianCurvature(bool useWorldUnits=true)
Compute the average gaussian curvature of the level set surface.
Definition: LevelSetMeasure.h:160
openvdb::v7_0::tools::levelSetVolume
Real levelSetVolume(const GridType &grid, bool useWorldSpace=true)
Return the volume of a narrow-band level set surface.
openvdb::v7_0::tools::LevelSetMeasure::avgMeanCurvature
Real avgMeanCurvature(bool useWorldUnits=true)
Compute the average mean curvature of the level set surface.
Definition: LevelSetMeasure.h:155
openvdb::v7_0::tools::LevelSetMeasure::volume
Real volume(bool useWorldUnits=true)
Compute the volume of the level set surface.
Definition: LevelSetMeasure.h:294
openvdb::v7_0::tools::LevelSetMeasure::ValueType
typename TreeType::ValueType ValueType
Definition: LevelSetMeasure.h:105
openvdb::v7_0::tools::LevelSetMeasure::eulerCharacteristic
int eulerCharacteristic()
Compute the Euler characteristic of the level set surface.
Definition: LevelSetMeasure.h:320
openvdb::v7_0::math::Pow3
Type Pow3(Type x)
Return x3.
Definition: Math.h:499
openvdb::v7_0::tools::levelSetArea
Real levelSetArea(const GridT &grid, bool useWorldUnits)
Definition: LevelSetMeasure.h:429
openvdb::v7_0::tools::LevelSetMeasure::totGaussianCurvature
Real totGaussianCurvature(bool useWorldUnits=true)
Compute the total gaussian curvature of the level set surface.
Definition: LevelSetMeasure.h:312
Grid.h
openvdb::v7_0::Real
double Real
Definition: Types.h:37
ValueAccessor.h
openvdb::v7_0::math::Pow2
Type Pow2(Type x)
Return x2.
Definition: Math.h:495
OPENVDB_DEPRECATED
#define OPENVDB_DEPRECATED
Definition: Platform.h:42
openvdb::v7_0::math::Abs
Coord Abs(const Coord &xyz)
Definition: Coord.h:515
openvdb::v7_0::tools::levelSetEulerCharacteristic
int levelSetEulerCharacteristic(const GridType &grid)
Return the Euler Characteristics of a narrow-band level set surface (possibly disconnected).
FiniteDifference.h
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
openvdb::v7_0::tools::LevelSetMeasure::init
void init(const GridType &grid)
Re-initialize using the specified grid.
Definition: LevelSetMeasure.h:260
openvdb::v7_0::tools::levelSetVolume
Real levelSetVolume(const GridT &grid, bool useWorldUnits)
Definition: LevelSetMeasure.h:462
openvdb::v7_0::TypeError
Definition: Exceptions.h:64
openvdb::v7_0::tree::LeafManager
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:82
openvdb::v7_0::tools::LevelSetMeasure::setGrainSize
void setGrainSize(int grainsize)
Set the grain-size used for multi-threading.
Definition: LevelSetMeasure.h:130
openvdb::v7_0::math::Vec3
Definition: Mat.h:170
NullInterrupter.h
openvdb::v7_0::tools::DiracDelta::DiracDelta
DiracDelta(RealT eps)
Definition: LevelSetMeasure.h:84
openvdb::v7_0::tools::levelSetGenus
int levelSetGenus(const GridType &grid)
Return the genus of a narrow-band level set surface.
openvdb::v7_0::RuntimeError
Definition: Exceptions.h:63
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
openvdb::v7_0::tools::LevelSetMeasure::getGrainSize
int getGrainSize() const
Definition: LevelSetMeasure.h:126
LeafManager.h
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
openvdb::v7_0::tools::levelSetArea
Real levelSetArea(const GridType &grid, bool useWorldSpace=true)
Return the surface area of a narrow-band level set.
openvdb::v7_0::tools::LevelSetMeasure::~LevelSetMeasure
virtual ~LevelSetMeasure()
Destructor.
Definition: LevelSetMeasure.h:123
openvdb::v7_0::tools::DiracDelta::operator()
RealT operator()(RealT phi) const
Definition: LevelSetMeasure.h:86
Stencils.h
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
openvdb::v7_0::tools::LevelSetMeasure
Multi-threaded computation of surface area, volume and average mean-curvature for narrow band level s...
Definition: LevelSetMeasure.h:100
openvdb::v7_0::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
openvdb::v7_0::GRID_LEVEL_SET
Definition: Types.h:454
openvdb
Definition: Exceptions.h:13
openvdb::v7_0::tools::levelSetEulerCharacteristic
int levelSetEulerCharacteristic(const GridT &grid)
Definition: LevelSetMeasure.h:496
Operators.h
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
openvdb::v7_0::tools::LevelSetMeasure::area
Real area(bool useWorldUnits=true)
Compute the surface area of the level set.
Definition: LevelSetMeasure.h:284