89 #ifndef OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
90 #define OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
92 #include <tbb/parallel_reduce.h>
93 #include <tbb/blocked_range.h>
105 #include <functional>
107 #include <type_traits>
120 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT = util::NullInterrupter>
121 inline void particlesToSdf(
const ParticleListT&, GridT&, InterrupterT* =
nullptr);
127 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT = util::NullInterrupter>
128 inline void particlesToSdf(
const ParticleListT&, GridT&,
Real radius, InterrupterT* =
nullptr);
137 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT = util::NullInterrupter>
144 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT = util::NullInterrupter>
145 inline void particlesToMask(
const ParticleListT&, GridT&, InterrupterT* =
nullptr);
151 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT = util::NullInterrupter>
152 inline void particlesToMask(
const ParticleListT&, GridT&,
Real radius, InterrupterT* =
nullptr);
161 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT = util::NullInterrupter>
168 namespace p2ls_internal {
173 template<
typename VisibleT,
typename BlindT>
class BlindData;
177 template<
typename SdfGridT,
178 typename AttributeT = void,
183 using DisableT =
typename std::is_void<AttributeT>::type;
189 using AttType =
typename std::conditional<DisableT::value, size_t, AttributeT>::type;
190 using AttGridType =
typename SdfGridT::template ValueConverter<AttType>::Type;
192 static const bool OutputIsMask = std::is_same<SdfType, bool>::value;
224 void finalize(
bool prune =
false);
264 template<
typename ParticleListT>
265 void rasterizeSpheres(
const ParticleListT& pa);
273 template<
typename ParticleListT>
274 void rasterizeSpheres(
const ParticleListT& pa,
Real radius);
291 template<
typename ParticleListT>
292 void rasterizeTrails(
const ParticleListT& pa,
Real delta=1.0);
295 using BlindType = p2ls_internal::BlindData<SdfType, AttType>;
296 using BlindGridType =
typename SdfGridT::template ValueConverter<BlindType>::Type;
299 template<
typename ParticleListT,
typename Gr
idT>
struct Raster;
301 SdfGridType* mSdfGrid;
302 typename AttGridType::Ptr mAttGrid;
303 BlindGridType* mBlindGrid;
304 InterrupterT* mInterrupter;
305 Real mDx, mHalfWidth;
307 size_t mMinCount, mMaxCount;
312 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
313 inline ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
314 ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupter) :
317 mInterrupter(interrupter),
318 mDx(grid.voxelSize()[0]),
319 mHalfWidth(grid.background()/mDx),
326 if (!mSdfGrid->hasUniformVoxels()) {
329 if (!DisableT::value) {
330 mBlindGrid =
new BlindGridType(BlindType(grid.background()));
331 mBlindGrid->setTransform(mSdfGrid->transform().copy());
335 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
336 template<
typename ParticleListT>
340 if (DisableT::value) {
341 Raster<ParticleListT, SdfGridT> r(*
this, mSdfGrid, pa);
342 r.rasterizeSpheres();
344 Raster<ParticleListT, BlindGridType> r(*
this, mBlindGrid, pa);
345 r.rasterizeSpheres();
349 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
350 template<
typename ParticleListT>
354 if (DisableT::value) {
355 Raster<ParticleListT, SdfGridT> r(*
this, mSdfGrid, pa);
356 r.rasterizeSpheres(radius/mDx);
358 Raster<ParticleListT, BlindGridType> r(*
this, mBlindGrid, pa);
359 r.rasterizeSpheres(radius/mDx);
363 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
364 template<
typename ParticleListT>
368 if (DisableT::value) {
369 Raster<ParticleListT, SdfGridT> r(*
this, mSdfGrid, pa);
370 r.rasterizeTrails(delta);
372 Raster<ParticleListT, BlindGridType> r(*
this, mBlindGrid, pa);
373 r.rasterizeTrails(delta);
378 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
397 using AttTreeT =
typename AttGridType::TreeType;
398 using AttLeafT =
typename AttTreeT::LeafNodeType;
399 using BlindTreeT =
typename BlindGridType::TreeType;
400 using BlindLeafIterT =
typename BlindTreeT::LeafCIter;
401 using BlindLeafT =
typename BlindTreeT::LeafNodeType;
402 using SdfTreeT =
typename SdfGridType::TreeType;
403 using SdfLeafT =
typename SdfTreeT::LeafNodeType;
406 const BlindTreeT& blindTree = mBlindGrid->tree();
409 typename AttTreeT::Ptr attTree(
new AttTreeT(
412 mAttGrid =
typename AttGridType::Ptr(
new AttGridType(attTree));
413 mAttGrid->setTransform(mBlindGrid->transform().copy());
415 typename SdfTreeT::Ptr sdfTree;
419 sdfTree.reset(
new SdfTreeT(blindTree,
424 leafNodes.
foreach([&](AttLeafT& attLeaf,
size_t ) {
425 if (
const auto* blindLeaf = blindTree.probeConstLeaf(attLeaf.origin())) {
426 for (
auto iter = attLeaf.beginValueOn(); iter; ++iter) {
427 const auto pos = iter.pos();
428 attLeaf.setValueOnly(pos, blindLeaf->getValue(pos).blind());
433 const auto blindAcc = mBlindGrid->getConstAccessor();
434 auto iter = attTree->beginValueOn();
435 iter.setMaxDepth(AttTreeT::ValueOnIter::LEAF_DEPTH - 1);
436 for ( ; iter; ++iter) {
437 iter.modifyValue([&](
AttType& v) { v = blindAcc.getValue(iter.getCoord()).blind(); });
442 sdfTree.reset(
new SdfTreeT(blindTree, blindTree.background().visible(),
TopologyCopy()));
443 for (BlindLeafIterT n = blindTree.cbeginLeaf(); n; ++n) {
444 const BlindLeafT& leaf = *n;
447 SdfLeafT* sdfLeaf = sdfTree->probeLeaf(xyz);
448 AttLeafT* attLeaf = attTree->probeLeaf(xyz);
450 typename BlindLeafT::ValueOnCIter m=leaf.cbeginValueOn();
453 const BlindType& v = leaf.getValue(k);
454 sdfLeaf->setValueOnly(k, v.visible());
455 attLeaf->setValueOnly(k, v.blind());
460 const BlindType& v = *m;
461 sdfLeaf->setValueOnly(k, v.visible());
462 attLeaf->setValueOnly(k, v.blind());
469 if (mSdfGrid->empty()) {
470 mSdfGrid->setTree(sdfTree);
473 mSdfGrid->tree().topologyUnion(*sdfTree);
487 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
488 template<
typename ParticleListT,
typename Gr
idT>
491 using DisableT =
typename std::is_void<AttributeT>::type;
493 using SdfT =
typename ParticlesToLevelSetT::SdfType;
494 using AttT =
typename ParticlesToLevelSetT::AttType;
495 using ValueT =
typename GridT::ValueType;
496 using AccessorT =
typename GridT::Accessor;
497 using TreeT =
typename GridT::TreeType;
498 using LeafNodeT =
typename TreeT::LeafNodeType;
503 DoAttrXfer = !DisableT::value;
506 Raster(ParticlesToLevelSetT& parent, GridT* grid,
const ParticleListT& particles)
508 , mParticles(particles)
510 , mMap(*(mGrid->transform().baseMap()))
515 mPointPartitioner =
new PointPartitionerT;
516 mPointPartitioner->construct(particles, mGrid->transform());
520 Raster(Raster& other, tbb::split)
521 : mParent(other.mParent)
522 , mParticles(other.mParticles)
529 , mPointPartitioner(other.mPointPartitioner)
541 delete mPointPartitioner;
547 mMinCount = mMaxCount = 0;
548 if (mParent.mInterrupter) {
549 mParent.mInterrupter->start(
"Rasterizing particles to level set using spheres");
551 mTask = std::bind(&Raster::rasterSpheres, std::placeholders::_1, std::placeholders::_2);
553 if (mParent.mInterrupter) mParent.mInterrupter->end();
558 mMinCount = radius < mParent.mRmin ? mParticles.size() : 0;
559 mMaxCount = radius > mParent.mRmax ? mParticles.size() : 0;
560 if (mMinCount>0 || mMaxCount>0) {
561 mParent.mMinCount = mMinCount;
562 mParent.mMaxCount = mMaxCount;
564 if (mParent.mInterrupter) {
565 mParent.mInterrupter->start(
566 "Rasterizing particles to level set using const spheres");
568 mTask = std::bind(&Raster::rasterFixedSpheres,
569 std::placeholders::_1, std::placeholders::_2, radius);
571 if (mParent.mInterrupter) mParent.mInterrupter->end();
577 mMinCount = mMaxCount = 0;
578 if (mParent.mInterrupter) {
579 mParent.mInterrupter->start(
"Rasterizing particles to level set using trails");
581 mTask = std::bind(&Raster::rasterTrails,
582 std::placeholders::_1, std::placeholders::_2, delta);
584 if (mParent.mInterrupter) mParent.mInterrupter->end();
588 void operator()(
const tbb::blocked_range<size_t>& r)
592 mParent.mMinCount = mMinCount;
593 mParent.mMaxCount = mMaxCount;
597 void join(Raster& other)
604 mGrid->topologyUnion(*other.mGrid);
610 mMinCount += other.mMinCount;
611 mMaxCount += other.mMaxCount;
616 Raster& operator=(
const Raster&) {
return *
this; }
619 bool ignoreParticle(
Real R)
621 if (R < mParent.mRmin) {
625 if (R > mParent.mRmax) {
634 void rasterSpheres(
const tbb::blocked_range<size_t>& r)
636 AccessorT acc = mGrid->getAccessor();
638 const Real invDx = 1 / mParent.mDx;
644 for (
size_t n = r.begin(), N = r.end(); n < N; ++n) {
646 typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n);
647 for ( ; run && iter; ++iter) {
649 mParticles.getPosRad(
id, pos, rad);
650 const Real R = invDx * rad;
651 if (this->ignoreParticle(R))
continue;
652 const Vec3R P = mMap.applyInverseMap(pos);
653 this->getAtt<DisableT>(
id, att);
654 run = this->makeSphere(P, R, att, acc);
662 void rasterFixedSpheres(
const tbb::blocked_range<size_t>& r,
Real R)
664 AccessorT acc = mGrid->getAccessor();
669 for (
size_t n = r.begin(), N = r.end(); n < N; ++n) {
671 for (
auto iter = mPointPartitioner->indices(n); iter; ++iter) {
673 this->getAtt<DisableT>(
id, att);
674 mParticles.getPos(
id, pos);
675 const Vec3R P = mMap.applyInverseMap(pos);
676 this->makeSphere(P, R, att, acc);
684 void rasterTrails(
const tbb::blocked_range<size_t>& r,
Real delta)
686 AccessorT acc = mGrid->getAccessor();
691 const Vec3R origin = mMap.applyInverseMap(
Vec3R(0,0,0));
692 const Real Rmin = mParent.mRmin, invDx = 1 / mParent.mDx;
695 for (
size_t n = r.begin(), N = r.end(); n < N; ++n) {
697 typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n);
698 for ( ; run && iter; ++iter) {
700 mParticles.getPosRadVel(
id, pos, rad, vel);
701 const Real R0 = invDx * rad;
702 if (this->ignoreParticle(R0))
continue;
703 this->getAtt<DisableT>(
id, att);
704 const Vec3R P0 = mMap.applyInverseMap(pos);
705 const Vec3R V = mMap.applyInverseMap(vel) - origin;
706 const Real speed = V.length(), invSpeed = 1.0 / speed;
707 const Vec3R Nrml = -V * invSpeed;
710 for (
size_t m = 0; run && d <= speed ; ++m) {
711 run = this->makeSphere(P, R, att, acc);
712 P += 0.5 * delta * R * Nrml;
713 d = (P - P0).length();
714 R = R0 - (R0 - Rmin) * d * invSpeed;
725 if (mParent.mGrainSize>0) {
726 tbb::parallel_reduce(
727 tbb::blocked_range<size_t>(0, bucketCount, mParent.mGrainSize), *
this);
729 (*this)(tbb::blocked_range<size_t>(0, bucketCount));
740 bool makeSphere(
const Vec3R& P,
Real R,
const AttT& att, AccessorT& acc)
744 return makeSphereMask(P, R, att, acc);
746 return makeNarrowBandSphere(P, R, att, acc);
765 bool makeNarrowBandSphere(
const Vec3R& P,
Real R,
const AttT& att, AccessorT& acc)
769 w = mParent.mHalfWidth,
777 const ValueT inside = -mGrid->background();
781 for (Coord c = lo; c.x() <= hi.x(); ++c.x()) {
784 tbb::task::self().cancel_group_execution();
788 for (c.y() = lo.y(); c.y() <= hi.y(); ++c.y()) {
790 for (c.z() = lo.z(); c.z() <= hi.z(); ++c.z()) {
792 #if defined __INTEL_COMPILER
793 _Pragma(
"warning (push)")
794 _Pragma("warning (disable:186)")
796 if (x2y2z2 >= max2 || (!acc.probeValue(c, v) && (v < ValueT(0))))
798 #if defined __INTEL_COMPILER
799 _Pragma(
"warning (pop)")
801 if (x2y2z2 <= min2) {
802 acc.setValueOff(c, inside);
807 const ValueT d = Merge(static_cast<SdfT>(dx*(
math::Sqrt(x2y2z2)-R)), att);
808 if (d < v) acc.setValue(c, d);
817 bool makeSphereMask(
const Vec3R& p,
Real r,
const AttT& att, AccessorT& acc)
831 const std::vector<CoordBBox> padding{
832 CoordBBox(outLo.x(), outLo.y(), outLo.z(), inLo.x()-1, outHi.y(), outHi.z()),
833 CoordBBox(inHi.x()+1, outLo.y(), outLo.z(), outHi.x(), outHi.y(), outHi.z()),
834 CoordBBox(outLo.x(), outLo.y(), outLo.z(), outHi.x(), inLo.y()-1, outHi.z()),
835 CoordBBox(outLo.x(), inHi.y()+1, outLo.z(), outHi.x(), outHi.y(), outHi.z()),
836 CoordBBox(outLo.x(), outLo.y(), outLo.z(), outHi.x(), outHi.y(), inLo.z()-1),
837 CoordBBox(outLo.x(), outLo.y(), inHi.z()+1, outHi.x(), outHi.y(), outHi.z()),
839 const ValueT onValue = Merge(SdfT(1), att);
843 acc.tree().sparseFill(CoordBBox(inLo, inHi), onValue);
846 for (
const auto& bbox: padding) {
848 tbb::task::self().cancel_group_execution();
851 const Coord &bmin = bbox.min(), &bmax = bbox.max();
854 for (c = bmin, cx = c.x(); c.x() <= bmax.x(); ++c.x(), cx += 1) {
856 for (c.y() = bmin.y(), cy = c.y(); c.y() <= bmax.y(); ++c.y(), cy += 1) {
858 for (c.z() = bmin.z(), cz = c.z(); c.z() <= bmax.z(); ++c.z(), cz += 1) {
860 if (x2y2z2 < rSquared) {
861 acc.setValue(c, onValue);
870 using FuncType =
typename std::function<void (Raster*,
const tbb::blocked_range<size_t>&)>;
872 template<
typename DisableType>
873 typename std::enable_if<DisableType::value>::type
874 getAtt(
size_t, AttT&)
const {}
876 template<
typename DisableType>
877 typename std::enable_if<!DisableType::value>::type
878 getAtt(
size_t n, AttT& a)
const { mParticles.getAtt(n, a); }
881 typename std::enable_if<std::is_same<T, ValueT>::value, ValueT>::type
882 Merge(T s,
const AttT&)
const {
return s; }
885 typename std::enable_if<!std::is_same<T, ValueT>::value, ValueT>::type
886 Merge(T s,
const AttT& a)
const {
return ValueT(s,a); }
888 ParticlesToLevelSetT& mParent;
889 const ParticleListT& mParticles;
891 const math::MapBase& mMap;
892 size_t mMinCount, mMaxCount;
895 PointPartitionerT* mPointPartitioner;
902 namespace p2ls_internal {
908 template<
typename VisibleT,
typename BlindT>
912 using type = VisibleT;
913 using VisibleType = VisibleT;
914 using BlindType = BlindT;
917 explicit BlindData(VisibleT v) : mVisible(v), mBlind(
zeroVal<BlindType>()) {}
918 BlindData(VisibleT v, BlindT b) : mVisible(v), mBlind(b) {}
919 BlindData(
const BlindData&) =
default;
920 BlindData& operator=(
const BlindData&) =
default;
921 const VisibleT& visible()
const {
return mVisible; }
922 const BlindT& blind()
const {
return mBlind; }
924 bool operator==(
const BlindData& rhs)
const {
return mVisible == rhs.mVisible; }
926 bool operator< (
const BlindData& rhs)
const {
return mVisible < rhs.mVisible; }
927 bool operator> (
const BlindData& rhs)
const {
return mVisible > rhs.mVisible; }
928 BlindData
operator+(
const BlindData& rhs)
const {
return BlindData(mVisible + rhs.mVisible); }
929 BlindData
operator-(
const BlindData& rhs)
const {
return BlindData(mVisible - rhs.mVisible); }
930 BlindData
operator-()
const {
return BlindData(-mVisible, mBlind); }
939 template<
typename VisibleT,
typename BlindT>
940 inline std::ostream&
operator<<(std::ostream& ostr,
const BlindData<VisibleT, BlindT>& rhs)
942 ostr << rhs.visible();
948 template<
typename VisibleT,
typename BlindT>
949 inline BlindData<VisibleT, BlindT>
Abs(
const BlindData<VisibleT, BlindT>& x)
951 return BlindData<VisibleT, BlindT>(
math::Abs(x.visible()), x.blind());
956 template<
typename VisibleT,
typename BlindT,
typename T>
957 inline BlindData<VisibleT, BlindT>
958 operator+(
const BlindData<VisibleT, BlindT>& x,
const T& rhs)
960 return BlindData<VisibleT, BlindT>(x.visible() + static_cast<VisibleT>(rhs), x.blind());
971 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT>
975 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
976 "particlesToSdf requires an SDF grid with floating-point values");
980 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
988 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT>
992 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
993 "particlesToSdf requires an SDF grid with floating-point values");
997 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
1005 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT>
1009 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
1010 "particleTrailsToSdf requires an SDF grid with floating-point values");
1014 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
1022 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT>
1026 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
1027 "particlesToMask requires a boolean-valued grid");
1033 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT>
1037 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
1038 "particlesToMask requires a boolean-valued grid");
1044 template<
typename Gr
idT,
typename ParticleListT,
typename InterrupterT>
1048 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
1049 "particleTrailsToMask requires a boolean-valued grid");
1059 #endif // OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED