OpenVDB 9.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//
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
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
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
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
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
374LevelSetMeasure<GridT, InterruptT>::
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
412doLevelSetArea(const GridT& grid, bool useWorldUnits)
413{
414 LevelSetMeasure<GridT> m(grid);
415 return m.area(useWorldUnits);
416}
417
418template<class GridT>
419inline
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
445doLevelSetVolume(const GridT& grid, bool useWorldUnits)
446{
447 LevelSetMeasure<GridT> m(grid);
448 return m.volume(useWorldUnits);
449}
450
451template<class GridT>
452inline
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
478doLevelSetEulerCharacteristic(const GridT& grid)
479{
480 LevelSetMeasure<GridT> m(grid);
481 return m.eulerCharacteristic();
482}
483
484template<class GridT>
485inline
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
512doLevelSetEuler(const GridT& grid)
513{
514 LevelSetMeasure<GridT> m(grid);
515 return m.eulerCharacteristics();
516
517}
518
519template<class GridT>
520inline
522doLevelSetGenus(const GridT& grid)
523{
524 LevelSetMeasure<GridT> m(grid);
525 return m.genus();
526}
527
528template<class GridT>
529inline
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
#define OPENVDB_INSTANTIATE_CLASS
Definition: ExplicitInstantiation.h:12
ValueT value
Definition: GridBuilder.h:1287
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...
Definition: Exceptions.h:63
Definition: Exceptions.h:64
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
Definition: Vec3.h:24
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
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:85
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
T reduce(RangeT range, const T &identity, const FuncT &func, const JoinT &join)
Definition: Reduce.h:41
T Abs(T x)
Definition: NanoVDB.h:747
float Round(float x)
Return x rounded to the nearest integer.
Definition: Math.h:822
constexpr T pi()
Pi constant taken from Boost to match old behaviour.
Definition: Math.h:118
Type Pow2(Type x)
Return x2.
Definition: Math.h:551
Type Pow3(Type x)
Return x3.
Definition: Math.h:555
int levelSetEulerCharacteristic(const GridType &grid)
Return the Euler Characteristics of a narrow-band level set surface (possibly disconnected).
int levelSetGenus(const GridType &grid)
Return the genus of a narrow-band level set surface.
Real levelSetVolume(const GridT &grid, bool useWorldUnits)
Definition: LevelSetMeasure.h:465
Real levelSetVolume(const GridType &grid, bool useWorldSpace=true)
Return the volume of a narrow-band level set surface.
int levelSetEulerCharacteristic(const GridT &grid)
Definition: LevelSetMeasure.h:499
int levelSetGenus(const GridT &grid)
Definition: LevelSetMeasure.h:542
Real levelSetArea(const GridType &grid, bool useWorldSpace=true)
Return the surface area of a narrow-band level set.
Real levelSetArea(const GridT &grid, bool useWorldUnits)
Definition: LevelSetMeasure.h:432
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
double Real
Definition: Types.h:60
@ GRID_LEVEL_SET
Definition: Types.h:337
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:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147