14 #ifndef OPENVDB_POINTS_POINT_SCATTER_HAS_BEEN_INCLUDED
15 #define OPENVDB_POINTS_POINT_SCATTER_HAS_BEEN_INCLUDED
17 #include <type_traits>
32 #include <tbb/parallel_sort.h>
33 #include <tbb/parallel_for.h>
73 typename RandGenT = std::mt19937,
74 typename PositionArrayT = TypedAttributeArray<Vec3f, NullCodec>,
75 typename PointDataGridT =
Grid<
76 typename points::TreeConverter<typename GridT::TreeType>::Type>,
77 typename InterrupterT = util::NullInterrupter>
78 inline typename PointDataGridT::Ptr
81 const unsigned int seed = 0,
82 const float spread = 1.0f,
83 InterrupterT* interrupter =
nullptr);
102 typename RandGenT = std::mt19937,
103 typename PositionArrayT = TypedAttributeArray<Vec3f, NullCodec>,
104 typename PointDataGridT =
Grid<
105 typename points::TreeConverter<typename GridT::TreeType>::Type>,
106 typename InterrupterT = util::NullInterrupter>
107 inline typename PointDataGridT::Ptr
109 const float pointsPerVoxel,
110 const unsigned int seed = 0,
111 const float spread = 1.0f,
112 InterrupterT* interrupter =
nullptr);
134 typename RandGenT = std::mt19937,
135 typename PositionArrayT = TypedAttributeArray<Vec3f, NullCodec>,
136 typename PointDataGridT =
Grid<
137 typename points::TreeConverter<typename GridT::TreeType>::Type>,
138 typename InterrupterT = util::NullInterrupter>
139 inline typename PointDataGridT::Ptr
141 const float pointsPerVoxel,
142 const unsigned int seed = 0,
143 const float spread = 1.0f,
144 InterrupterT* interrupter =
nullptr);
150 namespace point_scatter_internal
156 template<
typename Po
intDataGr
idT,
typename Gr
idT>
157 inline typename PointDataGridT::Ptr
160 typename PointDataGridT::Ptr points(
new PointDataGridT);
161 points->setTransform(grid.transform().copy());
162 points->topologyUnion(grid);
163 if (points->tree().hasActiveTiles()) {
164 points->tree().voxelizeActiveTiles();
177 template<
typename PositionType,
183 const AttributeSet::Descriptor::Ptr& descriptor,
189 using ValueType =
typename PositionTraits::ElementType;
192 leaf.initializeAttributes(descriptor,
static_cast<Index>(count));
196 auto& array = leaf.attributeArray(0);
199 PositionWriteHandle pHandle(array,
false);
201 for (
Index64 index = 0; index < count; ++index) {
202 P[0] = (spread * (rand01() - ValueType(0.5)));
203 P[1] = (spread * (rand01() - ValueType(0.5)));
204 P[2] = (spread * (rand01() - ValueType(0.5)));
205 pHandle.set(
static_cast<Index>(index), P);
218 typename PositionArrayT,
219 typename PointDataGridT,
220 typename InterrupterT>
221 inline typename PointDataGridT::Ptr
224 const unsigned int seed,
226 InterrupterT* interrupter)
228 using PositionType =
typename PositionArrayT::ValueType;
230 using ValueType =
typename PositionTraits::ElementType;
231 using CodecType =
typename PositionArrayT::Codec;
235 using TreeType =
typename PointDataGridT::TreeType;
236 using LeafNodeType =
typename TreeType::LeafNodeType;
244 static void getPrefixSum(LeafManagerT& leafManager,
245 std::vector<Index64>& offsets)
248 offsets.reserve(leafManager.leafCount() + 1);
249 offsets.push_back(0);
250 const auto leafRange = leafManager.
leafRange();
251 for (
auto leaf = leafRange.begin(); leaf; ++leaf) {
252 offset += leaf->onVoxelCount();
253 offsets.push_back(offset);
258 static_assert(PositionTraits::IsVec && PositionTraits::Size == 3,
259 "Invalid Position Array type.");
261 if (spread < 0.0f || spread > 1.0f) {
265 if (interrupter) interrupter->start(
"Uniform scattering with fixed point count");
267 typename PointDataGridT::Ptr points =
268 point_scatter_internal::initialisePointTopology<PointDataGridT>(grid);
269 TreeType& tree = points->tree();
270 if (!tree.cbeginLeaf())
return points;
272 LeafManagerT leafManager(tree);
273 const Index64 voxelCount = leafManager.activeLeafVoxelCount();
274 assert(voxelCount != 0);
276 const double pointsPerVolume = double(count) / double(voxelCount);
278 const Index64 remainder = count - (pointsPerVoxel * voxelCount);
280 if (remainder == 0) {
282 GridT, RandGenT, PositionArrayT, PointDataGridT, InterrupterT>(
283 grid, float(pointsPerVoxel), seed, spread, interrupter);
286 std::vector<Index64> voxelOffsets, values;
287 std::thread worker(&Local::getPrefixSum, std::ref(leafManager), std::ref(voxelOffsets));
291 values.reserve(remainder);
292 for (
Index64 i = 0; i < remainder; ++i) values.emplace_back(gen());
297 if (util::wasInterrupted<InterrupterT>(interrupter)) {
302 tbb::parallel_sort(values.begin(), values.end());
303 const bool fractionalOnly(pointsPerVoxel == 0);
305 leafManager.foreach([&voxelOffsets, &values, fractionalOnly]
306 (LeafNodeType& leaf,
const size_t idx)
308 const Index64 lowerOffset = voxelOffsets[idx];
309 const Index64 upperOffset = voxelOffsets[idx + 1];
310 assert(upperOffset > lowerOffset);
312 const auto valuesEnd = values.end();
313 auto lower = std::lower_bound(values.begin(), valuesEnd, lowerOffset);
315 auto*
const data = leaf.buffer().data();
316 auto iter = leaf.beginValueOn();
319 bool addedPoints(!fractionalOnly);
320 while (lower != valuesEnd) {
322 if (vId >= upperOffset)
break;
325 iter.increment(nextOffset - currentOffset);
326 currentOffset = nextOffset;
329 auto& value = data[iter.pos()];
337 if (!addedPoints) leaf.setValuesOff();
340 voxelOffsets.clear();
343 if (fractionalOnly) {
345 leafManager.rebuild();
348 const AttributeSet::Descriptor::Ptr descriptor =
349 AttributeSet::Descriptor::create(PositionArrayT::attributeType());
350 RandomGenerator rand01(seed);
352 const auto leafRange = leafManager.leafRange();
353 auto leaf = leafRange.begin();
354 for (; leaf; ++leaf) {
355 if (util::wasInterrupted<InterrupterT>(interrupter))
break;
357 for (
auto iter = leaf->beginValueAll(); iter; ++iter) {
358 if (iter.isValueOn()) {
360 if (value == 0) leaf->setValueOff(iter.pos());
361 else offset += value;
364 leaf->setOffsetOnly(iter.pos(), offset);
369 point_scatter_internal::generatePositions<PositionType, CodecType>
370 (*leaf, descriptor, offset, spread, rand01);
375 for (; leaf; ++leaf) leaf->setValuesOff();
379 if (interrupter) interrupter->end();
390 typename PositionArrayT,
391 typename PointDataGridT,
392 typename InterrupterT>
393 inline typename PointDataGridT::Ptr
395 const float pointsPerVoxel,
396 const unsigned int seed,
398 InterrupterT* interrupter)
400 using PositionType =
typename PositionArrayT::ValueType;
402 using ValueType =
typename PositionTraits::ElementType;
403 using CodecType =
typename PositionArrayT::Codec;
407 using TreeType =
typename PointDataGridT::TreeType;
409 static_assert(PositionTraits::IsVec && PositionTraits::Size == 3,
410 "Invalid Position Array type.");
412 if (pointsPerVoxel < 0.0f) {
416 if (spread < 0.0f || spread > 1.0f) {
420 if (interrupter) interrupter->start(
"Dense uniform scattering with fixed point count");
422 typename PointDataGridT::Ptr points =
423 point_scatter_internal::initialisePointTopology<PointDataGridT>(grid);
424 TreeType& tree = points->tree();
425 auto leafIter = tree.beginLeaf();
426 if (!leafIter)
return points;
429 const double delta = pointsPerVoxel - float(pointsPerVoxelInt);
431 const bool fractionalOnly = pointsPerVoxelInt == 0;
433 const AttributeSet::Descriptor::Ptr descriptor =
434 AttributeSet::Descriptor::create(PositionArrayT::attributeType());
435 RandomGenerator rand01(seed);
437 for (; leafIter; ++leafIter) {
438 if (util::wasInterrupted<InterrupterT>(interrupter))
break;
440 for (
auto iter = leafIter->beginValueAll(); iter; ++iter) {
441 if (iter.isValueOn()) {
442 offset += pointsPerVoxelInt;
443 if (fractional && rand01() < delta) ++offset;
444 else if (fractionalOnly) leafIter->setValueOff(iter.pos());
447 leafIter->setOffsetOnly(iter.pos(), offset);
451 point_scatter_internal::generatePositions<PositionType, CodecType>
452 (*leafIter, descriptor, offset, spread, rand01);
457 const bool prune(leafIter || fractionalOnly);
458 for (; leafIter; ++leafIter) leafIter->setValuesOff();
461 if (interrupter) interrupter->end();
472 typename PositionArrayT,
473 typename PointDataGridT,
474 typename InterrupterT>
475 inline typename PointDataGridT::Ptr
477 const float pointsPerVoxel,
478 const unsigned int seed,
480 InterrupterT* interrupter)
482 using PositionType =
typename PositionArrayT::ValueType;
484 using ValueType =
typename PositionTraits::ElementType;
485 using CodecType =
typename PositionArrayT::Codec;
489 using TreeType =
typename PointDataGridT::TreeType;
491 static_assert(PositionTraits::IsVec && PositionTraits::Size == 3,
492 "Invalid Position Array type.");
493 static_assert(std::is_arithmetic<typename GridT::ValueType>::value,
494 "Scalar grid type required for weighted voxel scattering.");
496 if (pointsPerVoxel < 0.0f) {
500 if (spread < 0.0f || spread > 1.0f) {
504 if (interrupter) interrupter->start(
"Non-uniform scattering with local point density");
506 typename PointDataGridT::Ptr points =
507 point_scatter_internal::initialisePointTopology<PointDataGridT>(grid);
508 TreeType& tree = points->tree();
509 auto leafIter = tree.beginLeaf();
510 if (!leafIter)
return points;
512 const AttributeSet::Descriptor::Ptr descriptor =
513 AttributeSet::Descriptor::create(PositionArrayT::attributeType());
514 RandomGenerator rand01(seed);
515 const auto accessor = grid.getConstAccessor();
517 for (; leafIter; ++leafIter) {
518 if (util::wasInterrupted<InterrupterT>(interrupter))
break;
520 for (
auto iter = leafIter->beginValueAll(); iter; ++iter) {
521 if (iter.isValueOn()) {
523 double(accessor.getValue(iter.getCoord())) * pointsPerVoxel;
524 fractional =
std::max(0.0, fractional);
525 int count = int(fractional);
526 if (rand01() < (fractional -
double(count))) ++count;
527 else if (count == 0) leafIter->setValueOff(iter.pos());
531 leafIter->setOffsetOnly(iter.pos(), offset);
535 point_scatter_internal::generatePositions<PositionType, CodecType>
536 (*leafIter, descriptor, offset, spread, rand01);
541 for (; leafIter; ++leafIter) leafIter->setValuesOff();
544 if (interrupter) interrupter->end();
554 #endif // OPENVDB_POINTS_POINT_SCATTER_HAS_BEEN_INCLUDED