Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | // | ||
4 | /// @author Ken Museth | ||
5 | /// | ||
6 | /// @file tools/PointScatter.h | ||
7 | /// | ||
8 | /// @brief We offer three different algorithms (each in its own class) | ||
9 | /// for scattering of points in active voxels: | ||
10 | /// | ||
11 | /// 1) UniformPointScatter. Has two modes: Either randomly distributes | ||
12 | /// a fixed number of points into the active voxels, or the user can | ||
13 | /// specify a fixed probability of having a points per unit of volume. | ||
14 | /// | ||
15 | /// 2) DenseUniformPointScatter. Randomly distributes points into active | ||
16 | /// voxels using a fixed number of points per voxel. | ||
17 | /// | ||
18 | /// 3) NonIniformPointScatter. Define the local probability of having | ||
19 | /// a point in a voxel as the product of a global density and the | ||
20 | /// value of the voxel itself. | ||
21 | |||
22 | #ifndef OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED | ||
23 | #define OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED | ||
24 | |||
25 | #include <openvdb/Types.h> | ||
26 | #include <openvdb/Grid.h> | ||
27 | #include <openvdb/math/Math.h> | ||
28 | #include <openvdb/util/NullInterrupter.h> | ||
29 | #include <tbb/parallel_sort.h> | ||
30 | #include <tbb/parallel_for.h> | ||
31 | #include <iostream> | ||
32 | #include <memory> | ||
33 | #include <string> | ||
34 | |||
35 | namespace openvdb { | ||
36 | OPENVDB_USE_VERSION_NAMESPACE | ||
37 | namespace OPENVDB_VERSION_NAME { | ||
38 | namespace tools { | ||
39 | |||
40 | /// Forward declaration of base class | ||
41 | template<typename PointAccessorType, | ||
42 | typename RandomGenerator, | ||
43 | typename InterruptType = util::NullInterrupter> | ||
44 | class BasePointScatter; | ||
45 | |||
46 | /// @brief The two point scatters UniformPointScatter and | ||
47 | /// NonUniformPointScatter depend on the following two classes: | ||
48 | /// | ||
49 | /// The @c PointAccessorType template argument below refers to any class | ||
50 | /// with the following interface: | ||
51 | /// @code | ||
52 | /// class PointAccessor { | ||
53 | /// ... | ||
54 | /// public: | ||
55 | /// void add(const openvdb::Vec3R &pos);// appends point with world positions pos | ||
56 | /// }; | ||
57 | /// @endcode | ||
58 | /// | ||
59 | /// | ||
60 | /// The @c InterruptType template argument below refers to any class | ||
61 | /// with the following interface: | ||
62 | /// @code | ||
63 | /// class Interrupter { | ||
64 | /// ... | ||
65 | /// public: | ||
66 | /// void start(const char* name = nullptr) // called when computations begin | ||
67 | /// void end() // called when computations end | ||
68 | /// bool wasInterrupted(int percent=-1) // return true to break computation | ||
69 | ///}; | ||
70 | /// @endcode | ||
71 | /// | ||
72 | /// @note If no template argument is provided for this InterruptType | ||
73 | /// the util::NullInterrupter is used which implies that all | ||
74 | /// interrupter calls are no-ops (i.e. incurs no computational overhead). | ||
75 | |||
76 | |||
77 | /// @brief Uniformly scatters points in the active voxels. | ||
78 | /// The point count is either explicitly defined or implicitly | ||
79 | /// through the specification of a global density (=points-per-volume) | ||
80 | /// | ||
81 | /// @note This uniform scattering technique assumes that the number of | ||
82 | /// points is generally smaller than the number of active voxels | ||
83 | /// (including virtual active voxels in active tiles). | ||
84 | template<typename PointAccessorType, | ||
85 | typename RandomGenerator, | ||
86 | typename InterruptType = util::NullInterrupter> | ||
87 | class UniformPointScatter : public BasePointScatter<PointAccessorType, | ||
88 | RandomGenerator, | ||
89 | InterruptType> | ||
90 | { | ||
91 | public: | ||
92 | using BaseT = BasePointScatter<PointAccessorType, RandomGenerator, InterruptType>; | ||
93 | |||
94 | 11 | UniformPointScatter(PointAccessorType& points, | |
95 | Index64 pointCount, | ||
96 | RandomGenerator& randGen, | ||
97 | double spread = 1.0, | ||
98 | InterruptType* interrupt = nullptr) | ||
99 | : BaseT(points, randGen, spread, interrupt) | ||
100 | , mTargetPointCount(pointCount) | ||
101 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
11 | , mPointsPerVolume(0.0f) |
102 | { | ||
103 | } | ||
104 | 1 | UniformPointScatter(PointAccessorType& points, | |
105 | float pointsPerVolume, | ||
106 | RandomGenerator& randGen, | ||
107 | double spread = 1.0, | ||
108 | InterruptType* interrupt = nullptr) | ||
109 | : BaseT(points, randGen, spread, interrupt) | ||
110 | , mTargetPointCount(0) | ||
111 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | , mPointsPerVolume(pointsPerVolume) |
112 | { | ||
113 | } | ||
114 | |||
115 | /// This is the main functor method implementing the actual scattering of points. | ||
116 | template<typename GridT> | ||
117 | 12 | bool operator()(const GridT& grid) | |
118 | { | ||
119 | 12 | mVoxelCount = grid.activeVoxelCount(); | |
120 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
|
12 | if (mVoxelCount == 0) return false; |
121 | |||
122 | const auto voxelVolume = grid.transform().voxelVolume(); | ||
123 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (mPointsPerVolume > 0) { |
124 | BaseT::start("Uniform scattering with fixed point density"); | ||
125 | 1 | mTargetPointCount = Index64(mPointsPerVolume * voxelVolume * double(mVoxelCount)); | |
126 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | } else if (mTargetPointCount > 0) { |
127 | BaseT::start("Uniform scattering with fixed point count"); | ||
128 | 10 | mPointsPerVolume = float(mTargetPointCount) / float(voxelVolume * double(mVoxelCount)); | |
129 | } else { | ||
130 | return false; | ||
131 | } | ||
132 | |||
133 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | std::unique_ptr<Index64[]> idList{new Index64[mTargetPointCount]}; |
134 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
22 | math::RandInt<Index64, RandomGenerator> rand(BaseT::mRand01.engine(), 0, mVoxelCount-1); |
135 |
2/2✓ Branch 0 taken 328144 times.
✓ Branch 1 taken 11 times.
|
328155 | for (Index64 i=0; i<mTargetPointCount; ++i) idList[i] = rand(); |
136 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | tbb::parallel_sort(idList.get(), idList.get() + mTargetPointCount); |
137 | |||
138 | 11 | CoordBBox bbox; | |
139 | const Vec3R offset(0.5, 0.5, 0.5); | ||
140 | typename GridT::ValueOnCIter valueIter = grid.cbeginValueOn(); | ||
141 | |||
142 |
2/2✓ Branch 0 taken 328144 times.
✓ Branch 1 taken 11 times.
|
328155 | for (Index64 i=0, n=valueIter.getVoxelCount() ; i != mTargetPointCount; ++i) { |
143 |
2/4✓ Branch 1 taken 328144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 328144 times.
✗ Branch 4 not taken.
|
328144 | if (BaseT::interrupt()) return false; |
144 | 328144 | const Index64 voxelId = idList[i]; | |
145 |
2/2✓ Branch 0 taken 650138 times.
✓ Branch 1 taken 328144 times.
|
978282 | while ( n <= voxelId ) { |
146 | ++valueIter; | ||
147 | 650138 | n += valueIter.getVoxelCount(); | |
148 | } | ||
149 | if (valueIter.isVoxelValue()) {// a majority is expected to be voxels | ||
150 |
1/2✓ Branch 1 taken 321052 times.
✗ Branch 2 not taken.
|
321052 | BaseT::addPoint(grid, valueIter.getCoord() - offset); |
151 | } else {// tiles contain multiple (virtual) voxels | ||
152 |
1/2✓ Branch 1 taken 7092 times.
✗ Branch 2 not taken.
|
7092 | valueIter.getBoundingBox(bbox); |
153 |
1/4✓ Branch 1 taken 7092 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7092 | BaseT::addPoint(grid, bbox.min() - offset, bbox.extents()); |
154 | } | ||
155 | }//loop over all the active voxels and tiles | ||
156 | //} | ||
157 | |||
158 | BaseT::end(); | ||
159 | return true; | ||
160 | } | ||
161 | |||
162 | // The following methods should only be called after the | ||
163 | // the operator() method was called | ||
164 | void print(const std::string &name, std::ostream& os = std::cout) const | ||
165 | { | ||
166 | os << "Uniformly scattered " << mPointCount << " points into " << mVoxelCount | ||
167 | << " active voxels in \"" << name << "\" corresponding to " | ||
168 | << mPointsPerVolume << " points per volume." << std::endl; | ||
169 | } | ||
170 | |||
171 | float getPointsPerVolume() const { return mPointsPerVolume; } | ||
172 | Index64 getTargetPointCount() const { return mTargetPointCount; } | ||
173 | |||
174 | private: | ||
175 | |||
176 | using BaseT::mPointCount; | ||
177 | using BaseT::mVoxelCount; | ||
178 | Index64 mTargetPointCount; | ||
179 | float mPointsPerVolume; | ||
180 | |||
181 | }; // class UniformPointScatter | ||
182 | |||
183 | /// @brief Scatters a fixed (and integer) number of points in all | ||
184 | /// active voxels and tiles. | ||
185 | template<typename PointAccessorType, | ||
186 | typename RandomGenerator, | ||
187 | typename InterruptType = util::NullInterrupter> | ||
188 | class DenseUniformPointScatter : public BasePointScatter<PointAccessorType, | ||
189 | RandomGenerator, | ||
190 | InterruptType> | ||
191 | { | ||
192 | public: | ||
193 | using BaseT = BasePointScatter<PointAccessorType, RandomGenerator, InterruptType>; | ||
194 | |||
195 | 1 | DenseUniformPointScatter(PointAccessorType& points, | |
196 | float pointsPerVoxel, | ||
197 | RandomGenerator& randGen, | ||
198 | double spread = 1.0, | ||
199 | InterruptType* interrupt = nullptr) | ||
200 | : BaseT(points, randGen, spread, interrupt) | ||
201 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | , mPointsPerVoxel(pointsPerVoxel) |
202 | { | ||
203 | } | ||
204 | |||
205 | /// This is the main functor method implementing the actual scattering of points. | ||
206 | template<typename GridT> | ||
207 | 1 | bool operator()(const GridT& grid) | |
208 | { | ||
209 | using ValueIter = typename GridT::ValueOnCIter; | ||
210 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (mPointsPerVoxel < 1.0e-6) return false; |
211 | 1 | mVoxelCount = grid.activeVoxelCount(); | |
212 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (mVoxelCount == 0) return false; |
213 | BaseT::start("Dense uniform scattering with fixed point count"); | ||
214 | 1 | CoordBBox bbox; | |
215 | const Vec3R offset(0.5, 0.5, 0.5); | ||
216 | |||
217 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | const int ppv = math::Floor(mPointsPerVoxel); |
218 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | const double delta = mPointsPerVoxel - float(ppv); |
219 | const bool fractional = !math::isApproxZero(delta, 1.0e-6); | ||
220 | |||
221 |
2/2✓ Branch 0 taken 262144 times.
✓ Branch 1 taken 1 times.
|
262145 | for (ValueIter iter = grid.cbeginValueOn(); iter; ++iter) { |
222 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 262144 times.
|
262144 | if (BaseT::interrupt()) return false; |
223 | if (iter.isVoxelValue()) {// a majority is expected to be voxels | ||
224 | 262144 | const Vec3R dmin = iter.getCoord() - offset; | |
225 |
2/2✓ Branch 0 taken 2097152 times.
✓ Branch 1 taken 262144 times.
|
2359296 | for (int n = 0; n != ppv; ++n) BaseT::addPoint(grid, dmin); |
226 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 262144 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
262144 | if (fractional && BaseT::getRand01() < delta) BaseT::addPoint(grid, dmin); |
227 | } else {// tiles contain multiple (virtual) voxels | ||
228 | ✗ | iter.getBoundingBox(bbox); | |
229 | ✗ | const Coord size(bbox.extents()); | |
230 | const Vec3R dmin = bbox.min() - offset; | ||
231 | ✗ | const double d = mPointsPerVoxel * float(iter.getVoxelCount()); | |
232 | const int m = math::Floor(d); | ||
233 | ✗ | for (int n = 0; n != m; ++n) BaseT::addPoint(grid, dmin, size); | |
234 | ✗ | if (BaseT::getRand01() < d - m) BaseT::addPoint(grid, dmin, size); | |
235 | } | ||
236 | }//loop over all the active voxels and tiles | ||
237 | //} | ||
238 | BaseT::end(); | ||
239 | return true; | ||
240 | } | ||
241 | |||
242 | // The following methods should only be called after the | ||
243 | // the operator() method was called | ||
244 | void print(const std::string &name, std::ostream& os = std::cout) const | ||
245 | { | ||
246 | os << "Dense uniformly scattered " << mPointCount << " points into " << mVoxelCount | ||
247 | << " active voxels in \"" << name << "\" corresponding to " | ||
248 | << mPointsPerVoxel << " points per voxel." << std::endl; | ||
249 | } | ||
250 | |||
251 | float getPointsPerVoxel() const { return mPointsPerVoxel; } | ||
252 | |||
253 | private: | ||
254 | using BaseT::mPointCount; | ||
255 | using BaseT::mVoxelCount; | ||
256 | float mPointsPerVoxel; | ||
257 | }; // class DenseUniformPointScatter | ||
258 | |||
259 | /// @brief Non-uniform scatters of point in the active voxels. | ||
260 | /// The local point count is implicitly defined as a product of | ||
261 | /// of a global density (called pointsPerVolume) and the local voxel | ||
262 | /// (or tile) value. | ||
263 | /// | ||
264 | /// @note This scattering technique can be significantly slower | ||
265 | /// than a uniform scattering since its computational complexity | ||
266 | /// is proportional to the active voxel (and tile) count. | ||
267 | template<typename PointAccessorType, | ||
268 | typename RandomGenerator, | ||
269 | typename InterruptType = util::NullInterrupter> | ||
270 | class NonUniformPointScatter : public BasePointScatter<PointAccessorType, | ||
271 | RandomGenerator, | ||
272 | InterruptType> | ||
273 | { | ||
274 | public: | ||
275 | using BaseT = BasePointScatter<PointAccessorType, RandomGenerator, InterruptType>; | ||
276 | |||
277 | 1 | NonUniformPointScatter(PointAccessorType& points, | |
278 | float pointsPerVolume, | ||
279 | RandomGenerator& randGen, | ||
280 | double spread = 1.0, | ||
281 | InterruptType* interrupt = nullptr) | ||
282 | : BaseT(points, randGen, spread, interrupt) | ||
283 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | , mPointsPerVolume(pointsPerVolume)//note this is merely a |
284 | //multiplier for the local point density | ||
285 | { | ||
286 | } | ||
287 | |||
288 | /// This is the main functor method implementing the actual scattering of points. | ||
289 | template<typename GridT> | ||
290 | 1 | bool operator()(const GridT& grid) | |
291 | { | ||
292 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (mPointsPerVolume <= 0.0f) return false; |
293 | 1 | mVoxelCount = grid.activeVoxelCount(); | |
294 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (mVoxelCount == 0) return false; |
295 | BaseT::start("Non-uniform scattering with local point density"); | ||
296 | const Vec3d dim = grid.voxelSize(); | ||
297 | 1 | const double volumePerVoxel = dim[0]*dim[1]*dim[2], | |
298 | 1 | pointsPerVoxel = mPointsPerVolume * volumePerVoxel; | |
299 | 1 | CoordBBox bbox; | |
300 | const Vec3R offset(0.5, 0.5, 0.5); | ||
301 |
2/2✓ Branch 0 taken 262144 times.
✓ Branch 1 taken 1 times.
|
262145 | for (typename GridT::ValueOnCIter iter = grid.cbeginValueOn(); iter; ++iter) { |
302 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 262144 times.
|
262144 | if (BaseT::interrupt()) return false; |
303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 262144 times.
|
262144 | const double d = double(*iter) * pointsPerVoxel * double(iter.getVoxelCount()); |
304 |
1/2✓ Branch 0 taken 262144 times.
✗ Branch 1 not taken.
|
262144 | const int n = int(d); |
305 | if (iter.isVoxelValue()) { // a majority is expected to be voxels | ||
306 | 262144 | const Vec3R dmin =iter.getCoord() - offset; | |
307 |
2/2✓ Branch 0 taken 441252 times.
✓ Branch 1 taken 262144 times.
|
703396 | for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin); |
308 |
2/2✓ Branch 0 taken 5278 times.
✓ Branch 1 taken 256866 times.
|
262144 | if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin); |
309 | } else { // tiles contain multiple (virtual) voxels | ||
310 | ✗ | iter.getBoundingBox(bbox); | |
311 | ✗ | const Coord size(bbox.extents()); | |
312 | const Vec3R dmin = bbox.min() - offset; | ||
313 | ✗ | for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin, size); | |
314 | ✗ | if (BaseT::getRand01() < (d - n)) BaseT::addPoint(grid, dmin, size); | |
315 | } | ||
316 | }//loop over all the active voxels and tiles | ||
317 | BaseT::end(); | ||
318 | return true; | ||
319 | } | ||
320 | |||
321 | // The following methods should only be called after the | ||
322 | // the operator() method was called | ||
323 | void print(const std::string &name, std::ostream& os = std::cout) const | ||
324 | { | ||
325 | os << "Non-uniformly scattered " << mPointCount << " points into " << mVoxelCount | ||
326 | << " active voxels in \"" << name << "\"." << std::endl; | ||
327 | } | ||
328 | |||
329 | float getPointPerVolume() const { return mPointsPerVolume; } | ||
330 | |||
331 | private: | ||
332 | using BaseT::mPointCount; | ||
333 | using BaseT::mVoxelCount; | ||
334 | float mPointsPerVolume; | ||
335 | |||
336 | }; // class NonUniformPointScatter | ||
337 | |||
338 | /// Base class of all the point scattering classes defined above | ||
339 | template<typename PointAccessorType, | ||
340 | typename RandomGenerator, | ||
341 | typename InterruptType> | ||
342 | class BasePointScatter | ||
343 | { | ||
344 | public: | ||
345 | |||
346 |
5/10✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
5 | Index64 getPointCount() const { return mPointCount; } |
347 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
|
4 | Index64 getVoxelCount() const { return mVoxelCount; } |
348 | |||
349 | protected: | ||
350 | |||
351 | PointAccessorType& mPoints; | ||
352 | InterruptType* mInterrupter; | ||
353 | Index64 mPointCount; | ||
354 | Index64 mVoxelCount; | ||
355 | Index64 mInterruptCount; | ||
356 | const double mSpread; | ||
357 | math::Rand01<double, RandomGenerator> mRand01; | ||
358 | |||
359 | /// This is a base class so the constructor is protected | ||
360 | 14 | BasePointScatter(PointAccessorType& points, | |
361 | RandomGenerator& randGen, | ||
362 | double spread, | ||
363 | InterruptType* interrupt = nullptr) | ||
364 | : mPoints(points) | ||
365 | , mInterrupter(interrupt) | ||
366 | , mPointCount(0) | ||
367 | , mVoxelCount(0) | ||
368 | , mInterruptCount(0) | ||
369 | , mSpread(math::Clamp01(spread)) | ||
370 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
14 | , mRand01(randGen) |
371 | { | ||
372 | } | ||
373 | |||
374 | inline void start(const char* name) | ||
375 | { | ||
376 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
|
13 | if (mInterrupter) mInterrupter->start(name); |
377 | } | ||
378 | |||
379 | inline void end() | ||
380 | { | ||
381 |
3/8✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
13 | if (mInterrupter) mInterrupter->end(); |
382 | } | ||
383 | |||
384 | 852432 | inline bool interrupt() | |
385 | { | ||
386 | //only check interrupter for every 32'th call | ||
387 |
3/4✓ Branch 0 taken 26645 times.
✓ Branch 1 taken 825787 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26645 times.
|
852432 | return !(mInterruptCount++ & ((1<<5)-1)) && util::wasInterrupted(mInterrupter); |
388 | } | ||
389 | |||
390 | /// @brief Return a random floating point number between zero and one | ||
391 | inline double getRand01() { return mRand01(); } | ||
392 | |||
393 | /// @brief Return a random floating point number between 0.5 -+ mSpread/2 | ||
394 | 8615478 | inline double getRand() { return 0.5 + mSpread * (mRand01() - 0.5); } | |
395 | |||
396 | template <typename GridT> | ||
397 | 2864734 | inline void addPoint(const GridT &grid, const Vec3R &dmin) | |
398 | { | ||
399 | 2864734 | const Vec3R pos(dmin[0] + this->getRand(), | |
400 | 2864734 | dmin[1] + this->getRand(), | |
401 | 2864734 | dmin[2] + this->getRand()); | |
402 | 2864734 | mPoints.add(grid.indexToWorld(pos)); | |
403 | 2864734 | ++mPointCount; | |
404 | 2864734 | } | |
405 | |||
406 | template <typename GridT> | ||
407 | 7092 | inline void addPoint(const GridT &grid, const Vec3R &dmin, const Coord &size) | |
408 | { | ||
409 | 7092 | const Vec3R pos(dmin[0] + size[0]*this->getRand(), | |
410 | 7092 | dmin[1] + size[1]*this->getRand(), | |
411 | 7092 | dmin[2] + size[2]*this->getRand()); | |
412 | 7092 | mPoints.add(grid.indexToWorld(pos)); | |
413 | 7092 | ++mPointCount; | |
414 | 7092 | } | |
415 | };// class BasePointScatter | ||
416 | |||
417 | } // namespace tools | ||
418 | } // namespace OPENVDB_VERSION_NAME | ||
419 | } // namespace openvdb | ||
420 | |||
421 | #endif // OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED | ||
422 |