31 #ifndef OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED
32 #define OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED
34 #include <openvdb/Grid.h>
35 #include <openvdb/tools/Composite.h>
36 #include <openvdb/tools/GridTransformer.h>
37 #include <openvdb/tree/LeafManager.h>
38 #include <openvdb/util/NullInterrupter.h>
39 #include <openvdb/util/Util.h>
41 #include <tbb/blocked_range.h>
42 #include <tbb/parallel_for.h>
43 #include <tbb/parallel_reduce.h>
45 #include <boost/random.hpp>
46 #include <boost/generator_iterator.hpp>
47 #include <boost/math/constants/constants.hpp>
63 template<
typename Gr
idType>
64 inline typename GridType::ValueType lsutilGridMax()
69 template<
typename Gr
idType>
70 inline typename GridType::ValueType lsutilGridZero()
72 return zeroVal<typename GridType::ValueType>();
89 template<
class Gr
idType>
93 typename GridType::ValueType cutOffDistance = lsutilGridMax<GridType>());
108 template<
class Gr
idType>
109 inline typename Grid<typename GridType::TreeType::template ValueConverter<bool>::Type>::Ptr
111 const GridType& grid,
112 typename GridType::ValueType iso = lsutilGridZero<GridType>());
119 template<
class TreeType>
137 inline void operator()(
const tbb::blocked_range<size_t>&);
141 LeafArray& mLeafArray;
142 ValueType mMin, mMax;
150 template<
class TreeType,
class LeafOp>
164 inline void operator()(
const tbb::blocked_range<size_t>&)
const;
177 template<
class Gr
idType,
class InterruptType = util::NullInterrupter>
208 const PointVec* points = NULL,
bool randomizeRotation =
true,
bool cutterOverlap =
true);
216 void clear() { mFragments.clear(); }
224 return mInterrupter && mInterrupter->wasInterrupted(percent);
227 bool isValidFragment(GridType&)
const;
228 void segmentFragments(GridPtrList&)
const;
229 void process(GridPtrList&,
const GridType& cutter);
231 InterruptType* mInterrupter;
232 GridPtrList mFragments;
245 template<
typename ValueType>
249 : mWeight(ValueType(1.0) / cutOffDistance)
254 template <
typename LeafNodeType>
255 void operator()(LeafNodeType &leaf,
size_t)
const
257 const ValueType zero = zeroVal<ValueType>();
259 for (
typename LeafNodeType::ValueAllIter iter = leaf.beginValueAll(); iter; ++iter) {
260 ValueType& value =
const_cast<ValueType&
>(iter.getValue());
265 value =
std::min(ValueType(1.0), value * mWeight);
266 iter.setValueOn(value > zero);
276 template<
typename TreeType>
285 template <
typename LeafNodeType>
286 void operator()(LeafNodeType &leaf,
size_t)
const
288 const Coord origin = leaf.getOrigin();
289 const typename TreeType::LeafNodeType* refLeafPt = mTree.probeConstLeaf(origin);
291 if (refLeafPt != NULL) {
293 const typename TreeType::LeafNodeType& refLeaf = *refLeafPt;
294 typename LeafNodeType::ValueAllIter iter = leaf.beginValueAll();
296 for (; iter; ++iter) {
297 if (refLeaf.getValue(iter.pos()) < mIso) {
307 const TreeType& mTree;
308 typename TreeType::ValueType mIso;
314 template<
typename Gr
idType,
typename InterruptType>
316 std::vector<typename GridType::Ptr>
segment(GridType& grid, InterruptType* interrupter = NULL)
318 typedef typename GridType::Ptr GridPtr;
319 typedef typename GridType::TreeType TreeType;
320 typedef typename TreeType::Ptr TreePtr;
321 typedef typename TreeType::ValueType ValueType;
323 std::vector<GridPtr> segments;
325 while (grid.activeVoxelCount() > 0) {
327 if (interrupter && interrupter->wasInterrupted())
break;
332 segment->setTransform(grid.transform().copy());
333 TreePtr tree(
new TreeType(grid.background()));
334 segment->setTree(tree);
336 std::deque<Coord> coordList;
337 coordList.push_back(grid.tree().beginLeaf()->beginValueOn().getCoord());
345 while (!coordList.empty()) {
347 if (interrupter && interrupter->wasInterrupted())
break;
349 ijk = coordList.back();
350 coordList.pop_back();
352 if (!sourceAcc.probeValue(ijk, value))
continue;
353 if (targetAcc.isValueOn(ijk))
continue;
355 targetAcc.setValue(ijk, value);
356 sourceAcc.setValueOff(ijk);
358 for (
int n = 0; n < 6; n++) {
360 if (!targetAcc.isValueOn(n_ijk) && sourceAcc.isValueOn(n_ijk)) {
361 coordList.push_back(n_ijk);
366 grid.tree().pruneInactive();
367 segment->tree().signedFloodFill();
368 segments.push_back(segment);
382 template <
class TreeType>
390 template <
class TreeType>
394 : mLeafArray(rhs.mLeafArray)
400 template <
class TreeType>
404 tbb::parallel_reduce(mLeafArray.getRange(), *
this);
408 template <
class TreeType>
412 (*this)(mLeafArray.getRange());
416 template <
class TreeType>
420 typename TreeType::LeafNodeType::ValueOnCIter iter;
422 for (
size_t n = range.begin(); n < range.end(); ++n) {
423 iter = mLeafArray.leaf(n).cbeginValueOn();
424 for (; iter; ++iter) {
432 template <
class TreeType>
444 template <
class TreeType,
class LeafOp>
452 template <
class TreeType,
class LeafOp>
456 : mLeafArray(rhs.mLeafArray)
457 , mLeafOp(rhs.mLeafOp)
461 template <
class TreeType,
class LeafOp>
465 tbb::parallel_for(mLeafArray.getRange(), *
this);
468 template <
class TreeType,
class LeafOp>
472 (*this)(mLeafArray.getRange());
475 template <
class TreeType,
class LeafOp>
479 for (
size_t n = range.begin(); n < range.end(); ++n) {
480 mLeafOp(mLeafArray.leaf(n), n);
488 template <
class Gr
idType>
492 typedef typename GridType::TreeType TreeType;
493 typedef typename GridType::ValueType ValueType;
495 cutOffDistance = -std::abs(cutOffDistance);
497 TreeType& tree =
const_cast<TreeType&
>(grid.tree());
506 if (minmax.
minVoxel() > cutOffDistance) {
517 const ValueType zero = zeroVal<ValueType>();
518 typename TreeType::ValueAllIter iter(tree);
519 iter.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 1);
521 for ( ; iter; ++iter) {
522 ValueType& value =
const_cast<ValueType&
>(iter.getValue());
528 value = ValueType(1.0);
529 iter.setActiveState(
true);
535 typename TreeType::Ptr newTree(
new TreeType(zero));
536 newTree->merge(tree);
545 grid.setTree(newTree);
554 template <
class Gr
idType>
558 typedef typename GridType::TreeType::template ValueConverter<bool>::Type BoolTreeType;
561 typename BoolGridType::Ptr maskGrid(BoolGridType::create(
false));
562 maskGrid->setTransform(grid.transform().copy());
563 BoolTreeType& maskTree = maskGrid->tree();
565 maskTree.topologyUnion(grid.tree());
572 InteriorMaskOp op(grid.tree(), iso);
575 transform.runParallel();
582 typename BoolTreeType::ValueAllIter iter(maskTree);
583 iter.setMaxDepth(BoolTreeType::ValueAllIter::LEAF_DEPTH - 1);
585 for ( ; iter; ++iter) {
589 maskTree.pruneInactive();
598 template<
class Gr
idType,
class InterruptType>
600 : mInterrupter(interrupter)
606 template<
class Gr
idType,
class InterruptType>
609 bool segment,
const PointVec* points,
bool randomizeRotation,
bool cutterOverlap)
611 if (points && points->size() != 0) {
616 const Vec3s cutterCenter = originalTransform->indexToWorld(
617 cutter.evalActiveVoxelBoundingBox().getCenter());
619 boost::mt19937 rng(1);
620 boost::uniform_int<int> range(0, 359);
621 boost::variate_generator< boost::mt19937, boost::uniform_int<int> > randNr(rng, range);
622 const float deg2rad = boost::math::constants::pi<float>() / 180.0;
627 for (
size_t p = 0, P = points->size(); p < P; ++p) {
629 int percent = int((
float(p) /
float(P)) * 100.0);
632 GridType instCutterGrid;
633 instCutterGrid.setTransform(originalTransform->copy());
636 xform->postTranslate(-cutterCenter);
638 if (randomizeRotation) {
640 const float xRot = float(randNr()) * deg2rad;
641 const float yRot = float(randNr()) * deg2rad;
642 const float zRot = float(randNr()) * deg2rad;
654 xform->postTranslate(T->indexToWorld((*points)[p]));
657 xform->postTranslate(originalTransform->indexToWorld((*points)[p]));
660 cutterGrid.setTransform(xform);
664 resampleToMatch<openvdb::tools::BoxSampler>(cutterGrid, instCutterGrid);
666 if (cutterOverlap) process(mFragments, instCutterGrid);
667 process(grids, instCutterGrid);
672 process(grids, cutter);
676 segmentFragments(mFragments);
677 segmentFragments(grids);
682 template<
class Gr
idType,
class InterruptType>
686 typedef typename GridType::TreeType TreeType;
687 if (grid.activeVoxelCount() < 27)
return false;
693 minmax.runParallel();
695 if ((minmax.minVoxel() < 0) == (minmax.maxVoxel() < 0))
return false;
702 template<
class Gr
idType,
class InterruptType>
704 LevelSetFracture<GridType, InterruptType>::segmentFragments(GridPtrList& grids)
const
706 GridPtrList newFragments;
707 for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) {
711 std::vector<typename GridType::Ptr> segments =
internal::segment(*(*it), mInterrupter);
713 for (
size_t n = 0, N = segments.size(); n < N; ++n) {
717 if (isValidFragment(*segments[n])) {
718 newFragments.push_back(segments[n]);
722 grids.swap(newFragments);
726 template<
class Gr
idType,
class InterruptType>
728 LevelSetFracture<GridType, InterruptType>::process(
729 GridPtrList& grids,
const GridType& cutter)
731 typedef typename GridType::Ptr GridPtr;
733 GridPtrList newFragments;
735 for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) {
742 GridPtr fragment = grid->deepCopy();
747 if (!isValidFragment(*fragment))
continue;
750 GridPtr residual = grid->deepCopy();
755 if (!isValidFragment(*residual))
continue;
757 newFragments.push_back(fragment);
759 grid->tree().clear();
760 grid->tree().merge(residual->tree());
763 if(!newFragments.empty()) {
764 mFragments.splice(mFragments.end(), newFragments);
772 #endif // OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED