97 #ifndef OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
98 #define OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
100 #include <tbb/parallel_reduce.h>
101 #include <tbb/blocked_range.h>
102 #include <boost/bind.hpp>
103 #include <boost/function.hpp>
104 #include <boost/type_traits/is_floating_point.hpp>
105 #include <boost/utility/enable_if.hpp>
106 #include <boost/mpl/if.hpp>
107 #include <openvdb/util/Util.h>
108 #include <openvdb/Types.h>
109 #include <openvdb/Grid.h>
110 #include <openvdb/math/Math.h>
111 #include <openvdb/math/Transform.h>
112 #include <openvdb/util/NullInterrupter.h>
124 namespace local {
template <
typename VisibleT,
typename BlindT>
class BlindData;}
126 template<
typename SdfGridT,
127 typename AttributeT = void,
133 typedef typename boost::is_void<AttributeT>::type
DisableT;
139 typedef typename boost::mpl::if_<DisableT, size_t, AttributeT>::type
AttType;
140 typedef typename SdfGridT::template ValueConverter<AttType>::Type
AttGridType;
142 BOOST_STATIC_ASSERT(boost::is_floating_point<SdfType>::value);
219 template <
typename ParticleListT>
220 void rasterizeSpheres(
const ParticleListT& pa);
227 template <
typename ParticleListT>
228 void rasterizeSpheres(
const ParticleListT& pa,
Real radius);
246 template <
typename ParticleListT>
247 void rasterizeTrails(
const ParticleListT& pa,
Real delta=1.0);
252 typedef typename SdfGridT::template ValueConverter<BlindType>::Type BlindGridType;
255 template<
typename ParticleListT,
typename Gr
idT>
struct Raster;
257 SdfGridType* mSdfGrid;
258 typename AttGridType::Ptr mAttGrid;
259 BlindGridType* mBlindGrid;
260 InterrupterT* mInterrupter;
261 Real mDx, mHalfWidth;
263 size_t mMinCount, mMaxCount;
268 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
269 inline ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
270 ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupter) :
273 mInterrupter(interrupter),
274 mDx(grid.voxelSize()[0]),
275 mHalfWidth(grid.background()/mDx),
282 if (!mSdfGrid->hasUniformVoxels() ) {
284 "ParticlesToLevelSet only supports uniform voxels!");
288 "ParticlesToLevelSet only supports level sets!"
289 "\nUse Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
292 if (!DisableT::value) {
293 mBlindGrid =
new BlindGridType(
BlindType(grid.background()));
294 mBlindGrid->setTransform(mSdfGrid->transform().copy());
298 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
299 template <
typename ParticleListT>
303 if (DisableT::value) {
304 Raster<ParticleListT, SdfGridT> r(*
this, mSdfGrid, pa);
305 r.rasterizeSpheres();
307 Raster<ParticleListT, BlindGridType> r(*
this, mBlindGrid, pa);
308 r.rasterizeSpheres();
312 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
313 template <
typename ParticleListT>
317 if (DisableT::value) {
318 Raster<ParticleListT, SdfGridT> r(*
this, mSdfGrid, pa);
319 r.rasterizeSpheres(radius/mDx);
321 Raster<ParticleListT, BlindGridType> r(*
this, mBlindGrid, pa);
322 r.rasterizeSpheres(radius/mDx);
326 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
327 template <
typename ParticleListT>
331 if (DisableT::value) {
332 Raster<ParticleListT, SdfGridT> r(*
this, mSdfGrid, pa);
333 r.rasterizeTrails(delta);
335 Raster<ParticleListT, BlindGridType> r(*
this, mBlindGrid, pa);
336 r.rasterizeTrails(delta);
340 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
344 if (mBlindGrid==NULL)
return;
346 typedef typename SdfGridType::TreeType SdfTreeT;
347 typedef typename AttGridType::TreeType AttTreeT;
348 typedef typename BlindGridType::TreeType BlindTreeT;
350 const BlindTreeT& tree = mBlindGrid->tree();
353 typename SdfTreeT::Ptr sdfTree(
new SdfTreeT(tree, tree.background().visible(),
openvdb::TopologyCopy()));
356 typename AttTreeT::Ptr attTree(
new AttTreeT(tree, tree.background().blind(),
openvdb::TopologyCopy()));
357 mAttGrid =
typename AttGridType::Ptr(
new AttGridType(attTree));
358 mAttGrid->setTransform(mBlindGrid->transform().copy());
363 typedef typename BlindTreeT::LeafCIter LeafIterT;
364 typedef typename BlindTreeT::LeafNodeType LeafT;
365 typedef typename SdfTreeT::LeafNodeType SdfLeafT;
366 typedef typename AttTreeT::LeafNodeType AttLeafT;
367 for (LeafIterT n = tree.cbeginLeaf(); n; ++n) {
368 const LeafT& leaf = *n;
371 SdfLeafT* sdfLeaf = sdfTree->probeLeaf(xyz);
372 AttLeafT* attLeaf = attTree->probeLeaf(xyz);
373 for (
typename LeafT::ValueOnCIter m=leaf.cbeginValueOn(); m; ++m) {
377 sdfLeaf->setValueOnly(k, v.
visible());
378 attLeaf->setValueOnly(k, v.
blind());
381 sdfTree->signedFloodFill();
383 if (mSdfGrid->empty()) {
384 mSdfGrid->setTree(sdfTree);
392 template<
typename SdfGr
idT,
typename AttributeT,
typename InterrupterT>
393 template<
typename ParticleListT,
typename Gr
idT>
396 typedef typename boost::is_void<AttributeT>::type
DisableT;
398 typedef typename ParticlesToLevelSetT::SdfType SdfT;
399 typedef typename ParticlesToLevelSetT::AttType AttT;
400 typedef typename GridT::ValueType ValueT;
401 typedef typename GridT::Accessor AccessorT;
404 Raster(ParticlesToLevelSetT& parent, GridT* grid,
const ParticleListT& particles)
406 mParticles(particles),
408 mMap(*(mGrid->transform().baseMap())),
416 Raster(Raster& other, tbb::split)
417 : mParent(other.mParent),
418 mParticles(other.mParticles),
419 mGrid(new GridT(*other.mGrid, openvdb::
ShallowCopy())),
429 virtual ~Raster() {
if (mOwnsGrid)
delete mGrid; }
435 mMinCount = mMaxCount = 0;
436 if (mParent.mInterrupter) mParent.mInterrupter->start(
"Rasterizing particles to level set using spheres");
437 mTask = boost::bind(&Raster::rasterSpheres, _1, _2);
439 if (mParent.mInterrupter) mParent.mInterrupter->end();
446 mMinCount = radius < mParent.mRmin ? mParticles.size() : 0;
447 mMaxCount = radius > mParent.mRmax ? mParticles.size() : 0;
448 if (mMinCount>0 || mMaxCount>0) {
449 mParent.mMinCount = mMinCount;
450 mParent.mMaxCount = mMaxCount;
452 if (mParent.mInterrupter) mParent.mInterrupter->start(
"Rasterizing particles to level set using const spheres");
453 mTask = boost::bind(&Raster::rasterFixedSpheres, _1, _2, SdfT(radius));
455 if (mParent.mInterrupter) mParent.mInterrupter->end();
474 mMinCount = mMaxCount = 0;
475 if (mParent.mInterrupter) mParent.mInterrupter->start(
"Rasterizing particles to level set using trails");
476 mTask = boost::bind(&Raster::rasterTrails, _1, _2, SdfT(delta));
478 if (mParent.mInterrupter) mParent.mInterrupter->end();
482 void operator()(
const tbb::blocked_range<size_t>& r)
486 mParent.mMinCount = mMinCount;
487 mParent.mMaxCount = mMaxCount;
491 void join(Raster& other)
494 mMinCount += other.mMinCount;
495 mMaxCount += other.mMaxCount;
499 Raster& operator=(
const Raster& other) {
return *
this; }
502 bool ignoreParticle(SdfT R)
504 if (R < mParent.mRmin) {
508 if (R > mParent.mRmax) {
518 void rasterSpheres(
const tbb::blocked_range<size_t>& r)
520 AccessorT acc = mGrid->getAccessor();
522 const SdfT invDx = 1/mParent.mDx;
526 for (
Index32 id = r.begin(), e=r.end(); run &&
id != e; ++id) {
527 mParticles.getPosRad(
id, pos, rad);
528 const SdfT R = invDx * rad;
529 if (this->ignoreParticle(R))
continue;
530 const Vec3R P =
mMap.applyInverseMap(pos);
531 this->getAtt<DisableT>(id, att);
532 run = this->makeSphere(P, R, att, acc);
539 void rasterFixedSpheres(
const tbb::blocked_range<size_t>& r, SdfT R)
541 const SdfT dx = mParent.mDx, w = mParent.mHalfWidth;
542 AccessorT acc = mGrid->getAccessor();
543 const ValueT inside = -mGrid->background();
544 const SdfT
max = R + w;
551 for (
size_t id = r.begin(), e=r.end();
id != e; ++id) {
552 this->getAtt<DisableT>(id, att);
553 mParticles.getPos(
id, pos);
554 const Vec3R P =
mMap.applyInverseMap(pos);
557 for (
Coord c = a; c.
x() <= b.x(); ++c.x() ) {
560 tbb::task::self().cancel_group_execution();
564 for ( c.y() = a.y(); c.y() <= b.y(); ++c.y() ) {
566 for ( c.z() = a.z(); c.z() <= b.z(); ++c.z() ) {
567 SdfT x2y2z2 = x2y2 +
math::Pow2( c.z() - P[2] );
568 if ( x2y2z2 >= max2 || (!acc.probeValue(c,v) && v<ValueT(0)) )
570 if ( x2y2z2 <= min2 ) {
571 acc.setValueOff(c, inside);
575 const ValueT d=Merge(dx*(
math::Sqrt(x2y2z2) - R), att);
576 if (d < v) acc.setValue(c, d);
586 void rasterTrails(
const tbb::blocked_range<size_t>& r, SdfT delta)
588 AccessorT acc = mGrid->getAccessor();
594 const SdfT Rmin = mParent.mRmin, invDx = 1/mParent.mDx;
595 for (
size_t id = r.begin(), e=r.end(); run &&
id != e; ++id) {
596 mParticles.getPosRadVel(
id, pos, rad, vel);
597 const SdfT R0 = invDx*rad;
598 if (this->ignoreParticle(R0))
continue;
599 this->getAtt<DisableT>(id, att);
600 const Vec3R P0 =
mMap.applyInverseMap(pos);
601 const Vec3R V =
mMap.applyInverseMap(vel) - origin;
602 const SdfT speed = V.length(), inv_speed=1.0/speed;
603 const Vec3R N = -V*inv_speed;
606 for (
size_t m=0; run && d <= speed ; ++m) {
607 run = this->makeSphere(P, R, att, acc);
610 R = R0-(R0-Rmin)*d*inv_speed;
617 if (mParent.mGrainSize>0) {
618 tbb::parallel_reduce(tbb::blocked_range<size_t>(0,mParticles.size(),mParent.mGrainSize), *
this);
620 (*this)(tbb::blocked_range<size_t>(0, mParticles.size()));
639 bool makeSphere(
const Vec3R &P, SdfT R,
const AttT& att, AccessorT& acc)
641 const ValueT inside = -mGrid->background();
642 const SdfT dx = mParent.mDx, w = mParent.mHalfWidth;
643 const SdfT max = R + w;
650 for (
Coord c = a; c.
x() <= b.x(); ++c.x() ) {
653 tbb::task::self().cancel_group_execution();
657 for ( c.y() = a.y(); c.y() <= b.y(); ++c.y() ) {
659 for ( c.z() = a.z(); c.z() <= b.z(); ++c.z() ) {
660 SdfT x2y2z2 = x2y2 +
math::Pow2( c.z() - P[2] );
661 if ( x2y2z2 >= max2 || (!acc.probeValue(c,v) && v<ValueT(0)) )
663 if ( x2y2z2 <= min2 ) {
664 acc.setValueOff(c, inside);
669 const ValueT d=Merge(dx*(
math::Sqrt(x2y2z2) - R), att);
670 if (d < v) acc.setValue(c, d);
676 typedef typename boost::function<void (Raster*, const tbb::blocked_range<size_t>&)> FuncType;
678 template <
typename DisableType>
679 typename boost::enable_if<DisableType>::type
680 getAtt(
size_t, AttT&)
const {;}
682 template <
typename DisableType>
683 typename boost::disable_if<DisableType>::type
684 getAtt(
size_t n, AttT& a)
const {mParticles.getAtt(n, a);}
686 template <
typename T>
687 typename boost::enable_if<boost::is_same<T,ValueT>, ValueT>::type
688 Merge(T s,
const AttT&)
const {
return s; }
690 template <
typename T>
691 typename boost::disable_if<boost::is_same<T,ValueT>, ValueT>::type
692 Merge(T s,
const AttT& a)
const {
return ValueT(s,a); }
694 ParticlesToLevelSetT& mParent;
695 const ParticleListT& mParticles;
697 const math::MapBase&
mMap;
698 size_t mMinCount, mMaxCount;
700 const bool mOwnsGrid;
710 template <
typename VisibleT,
typename BlindT>
740 template <
typename VisibleT,
typename BlindT>
741 inline std::ostream& operator<<(std::ostream& ostr, const BlindData<VisibleT, BlindT>& rhs)
743 ostr << rhs.visible();
747 template <
typename VisibleT,
typename BlindT>
760 #endif // OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED