OpenVDB 7.0.0

LevelSetFracture.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
9
10 #ifndef OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED
11 #define OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED
12
13 #include <openvdb/Grid.h>
14 #include <openvdb/math/Quat.h>
15 #include <openvdb/util/NullInterrupter.h>
16
17 #include "Composite.h" // for csgIntersectionCopy() and csgDifferenceCopy()
18 #include "GridTransformer.h" // for resampleToMatch()
19 #include "LevelSetUtil.h" // for sdfSegmentation()
20
21 #include <algorithm> // for std::max(), std::min()
22 #include <limits>
23 #include <list>
24 #include <vector>
25
26 #include <tbb/blocked_range.h>
27 #include <tbb/parallel_reduce.h>
28
29
30 namespace openvdb {
31 OPENVDB_USE_VERSION_NAMESPACE
32 namespace OPENVDB_VERSION_NAME {
33 namespace tools {
34
36 template<class GridType, class InterruptType = util::NullInterrupter>
37 class LevelSetFracture
38 {
39 public:
40 using Vec3sList = std::vector<Vec3s>;
41 using QuatsList = std::vector<math::Quats>;
42 using GridPtrList = std::list<typename GridType::Ptr>;
43 using GridPtrListIter = typename GridPtrList::iterator;
44
45
49 explicit LevelSetFracture(InterruptType* interrupter = nullptr);
50
69 void fracture(GridPtrList& grids, const GridType& cutter, bool segment = false,
70 const Vec3sList* points = nullptr, const QuatsList* rotations = nullptr,
71 bool cutterOverlap = true);
72
74 GridPtrList& fragments() { return mFragments; }
75
77 void clear() { mFragments.clear(); }
78
79 private:
80 // disallow copy by assignment
81 void operator=(const LevelSetFracture&) {}
82
83 bool wasInterrupted(int percent = -1) const {
84 return mInterrupter && mInterrupter->wasInterrupted(percent);
85 }
86
87 bool isValidFragment(GridType&) const;
88 void segmentFragments(GridPtrList&) const;
89 void process(GridPtrList&, const GridType& cutter);
90
91 InterruptType* mInterrupter;
92 GridPtrList mFragments;
93 };
94
95
97
98
99 // Internal utility objects and implementation details
100
101 namespace level_set_fracture_internal {
102
103
104 template<typename LeafNodeType>
105 struct FindMinMaxVoxelValue {
106
107 using ValueType = typename LeafNodeType::ValueType;
108
109 FindMinMaxVoxelValue(const std::vector<const LeafNodeType*>& nodes)
110 : minValue(std::numeric_limits<ValueType>::max())
111 , maxValue(-minValue)
112 , mNodes(nodes.empty() ? nullptr : &nodes.front())
113 {
114 }
115
116 FindMinMaxVoxelValue(FindMinMaxVoxelValue& rhs, tbb::split)
117 : minValue(std::numeric_limits<ValueType>::max())
118 , maxValue(-minValue)
119 , mNodes(rhs.mNodes)
120 {
121 }
122
123 void operator()(const tbb::blocked_range<size_t>& range) {
124 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
125 const ValueType* data = mNodes[n]->buffer().data();
126 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
127 minValue = std::min(minValue, data[i]);
128 maxValue = std::max(maxValue, data[i]);
129 }
130 }
131 }
132
133 void join(FindMinMaxVoxelValue& rhs) {
134 minValue = std::min(minValue, rhs.minValue);
135 maxValue = std::max(maxValue, rhs.maxValue);
136 }
137
138 ValueType minValue, maxValue;
139
140 LeafNodeType const * const * const mNodes;
141 }; // struct FindMinMaxVoxelValue
142
143
144 } // namespace level_set_fracture_internal
145
146
148
149
150 template<class GridType, class InterruptType>
151 LevelSetFracture<GridType, InterruptType>::LevelSetFracture(InterruptType* interrupter)
152 : mInterrupter(interrupter)
153 , mFragments()
154 {
155 }
156
157
158 template<class GridType, class InterruptType>
159 void
160 LevelSetFracture<GridType, InterruptType>::fracture(GridPtrList& grids, const GridType& cutter,
161 bool segmentation, const Vec3sList* points, const QuatsList* rotations, bool cutterOverlap)
162 {
163 // We can process all incoming grids with the same cutter instance,
164 // this optimization is enabled by the requirement of having matching
165 // transforms between all incoming grids and the cutter object.
166 if (points && points->size() != 0) {
167
168
169 math::Transform::Ptr originalCutterTransform = cutter.transform().copy();
170 GridType cutterGrid(*const_cast<GridType*>(&cutter), ShallowCopy());
171
172 const bool hasInstanceRotations =
173 points && rotations && points->size() == rotations->size();
174
175 // for each instance point..
176 for (size_t p = 0, P = points->size(); p < P; ++p) {
177 int percent = int((float(p) / float(P)) * 100.0);
178 if (wasInterrupted(percent)) break;
179
180 GridType instCutterGrid;
181 instCutterGrid.setTransform(originalCutterTransform->copy());
182 math::Transform::Ptr xform = originalCutterTransform->copy();
183
184 if (hasInstanceRotations) {
185 const Vec3s& rot = (*rotations)[p].eulerAngles(math::XYZ_ROTATION);
186 xform->preRotate(rot[0], math::X_AXIS);
187 xform->preRotate(rot[1], math::Y_AXIS);
188 xform->preRotate(rot[2], math::Z_AXIS);
189 xform->postTranslate((*points)[p]);
190 } else {
191 xform->postTranslate((*points)[p]);
192 }
193
194 cutterGrid.setTransform(xform);
195
196 // Since there is no scaling, use the generic resampler instead of
197 // the more expensive level set rebuild tool.
198 if (mInterrupter != nullptr) {
199
200 if (hasInstanceRotations) {
201 doResampleToMatch<BoxSampler>(cutterGrid, instCutterGrid, *mInterrupter);
202 } else {
203 doResampleToMatch<PointSampler>(cutterGrid, instCutterGrid, *mInterrupter);
204 }
205 } else {
206 util::NullInterrupter interrupter;
207 if (hasInstanceRotations) {
208 doResampleToMatch<BoxSampler>(cutterGrid, instCutterGrid, interrupter);
209 } else {
210 doResampleToMatch<PointSampler>(cutterGrid, instCutterGrid, interrupter);
211 }
212 }
213
214 if (wasInterrupted(percent)) break;
215
216 if (cutterOverlap && !mFragments.empty()) process(mFragments, instCutterGrid);
217 process(grids, instCutterGrid);
218 }
219
220 } else {
221 // use cutter in place
222 if (cutterOverlap && !mFragments.empty()) process(mFragments, cutter);
223 process(grids, cutter);
224 }
225
226 if (segmentation) {
227 segmentFragments(mFragments);
228 segmentFragments(grids);
229 }
230 }
231
232
233 template<class GridType, class InterruptType>
234 bool
235 LevelSetFracture<GridType, InterruptType>::isValidFragment(GridType& grid) const
236 {
237 using LeafNodeType = typename GridType::TreeType::LeafNodeType;
238
239 if (grid.tree().leafCount() < 9) {
240
241 std::vector<const LeafNodeType*> nodes;
242 grid.tree().getNodes(nodes);
243
244 Index64 activeVoxelCount = 0;
245
246 for (size_t n = 0, N = nodes.size(); n < N; ++n) {
247 activeVoxelCount += nodes[n]->onVoxelCount();
248 }
249
250 if (activeVoxelCount < 27) return false;
251
252 level_set_fracture_internal::FindMinMaxVoxelValue<LeafNodeType> op(nodes);
253 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
254
255 if ((op.minValue < 0) == (op.maxValue < 0)) return false;
256 }
257
258 return true;
259 }
260
261
262 template<class GridType, class InterruptType>
263 void
264 LevelSetFracture<GridType, InterruptType>::segmentFragments(GridPtrList& grids) const
265 {
266 GridPtrList newFragments;
267
268 for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) {
269
270 std::vector<typename GridType::Ptr> segments;
271 segmentSDF(*(*it), segments);
272
273 for (size_t n = 0, N = segments.size(); n < N; ++n) {
274 newFragments.push_back(segments[n]);
275 }
276 }
277
278 grids.swap(newFragments);
279 }
280
281
282 template<class GridType, class InterruptType>
283 void
284 LevelSetFracture<GridType, InterruptType>::process(
285 GridPtrList& grids, const GridType& cutter)
286 {
287 using GridPtr = typename GridType::Ptr;
288 GridPtrList newFragments;
289
290 for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) {
291
292 if (wasInterrupted()) break;
293
294 GridPtr& grid = *it;
295
296 GridPtr fragment = csgIntersectionCopy(*grid, cutter);
297 if (!isValidFragment(*fragment)) continue;
298
299 GridPtr residual = csgDifferenceCopy(*grid, cutter);
300 if (!isValidFragment(*residual)) continue;
301
302 newFragments.push_back(fragment);
303
304 grid->tree().clear();
305 grid->tree().merge(residual->tree());
306 }
307
308 if (!newFragments.empty()) {
309 mFragments.splice(mFragments.end(), newFragments);
310 }
311 }
312
313 } // namespace tools
314 } // namespace OPENVDB_VERSION_NAME
315 } // namespace openvdb
316
317 #endif // OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::join
void join(FindMinMaxVoxelValue &rhs)
Definition: LevelSetFracture.h:133
Composite.h
Functions to efficiently perform various compositing operations on grids.
openvdb::v7_0::tools::LevelSetFracture::QuatsList
std::vector< math::Quats > QuatsList
Definition: LevelSetFracture.h:41
openvdb::v7_0::math::Transform::Ptr
SharedPtr< Transform > Ptr
Definition: Transform.h:42
openvdb::v7_0::tools::csgIntersectionCopy
GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG intersection operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1178
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::FindMinMaxVoxelValue
FindMinMaxVoxelValue(FindMinMaxVoxelValue &rhs, tbb::split)
Definition: LevelSetFracture.h:116
openvdb::v7_0::math::Z_AXIS
Definition: Math.h:852
openvdb::v7_0::math::XYZ_ROTATION
Definition: Math.h:857
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::maxValue
ValueType maxValue
Definition: LevelSetFracture.h:138
openvdb::v7_0::math::X_AXIS
Definition: Math.h:850
LevelSetUtil.h
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
Grid.h
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::FindMinMaxVoxelValue
FindMinMaxVoxelValue(const std::vector< const LeafNodeType * > &nodes)
Definition: LevelSetFracture.h:109
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::mNodes
const LeafNodeType *const *const mNodes
Definition: LevelSetFracture.h:140
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue
Definition: LevelSetFracture.h:105
openvdb::v7_0::util::NullInterrupter
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:25
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: LevelSetFracture.h:123
openvdb::v7_0::math::Y_AXIS
Definition: Math.h:851
openvdb::v7_0::tools::csgDifferenceCopy
GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG difference operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1192
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::ValueType
typename LeafNodeType::ValueType ValueType
Definition: LevelSetFracture.h:107
openvdb::v7_0::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:106
openvdb::v7_0::tools::LevelSetFracture::fragments
GridPtrList & fragments()
Return a list of new fragments, not including the residuals from the input grids.
Definition: LevelSetFracture.h:74
NullInterrupter.h
openvdb::v7_0::tools::LevelSetFracture
Level set fracturing.
Definition: LevelSetFracture.h:37
openvdb::v7_0::tools::level_set_fracture_internal::FindMinMaxVoxelValue::minValue
ValueType minValue
Definition: LevelSetFracture.h:138
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
openvdb::v7_0::tools::LevelSetFracture::GridPtrList
std::list< typename GridType::Ptr > GridPtrList
Definition: LevelSetFracture.h:42
Quat.h
openvdb::v7_0::tools::LevelSetFracture::clear
void clear()
Remove all elements from the fragment list.
Definition: LevelSetFracture.h:77
GridTransformer.h
openvdb::v7_0::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:102
openvdb::v7_0::tools::LevelSetFracture::fracture
void fracture(GridPtrList &grids, const GridType &cutter, bool segment=false, const Vec3sList *points=nullptr, const QuatsList *rotations=nullptr, bool cutterOverlap=true)
Divide volumes represented by level set grids into multiple, disjoint pieces by intersecting them wit...
Definition: LevelSetFracture.h:160
std
Definition: Coord.h:587
openvdb::v7_0::Index
Index32 Index
Definition: Types.h:31
openvdb::v7_0::tools::LevelSetFracture::GridPtrListIter
typename GridPtrList::iterator GridPtrListIter
Definition: LevelSetFracture.h:43
openvdb::v7_0::math::Vec3s
Vec3< float > Vec3s
Definition: Vec3.h:661
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
openvdb::v7_0::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
openvdb
Definition: Exceptions.h:13
openvdb::v7_0::tools::LevelSetFracture::Vec3sList
std::vector< Vec3s > Vec3sList
Definition: LevelSetFracture.h:40
openvdb::v7_0::Index64
uint64_t Index64
Definition: Types.h:30
openvdb::v7_0::tools::segmentSDF
void segmentSDF(const GridOrTreeType &volume, std::vector< typename GridOrTreeType::Ptr > &segments)
Separates disjoint SDF surfaces into distinct grids or trees.
Definition: LevelSetUtil.h:2549
openvdb::v7_0::ShallowCopy
Tag dispatch class that distinguishes shallow copy constructors from deep copy constructors.
Definition: Types.h:678