GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/tools/LevelSetUtil.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 774 856 90.4%
Functions: 65 200 32.5%
Branches: 774 1675 46.2%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file tools/LevelSetUtil.h
5 ///
6 /// @brief Miscellaneous utility methods that operate primarily
7 /// or exclusively on level set grids.
8 ///
9 /// @author Mihai Alden
10
11 #ifndef OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED
12 #define OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED
13
14 #include "MeshToVolume.h" // for traceExteriorBoundaries
15 #include "SignedFloodFill.h" // for signedFloodFillWithValues
16
17 #include <openvdb/Types.h>
18 #include <openvdb/Grid.h>
19 #include <openvdb/openvdb.h>
20 #include <openvdb/points/PointDataGrid.h>
21 #include <tbb/blocked_range.h>
22 #include <tbb/parallel_for.h>
23 #include <tbb/parallel_reduce.h>
24 #include <tbb/parallel_sort.h>
25 #include <algorithm>
26 #include <cmath>
27 #include <cstdlib>
28 #include <deque>
29 #include <limits>
30 #include <memory>
31 #include <set>
32 #include <vector>
33
34
35 namespace openvdb {
36 OPENVDB_USE_VERSION_NAMESPACE
37 namespace OPENVDB_VERSION_NAME {
38 namespace tools {
39
40 // MS Visual C++ requires this extra level of indirection in order to compile
41 // THIS MUST EXIST IN AN UNNAMED NAMESPACE IN ORDER TO COMPILE ON WINDOWS
42 namespace {
43
44 template<typename GridType>
45 inline typename GridType::ValueType lsutilGridMax()
46 {
47 return std::numeric_limits<typename GridType::ValueType>::max();
48 }
49
50 template<typename GridType>
51 inline typename GridType::ValueType lsutilGridZero()
52 {
53 return zeroVal<typename GridType::ValueType>();
54 }
55
56 } // unnamed namespace
57
58
59 ////////////////////////////////////////
60
61
62 /// @brief Threaded method to convert a sparse level set/SDF into a sparse fog volume
63 ///
64 /// @details For a level set, the active and negative-valued interior half of the
65 /// narrow band becomes a linear ramp from 0 to 1; the inactive interior becomes
66 /// active with a constant value of 1; and the exterior, including the background
67 /// and the active exterior half of the narrow band, becomes inactive with a constant
68 /// value of 0. The interior, though active, remains sparse.
69 /// @details For a generic SDF, a specified cutoff distance determines the width
70 /// of the ramp, but otherwise the result is the same as for a level set.
71 ///
72 /// @param grid level set/SDF grid to transform
73 /// @param cutoffDistance optional world space cutoff distance for the ramp
74 /// (automatically clamped if greater than the interior
75 /// narrow band width)
76 template<class GridType>
77 void
78 sdfToFogVolume(
79 GridType& grid,
80 typename GridType::ValueType cutoffDistance = lsutilGridMax<GridType>());
81
82
83 /// @brief Threaded method to construct a boolean mask that represents interior regions
84 /// in a signed distance field.
85 ///
86 /// @return A shared pointer to either a boolean grid or tree with the same tree
87 /// configuration and potentially transform as the input @c volume and whose active
88 /// and @c true values correspond to the interior of the input signed distance field.
89 ///
90 /// @param volume Signed distance field / level set volume.
91 /// @param isovalue Threshold below which values are considered part of the
92 /// interior region.
93 template<class GridOrTreeType>
94 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
95 sdfInteriorMask(
96 const GridOrTreeType& volume,
97 typename GridOrTreeType::ValueType isovalue = lsutilGridZero<GridOrTreeType>());
98
99
100 /// @brief Extracts the interior regions of a signed distance field and topologically enclosed
101 /// (watertight) regions of value greater than the @a isovalue (cavities) that can arise
102 /// as the result of CSG union operations between different shapes where at least one of
103 /// the shapes has a concavity that is capped.
104 ///
105 /// For example the enclosed region of a capped bottle would include the walls and
106 /// the interior cavity.
107 ///
108 /// @return A shared pointer to either a boolean grid or tree with the same tree configuration
109 /// and potentially transform as the input @c volume and whose active and @c true values
110 /// correspond to the interior and enclosed regions in the input signed distance field.
111 ///
112 /// @param volume Signed distance field / level set volume.
113 /// @param isovalue Threshold below which values are considered part of the interior region.
114 /// @param fillMask Optional boolean tree, when provided enclosed cavity regions that are not
115 /// completely filled by this mask are ignored.
116 ///
117 /// For instance if the fill mask does not completely fill the bottle in the
118 /// previous example only the walls and cap are returned and the interior
119 /// cavity will be ignored.
120 template<typename GridOrTreeType>
121 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
122 extractEnclosedRegion(
123 const GridOrTreeType& volume,
124 typename GridOrTreeType::ValueType isovalue = lsutilGridZero<GridOrTreeType>(),
125 const typename TreeAdapter<GridOrTreeType>::TreeType::template ValueConverter<bool>::Type*
126 fillMask = nullptr);
127
128
129 /// @brief Return a mask of the voxels that intersect the implicit surface with
130 /// the given @a isovalue.
131 ///
132 /// @param volume Signed distance field / level set volume.
133 /// @param isovalue The crossing point that is considered the surface.
134 template<typename GridOrTreeType>
135 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
136 extractIsosurfaceMask(const GridOrTreeType& volume, typename GridOrTreeType::ValueType isovalue);
137
138
139 /// @brief Return a mask for each connected component of the given grid's active voxels.
140 ///
141 /// @param volume Input grid or tree
142 /// @param masks Output set of disjoint active topology masks sorted in descending order
143 /// based on the active voxel count.
144 template<typename GridOrTreeType>
145 void
146 extractActiveVoxelSegmentMasks(const GridOrTreeType& volume,
147 std::vector<typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr>& masks);
148
149
150 /// @brief Separates disjoint active topology components into distinct grids or trees.
151 ///
152 /// @details Supports volumes with active tiles.
153 ///
154 /// @param volume Input grid or tree
155 /// @param segments Output set of disjoint active topology components sorted in
156 /// descending order based on the active voxel count.
157 template<typename GridOrTreeType>
158 void
159 segmentActiveVoxels(const GridOrTreeType& volume,
160 std::vector<typename GridOrTreeType::Ptr>& segments);
161
162
163 /// @brief Separates disjoint SDF surfaces into distinct grids or trees.
164 ///
165 /// @details Supports asymmetric interior / exterior narrowband widths and
166 /// SDF volumes with dense interior regions.
167 ///
168 /// @param volume Input signed distance field / level set volume
169 /// @param segments Output set of disjoint SDF surfaces found in @a volume sorted in
170 /// descending order based on the surface intersecting voxel count.
171 template<typename GridOrTreeType>
172 void
173 segmentSDF(const GridOrTreeType& volume, std::vector<typename GridOrTreeType::Ptr>& segments);
174
175
176 ////////////////////////////////////////////////////////////////////////////////
177 ////////////////////////////////////////////////////////////////////////////////
178
179 // Internal utility objects and implementation details
180
181 /// @cond OPENVDB_DOCS_INTERNAL
182
183 namespace level_set_util_internal {
184
185
186 template<typename LeafNodeType>
187 struct MaskInteriorVoxels {
188
189 using ValueType = typename LeafNodeType::ValueType;
190 using BoolLeafNodeType = tree::LeafNode<bool, LeafNodeType::LOG2DIM>;
191
192 30 MaskInteriorVoxels(
193 ValueType isovalue, const LeafNodeType ** nodes, BoolLeafNodeType ** maskNodes)
194 30 : mNodes(nodes), mMaskNodes(maskNodes), mIsovalue(isovalue)
195 {
196 }
197
198 4384 void operator()(const tbb::blocked_range<size_t>& range) const {
199
200 BoolLeafNodeType * maskNodePt = nullptr;
201
202
2/2
✓ Branch 0 taken 9899 times.
✓ Branch 1 taken 2192 times.
24182 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
203
204 19798 mMaskNodes[n] = nullptr;
205 19798 const LeafNodeType& node = *mNodes[n];
206
207
2/2
✓ Branch 0 taken 6669 times.
✓ Branch 1 taken 3230 times.
19798 if (!maskNodePt) {
208 13338 maskNodePt = new BoolLeafNodeType(node.origin(), false);
209 } else {
210 maskNodePt->setOrigin(node.origin());
211 }
212
213 const ValueType* values = &node.getValue(0);
214
2/2
✓ Branch 0 taken 5068288 times.
✓ Branch 1 taken 9899 times.
10156374 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
215
2/2
✓ Branch 0 taken 1612481 times.
✓ Branch 1 taken 3455807 times.
10136576 if (values[i] < mIsovalue) maskNodePt->setValueOn(i, true);
216 }
217
218
2/2
✓ Branch 0 taken 5727 times.
✓ Branch 1 taken 4172 times.
19798 if (maskNodePt->onVoxelCount() > 0) {
219 11454 mMaskNodes[n] = maskNodePt;
220 maskNodePt = nullptr;
221 }
222 }
223
224
2/2
✓ Branch 0 taken 942 times.
✓ Branch 1 taken 1250 times.
4384 if (maskNodePt) delete maskNodePt;
225 4384 }
226
227 LeafNodeType const * const * const mNodes;
228 BoolLeafNodeType ** const mMaskNodes;
229 ValueType const mIsovalue;
230 }; // MaskInteriorVoxels
231
232
233 template<typename TreeType, typename InternalNodeType>
234 struct MaskInteriorTiles {
235
236 using ValueType = typename TreeType::ValueType;
237
238 30 MaskInteriorTiles(ValueType isovalue, const TreeType& tree, InternalNodeType ** maskNodes)
239 30 : mTree(&tree), mMaskNodes(maskNodes), mIsovalue(isovalue) { }
240
241 306 void operator()(const tbb::blocked_range<size_t>& range) const {
242 306 tree::ValueAccessor<const TreeType> acc(*mTree);
243
2/2
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 153 times.
612 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
244 306 typename InternalNodeType::ValueAllIter it = mMaskNodes[n]->beginValueAll();
245
2/2
✓ Branch 0 taken 620961 times.
✓ Branch 1 taken 153 times.
1242228 for (; it; ++it) {
246
4/8
✓ Branch 1 taken 620961 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 620961 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2186 times.
✓ Branch 7 taken 618775 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1241922 if (acc.getValue(it.getCoord()) < mIsovalue) {
247 it.setValue(true);
248
1/2
✓ Branch 1 taken 2186 times.
✗ Branch 2 not taken.
4372 it.setValueOn(true);
249 }
250 }
251 }
252 306 }
253
254 TreeType const * const mTree;
255 InternalNodeType ** const mMaskNodes;
256 ValueType const mIsovalue;
257 }; // MaskInteriorTiles
258
259
260 template<typename TreeType>
261
5/16
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 2 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 27 times.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 27 taken 18 times.
✗ Branch 28 not taken.
112 struct PopulateTree {
262
263 using ValueType = typename TreeType::ValueType;
264 using LeafNodeType = typename TreeType::LeafNodeType;
265
266 50 PopulateTree(TreeType& tree, LeafNodeType** leafnodes,
267 const size_t * nodexIndexMap, ValueType background)
268 : mNewTree(background)
269 , mTreePt(&tree)
270 , mNodes(leafnodes)
271 50 , mNodeIndexMap(nodexIndexMap)
272 {
273 }
274
275 62 PopulateTree(PopulateTree& rhs, tbb::split)
276 : mNewTree(rhs.mNewTree.background())
277 , mTreePt(&mNewTree)
278 62 , mNodes(rhs.mNodes)
279 62 , mNodeIndexMap(rhs.mNodeIndexMap)
280 {
281 }
282
283 570 void operator()(const tbb::blocked_range<size_t>& range) {
284
285 570 tree::ValueAccessor<TreeType> acc(*mTreePt);
286
287
1/2
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
570 if (mNodeIndexMap) {
288
2/2
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 376 times.
1140 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
289
2/2
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 54575 times.
99821 for (size_t i = mNodeIndexMap[n], I = mNodeIndexMap[n + 1]; i < I; ++i) {
290
3/4
✓ Branch 0 taken 38692 times.
✓ Branch 1 taken 15883 times.
✓ Branch 3 taken 38692 times.
✗ Branch 4 not taken.
99251 if (mNodes[i] != nullptr) acc.addLeaf(mNodes[i]);
291 }
292 }
293 } else {
294 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
295 acc.addLeaf(mNodes[n]);
296 }
297 }
298 570 }
299
300 62 void join(PopulateTree& rhs) { mTreePt->merge(*rhs.mTreePt); }
301
302 private:
303 TreeType mNewTree;
304 TreeType * const mTreePt;
305 LeafNodeType ** const mNodes;
306 size_t const * const mNodeIndexMap;
307 }; // PopulateTree
308
309
310 /// @brief Negative active values are set @c 0, everything else is set to @c 1.
311 template<typename LeafNodeType>
312 struct LabelBoundaryVoxels {
313
314 using ValueType = typename LeafNodeType::ValueType;
315 using CharLeafNodeType = tree::LeafNode<char, LeafNodeType::LOG2DIM>;
316
317 2 LabelBoundaryVoxels(
318 ValueType isovalue, const LeafNodeType ** nodes, CharLeafNodeType ** maskNodes)
319
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 : mNodes(nodes), mMaskNodes(maskNodes), mIsovalue(isovalue)
320 {
321 }
322
323 550 void operator()(const tbb::blocked_range<size_t>& range) const {
324
325 CharLeafNodeType * maskNodePt = nullptr;
326
327
2/2
✓ Branch 0 taken 848 times.
✓ Branch 1 taken 275 times.
2246 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
328
329 1696 mMaskNodes[n] = nullptr;
330 1696 const LeafNodeType& node = *mNodes[n];
331
332
1/2
✓ Branch 0 taken 848 times.
✗ Branch 1 not taken.
1696 if (!maskNodePt) {
333
1/2
✓ Branch 2 taken 848 times.
✗ Branch 3 not taken.
1696 maskNodePt = new CharLeafNodeType(node.origin(), 1);
334 } else {
335 maskNodePt->setOrigin(node.origin());
336 }
337
338 typename LeafNodeType::ValueOnCIter it;
339
2/2
✓ Branch 0 taken 285935 times.
✓ Branch 1 taken 848 times.
575262 for (it = node.cbeginValueOn(); it; ++it) {
340 1143740 maskNodePt->setValueOn(it.pos(), ((*it - mIsovalue) < 0.0) ? 0 : 1);
341 }
342
343
1/2
✓ Branch 0 taken 848 times.
✗ Branch 1 not taken.
1696 if (maskNodePt->onVoxelCount() > 0) {
344 1696 mMaskNodes[n] = maskNodePt;
345 maskNodePt = nullptr;
346 }
347 }
348
349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
550 if (maskNodePt) delete maskNodePt;
350 }
351
352 LeafNodeType const * const * const mNodes;
353 CharLeafNodeType ** const mMaskNodes;
354 ValueType const mIsovalue;
355 }; // LabelBoundaryVoxels
356
357
358 template<typename LeafNodeType>
359 struct FlipRegionSign {
360 using ValueType = typename LeafNodeType::ValueType;
361
362
2/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
3 FlipRegionSign(LeafNodeType ** nodes) : mNodes(nodes) { }
363
364 270 void operator()(const tbb::blocked_range<size_t>& range) const {
365
2/2
✓ Branch 0 taken 852 times.
✓ Branch 1 taken 270 times.
1122 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
366 852 ValueType* values = const_cast<ValueType*>(&mNodes[n]->getValue(0));
367
2/2
✓ Branch 0 taken 436224 times.
✓ Branch 1 taken 852 times.
437076 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
368
2/2
✓ Branch 0 taken 166023 times.
✓ Branch 1 taken 270201 times.
602247 values[i] = values[i] < 0 ? 1 : -1;
369 }
370 }
371 270 }
372
373 LeafNodeType ** const mNodes;
374 }; // FlipRegionSign
375
376
377 template<typename LeafNodeType>
378 struct FindMinVoxelValue {
379
380 using ValueType = typename LeafNodeType::ValueType;
381
382 1 FindMinVoxelValue(LeafNodeType const * const * const leafnodes)
383 : minValue(std::numeric_limits<ValueType>::max())
384
1/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 , mNodes(leafnodes)
385 {
386 }
387
388 1 FindMinVoxelValue(FindMinVoxelValue& rhs, tbb::split)
389 : minValue(std::numeric_limits<ValueType>::max())
390 1 , mNodes(rhs.mNodes)
391 {
392 }
393
394 64 void operator()(const tbb::blocked_range<size_t>& range) {
395
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
128 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
396 64 const ValueType* data = mNodes[n]->buffer().data();
397
2/2
✓ Branch 0 taken 16384 times.
✓ Branch 1 taken 32 times.
32832 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
398
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 16345 times.
32846 minValue = std::min(minValue, data[i]);
399 }
400 }
401 }
402
403
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 void join(FindMinVoxelValue& rhs) { minValue = std::min(minValue, rhs.minValue); }
404
405 ValueType minValue;
406
407 LeafNodeType const * const * const mNodes;
408 }; // FindMinVoxelValue
409
410
411 template<typename InternalNodeType>
412 struct FindMinTileValue {
413
414 using ValueType = typename InternalNodeType::ValueType;
415
416 19 FindMinTileValue(InternalNodeType const * const * const nodes)
417 : minValue(std::numeric_limits<ValueType>::max())
418
2/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
19 , mNodes(nodes)
419 {
420 }
421
422 22 FindMinTileValue(FindMinTileValue& rhs, tbb::split)
423 : minValue(std::numeric_limits<ValueType>::max())
424 22 , mNodes(rhs.mNodes)
425 {
426 }
427
428 364 void operator()(const tbb::blocked_range<size_t>& range) {
429
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 182 times.
728 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
430 364 typename InternalNodeType::ValueAllCIter it = mNodes[n]->beginValueAll();
431
2/2
✓ Branch 0 taken 745362 times.
✓ Branch 1 taken 182 times.
1491088 for (; it; ++it) {
432
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 745286 times.
1490876 minValue = std::min(minValue, *it);
433 }
434 }
435 }
436
437
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 20 times.
24 void join(FindMinTileValue& rhs) { minValue = std::min(minValue, rhs.minValue); }
438
439 ValueType minValue;
440
441 InternalNodeType const * const * const mNodes;
442 }; // FindMinTileValue
443
444
445 template<typename LeafNodeType>
446 struct SDFVoxelsToFogVolume {
447
448 using ValueType = typename LeafNodeType::ValueType;
449
450 18 SDFVoxelsToFogVolume(LeafNodeType ** nodes, ValueType cutoffDistance)
451
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 : mNodes(nodes), mWeight(ValueType(1.0) / cutoffDistance)
452 {
453 }
454
455 4888 void operator()(const tbb::blocked_range<size_t>& range) const {
456
457
2/2
✓ Branch 0 taken 43828 times.
✓ Branch 1 taken 2444 times.
92544 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
458
459 87656 LeafNodeType& node = *mNodes[n];
460 node.setValuesOff();
461
462 87656 ValueType* values = node.buffer().data();
463
2/2
✓ Branch 0 taken 22439936 times.
✓ Branch 1 taken 43828 times.
44967528 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
464
2/2
✓ Branch 0 taken 9463053 times.
✓ Branch 1 taken 12976883 times.
44879872 values[i] = values[i] > ValueType(0.0) ? ValueType(0.0) : values[i] * mWeight;
465
2/2
✓ Branch 0 taken 9461133 times.
✓ Branch 1 taken 12978803 times.
44879872 if (values[i] > ValueType(0.0)) node.setValueOn(i);
466 }
467
468
2/2
✓ Branch 0 taken 11711 times.
✓ Branch 1 taken 32117 times.
87656 if (node.onVoxelCount() == 0) {
469
1/2
✓ Branch 0 taken 11711 times.
✗ Branch 1 not taken.
46844 delete mNodes[n];
470 23422 mNodes[n] = nullptr;
471 }
472 }
473 }
474
475 LeafNodeType ** const mNodes;
476 ValueType const mWeight;
477 }; // SDFVoxelsToFogVolume
478
479
480 template<typename TreeType, typename InternalNodeType>
481 struct SDFTilesToFogVolume {
482
483 18 SDFTilesToFogVolume(const TreeType& tree, InternalNodeType ** nodes)
484
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 : mTree(&tree), mNodes(nodes) { }
485
486 344 void operator()(const tbb::blocked_range<size_t>& range) const {
487
488 using ValueType = typename TreeType::ValueType;
489 344 tree::ValueAccessor<const TreeType> acc(*mTree);
490
491
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 172 times.
688 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
492 344 typename InternalNodeType::ValueAllIter it = mNodes[n]->beginValueAll();
493
2/2
✓ Branch 0 taken 672395 times.
✓ Branch 1 taken 172 times.
1345134 for (; it; ++it) {
494
4/8
✓ Branch 1 taken 672395 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 672395 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 99214 times.
✓ Branch 7 taken 573181 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1344790 if (acc.getValue(it.getCoord()) < ValueType(0.0)) {
495 it.setValue(ValueType(1.0));
496
1/2
✓ Branch 1 taken 99214 times.
✗ Branch 2 not taken.
198428 it.setValueOn(true);
497 }
498 }
499 }
500 }
501
502 TreeType const * const mTree;
503 InternalNodeType ** const mNodes;
504 }; // SDFTilesToFogVolume
505
506
507 template<typename TreeType>
508 struct FillMaskBoundary {
509
510 using ValueType = typename TreeType::ValueType;
511 using LeafNodeType = typename TreeType::LeafNodeType;
512 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
513 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
514
515 1 FillMaskBoundary(const TreeType& tree, ValueType isovalue, const BoolTreeType& fillMask,
516 const BoolLeafNodeType ** fillNodes, BoolLeafNodeType ** newNodes)
517 : mTree(&tree)
518 , mFillMask(&fillMask)
519 , mFillNodes(fillNodes)
520 , mNewNodes(newNodes)
521
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 , mIsovalue(isovalue)
522 {
523 }
524
525 256 void operator()(const tbb::blocked_range<size_t>& range) const {
526
527 256 tree::ValueAccessor<const BoolTreeType> maskAcc(*mFillMask);
528
1/2
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
256 tree::ValueAccessor<const TreeType> distAcc(*mTree);
529
530
1/2
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
256 std::unique_ptr<char[]> valueMask(new char[BoolLeafNodeType::SIZE]);
531
532
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 128 times.
514 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
533
534 258 mNewNodes[n] = nullptr;
535 258 const BoolLeafNodeType& node = *mFillNodes[n];
536 const Coord& origin = node.origin();
537
538 const bool denseNode = node.isDense();
539
540 // possible early out if the fill mask is dense
541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
258 if (denseNode) {
542
543 int denseNeighbors = 0;
544
545 const BoolLeafNodeType* neighborNode =
546 maskAcc.probeConstLeaf(origin.offsetBy(-1, 0, 0));
547 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
548
549 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(BoolLeafNodeType::DIM, 0, 0));
550 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
551
552 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, -1, 0));
553 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
554
555 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, BoolLeafNodeType::DIM, 0));
556 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
557
558 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, 0, -1));
559 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
560
561 neighborNode = maskAcc.probeConstLeaf(origin.offsetBy(0, 0, BoolLeafNodeType::DIM));
562 if (neighborNode && neighborNode->isDense()) ++denseNeighbors;
563
564 if (denseNeighbors == 6) continue;
565 }
566
567 // rest value mask
568 258 memset(valueMask.get(), 0, sizeof(char) * BoolLeafNodeType::SIZE);
569
570 const typename TreeType::LeafNodeType* distNode = distAcc.probeConstLeaf(origin);
571
572 // check internal voxel neighbors
573
574 bool earlyTermination = false;
575
576
1/2
✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
258 if (!denseNode) {
577
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 4 times.
258 if (distNode) {
578
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalInternalNeighborsP(valueMask.get(), node, *distNode);
579
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalInternalNeighborsN(valueMask.get(), node, *distNode);
580
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
8 } else if (distAcc.getValue(origin) > mIsovalue) {
581 8 earlyTermination = evalInternalNeighborsP(valueMask.get(), node);
582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
8 if (!earlyTermination) {
583 earlyTermination = evalInternalNeighborsN(valueMask.get(), node);
584 }
585 }
586 }
587
588 // check external voxel neighbors
589
590
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
8 if (!earlyTermination) {
591
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalExternalNeighborsX<true>(valueMask.get(), node, maskAcc, distAcc);
592
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalExternalNeighborsX<false>(valueMask.get(), node, maskAcc, distAcc);
593
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalExternalNeighborsY<true>(valueMask.get(), node, maskAcc, distAcc);
594
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalExternalNeighborsY<false>(valueMask.get(), node, maskAcc, distAcc);
595
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalExternalNeighborsZ<true>(valueMask.get(), node, maskAcc, distAcc);
596
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
250 evalExternalNeighborsZ<false>(valueMask.get(), node, maskAcc, distAcc);
597 }
598
599 // Export marked boundary voxels.
600
601 int numBoundaryValues = 0;
602
2/2
✓ Branch 0 taken 66048 times.
✓ Branch 1 taken 129 times.
132354 for (Index i = 0, I = BoolLeafNodeType::SIZE; i < I; ++i) {
603 132096 numBoundaryValues += valueMask[i] == 1;
604 }
605
606
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 106 times.
258 if (numBoundaryValues > 0) {
607
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 mNewNodes[n] = new BoolLeafNodeType(origin, false);
608
2/2
✓ Branch 0 taken 11776 times.
✓ Branch 1 taken 23 times.
23598 for (Index i = 0, I = BoolLeafNodeType::SIZE; i < I; ++i) {
609
2/2
✓ Branch 0 taken 1094 times.
✓ Branch 1 taken 10682 times.
23552 if (valueMask[i] == 1) mNewNodes[n]->setValueOn(i);
610 }
611 }
612 }
613 }
614
615 private:
616 // Check internal voxel neighbors in positive {x, y, z} directions.
617 250 void evalInternalNeighborsP(char* valueMask, const BoolLeafNodeType& node,
618 const LeafNodeType& distNode) const
619 {
620
2/2
✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 125 times.
2250 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
621 2000 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
622
2/2
✓ Branch 0 taken 8000 times.
✓ Branch 1 taken 1000 times.
18000 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
623 16000 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
624
2/2
✓ Branch 0 taken 56000 times.
✓ Branch 1 taken 8000 times.
128000 for (Index z = 0; z < BoolLeafNodeType::DIM - 1; ++z) {
625 112000 const Index pos = yPos + z;
626
627
3/4
✓ Branch 0 taken 56000 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 19132 times.
✓ Branch 4 taken 36868 times.
112000 if (valueMask[pos] != 0 || !node.isValueOn(pos)) continue;
628
629
3/4
✓ Branch 1 taken 705 times.
✓ Branch 2 taken 36163 times.
✓ Branch 4 taken 705 times.
✗ Branch 5 not taken.
73736 if (!node.isValueOn(pos + 1) && distNode.getValue(pos + 1) > mIsovalue) {
630 1410 valueMask[pos] = 1;
631 }
632 }
633 }
634 }
635
636
2/2
✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 125 times.
2250 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
637 2000 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
638
2/2
✓ Branch 0 taken 7000 times.
✓ Branch 1 taken 1000 times.
16000 for (Index y = 0; y < BoolLeafNodeType::DIM - 1; ++y) {
639 14000 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
640
2/2
✓ Branch 0 taken 56000 times.
✓ Branch 1 taken 7000 times.
126000 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
641 112000 const Index pos = yPos + z;
642
643
4/4
✓ Branch 0 taken 55387 times.
✓ Branch 1 taken 613 times.
✓ Branch 3 taken 36225 times.
✓ Branch 4 taken 19162 times.
112000 if (valueMask[pos] != 0 || !node.isValueOn(pos)) continue;
644
645
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36225 times.
72450 if (!node.isValueOn(pos + BoolLeafNodeType::DIM) &&
646 distNode.getValue(pos + BoolLeafNodeType::DIM) > mIsovalue) {
647 valueMask[pos] = 1;
648 }
649 }
650 }
651 }
652
653
2/2
✓ Branch 0 taken 875 times.
✓ Branch 1 taken 125 times.
2000 for (Index x = 0; x < BoolLeafNodeType::DIM - 1; ++x) {
654 1750 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
655
2/2
✓ Branch 0 taken 7000 times.
✓ Branch 1 taken 875 times.
15750 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
656 14000 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
657
2/2
✓ Branch 0 taken 56000 times.
✓ Branch 1 taken 7000 times.
126000 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
658 112000 const Index pos = yPos + z;
659
660
4/4
✓ Branch 0 taken 55387 times.
✓ Branch 1 taken 613 times.
✓ Branch 3 taken 36225 times.
✓ Branch 4 taken 19162 times.
112000 if (valueMask[pos] != 0 || !node.isValueOn(pos)) continue;
661
662
2/2
✓ Branch 1 taken 961 times.
✓ Branch 2 taken 35264 times.
72450 if (!node.isValueOn(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM) &&
663 (distNode.getValue(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)
664
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 961 times.
1922 > mIsovalue))
665 {
666 valueMask[pos] = 1;
667 }
668 }
669 }
670 }
671 }
672
673 8 bool evalInternalNeighborsP(char* valueMask, const BoolLeafNodeType& node) const {
674
675
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
676 8 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
677
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
678 8 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
679
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 for (Index z = 0; z < BoolLeafNodeType::DIM - 1; ++z) {
680 8 const Index pos = yPos + z;
681
682
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 if (node.isValueOn(pos) && !node.isValueOn(pos + 1)) {
683 8 valueMask[pos] = 1;
684 8 return true;
685 }
686 }
687 }
688 }
689
690 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
691 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
692 for (Index y = 0; y < BoolLeafNodeType::DIM - 1; ++y) {
693 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
694 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
695 const Index pos = yPos + z;
696
697 if (node.isValueOn(pos) && !node.isValueOn(pos + BoolLeafNodeType::DIM)) {
698 valueMask[pos] = 1;
699 return true;
700 }
701 }
702 }
703 }
704
705 for (Index x = 0; x < BoolLeafNodeType::DIM - 1; ++x) {
706 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
707 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
708 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
709 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
710 const Index pos = yPos + z;
711
712 if (node.isValueOn(pos) &&
713 !node.isValueOn(pos + BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)) {
714 valueMask[pos] = 1;
715 return true;
716 }
717 }
718 }
719 }
720
721 return false;
722 }
723
724 // Check internal voxel neighbors in negative {x, y, z} directions.
725
726 250 void evalInternalNeighborsN(char* valueMask, const BoolLeafNodeType& node,
727 const LeafNodeType& distNode) const
728 {
729
2/2
✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 125 times.
2250 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
730 2000 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
731
2/2
✓ Branch 0 taken 8000 times.
✓ Branch 1 taken 1000 times.
18000 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
732 16000 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
733
2/2
✓ Branch 0 taken 56000 times.
✓ Branch 1 taken 8000 times.
128000 for (Index z = 1; z < BoolLeafNodeType::DIM; ++z) {
734 112000 const Index pos = yPos + z;
735
736
3/4
✓ Branch 0 taken 56000 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 16954 times.
✓ Branch 4 taken 39046 times.
112000 if (valueMask[pos] != 0 || !node.isValueOn(pos)) continue;
737
738
3/4
✓ Branch 1 taken 2883 times.
✓ Branch 2 taken 36163 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2883 times.
78092 if (!node.isValueOn(pos - 1) && distNode.getValue(pos - 1) > mIsovalue) {
739 valueMask[pos] = 1;
740 }
741 }
742 }
743 }
744
745
2/2
✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 125 times.
2250 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
746 2000 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
747
2/2
✓ Branch 0 taken 7000 times.
✓ Branch 1 taken 1000 times.
16000 for (Index y = 1; y < BoolLeafNodeType::DIM; ++y) {
748 14000 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
749
2/2
✓ Branch 0 taken 56000 times.
✓ Branch 1 taken 7000 times.
126000 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
750 112000 const Index pos = yPos + z;
751
752
4/4
✓ Branch 0 taken 55356 times.
✓ Branch 1 taken 644 times.
✓ Branch 3 taken 38612 times.
✓ Branch 4 taken 16744 times.
112000 if (valueMask[pos] != 0 || !node.isValueOn(pos)) continue;
753
754
2/2
✓ Branch 1 taken 2387 times.
✓ Branch 2 taken 36225 times.
77224 if (!node.isValueOn(pos - BoolLeafNodeType::DIM) &&
755
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2387 times.
4774 distNode.getValue(pos - BoolLeafNodeType::DIM) > mIsovalue) {
756 valueMask[pos] = 1;
757 }
758 }
759 }
760 }
761
762
2/2
✓ Branch 0 taken 875 times.
✓ Branch 1 taken 125 times.
2000 for (Index x = 1; x < BoolLeafNodeType::DIM; ++x) {
763 1750 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
764
2/2
✓ Branch 0 taken 7000 times.
✓ Branch 1 taken 875 times.
15750 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
765 14000 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
766
2/2
✓ Branch 0 taken 56000 times.
✓ Branch 1 taken 7000 times.
126000 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
767 112000 const Index pos = yPos + z;
768
769
4/4
✓ Branch 0 taken 55356 times.
✓ Branch 1 taken 644 times.
✓ Branch 3 taken 37651 times.
✓ Branch 4 taken 17705 times.
112000 if (valueMask[pos] != 0 || !node.isValueOn(pos)) continue;
770
771
2/2
✓ Branch 1 taken 2387 times.
✓ Branch 2 taken 35264 times.
75302 if (!node.isValueOn(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM) &&
772 (distNode.getValue(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)
773
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2387 times.
4774 > mIsovalue))
774 {
775 valueMask[pos] = 1;
776 }
777 }
778 }
779 }
780 }
781
782
783 bool evalInternalNeighborsN(char* valueMask, const BoolLeafNodeType& node) const {
784
785 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
786 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
787 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
788 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
789 for (Index z = 1; z < BoolLeafNodeType::DIM; ++z) {
790 const Index pos = yPos + z;
791
792 if (node.isValueOn(pos) && !node.isValueOn(pos - 1)) {
793 valueMask[pos] = 1;
794 return true;
795 }
796 }
797 }
798 }
799
800 for (Index x = 0; x < BoolLeafNodeType::DIM; ++x) {
801 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
802 for (Index y = 1; y < BoolLeafNodeType::DIM; ++y) {
803 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
804 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
805 const Index pos = yPos + z;
806
807 if (node.isValueOn(pos) && !node.isValueOn(pos - BoolLeafNodeType::DIM)) {
808 valueMask[pos] = 1;
809 return true;
810 }
811 }
812 }
813 }
814
815 for (Index x = 1; x < BoolLeafNodeType::DIM; ++x) {
816 const Index xPos = x << (2 * BoolLeafNodeType::LOG2DIM);
817 for (Index y = 0; y < BoolLeafNodeType::DIM; ++y) {
818 const Index yPos = xPos + (y << BoolLeafNodeType::LOG2DIM);
819 for (Index z = 0; z < BoolLeafNodeType::DIM; ++z) {
820 const Index pos = yPos + z;
821
822 if (node.isValueOn(pos) &&
823 !node.isValueOn(pos - BoolLeafNodeType::DIM * BoolLeafNodeType::DIM)) {
824 valueMask[pos] = 1;
825 return true;
826 }
827 }
828 }
829 }
830
831 return false;
832 }
833
834
835 // Check external voxel neighbors
836
837 // If UpWind is true check the X+ oriented node face, else the X- oriented face.
838 template<bool UpWind>
839 500 void evalExternalNeighborsX(char* valueMask, const BoolLeafNodeType& node,
840 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
841 const tree::ValueAccessor<const TreeType>& distAcc) const {
842
843 const Coord& origin = node.origin();
844 Coord ijk(0, 0, 0), nijk;
845 int step = -1;
846
847 if (UpWind) {
848 step = 1;
849 ijk[0] = int(BoolLeafNodeType::DIM) - 1;
850 }
851
852 const Index xPos = ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM));
853
854
2/2
✓ Branch 0 taken 2000 times.
✓ Branch 1 taken 250 times.
4500 for (ijk[1] = 0; ijk[1] < int(BoolLeafNodeType::DIM); ++ijk[1]) {
855 4000 const Index yPos = xPos + (ijk[1] << int(BoolLeafNodeType::LOG2DIM));
856
857
2/2
✓ Branch 0 taken 16000 times.
✓ Branch 1 taken 2000 times.
36000 for (ijk[2] = 0; ijk[2] < int(BoolLeafNodeType::DIM); ++ijk[2]) {
858 32000 const Index pos = yPos + ijk[2];
859
860
4/4
✓ Branch 0 taken 15847 times.
✓ Branch 1 taken 153 times.
✓ Branch 3 taken 9606 times.
✓ Branch 4 taken 6241 times.
32000 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
861
862 19212 nijk = origin + ijk.offsetBy(step, 0, 0);
863
864
3/4
✓ Branch 1 taken 658 times.
✓ Branch 2 taken 8948 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 658 times.
19212 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
865 valueMask[pos] = 1;
866 }
867 }
868 }
869 }
870 }
871
872 // If UpWind is true check the Y+ oriented node face, else the Y- oriented face.
873 template<bool UpWind>
874 500 void evalExternalNeighborsY(char* valueMask, const BoolLeafNodeType& node,
875 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
876 const tree::ValueAccessor<const TreeType>& distAcc) const {
877
878 const Coord& origin = node.origin();
879 Coord ijk(0, 0, 0), nijk;
880 int step = -1;
881
882 if (UpWind) {
883 step = 1;
884 ijk[1] = int(BoolLeafNodeType::DIM) - 1;
885 }
886
887 const Index yPos = ijk[1] << int(BoolLeafNodeType::LOG2DIM);
888
889
2/2
✓ Branch 0 taken 2000 times.
✓ Branch 1 taken 250 times.
4500 for (ijk[0] = 0; ijk[0] < int(BoolLeafNodeType::DIM); ++ijk[0]) {
890 4000 const Index xPos = yPos + (ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM)));
891
892
2/2
✓ Branch 0 taken 16000 times.
✓ Branch 1 taken 2000 times.
36000 for (ijk[2] = 0; ijk[2] < int(BoolLeafNodeType::DIM); ++ijk[2]) {
893 32000 const Index pos = xPos + ijk[2];
894
895
4/4
✓ Branch 0 taken 15847 times.
✓ Branch 1 taken 153 times.
✓ Branch 3 taken 8645 times.
✓ Branch 4 taken 7202 times.
32000 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
896
897 17290 nijk = origin + ijk.offsetBy(0, step, 0);
898
3/4
✓ Branch 1 taken 1043 times.
✓ Branch 2 taken 7602 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1043 times.
17290 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
899 valueMask[pos] = 1;
900 }
901 }
902 }
903 }
904 }
905
906 // If UpWind is true check the Z+ oriented node face, else the Z- oriented face.
907 template<bool UpWind>
908 500 void evalExternalNeighborsZ(char* valueMask, const BoolLeafNodeType& node,
909 const tree::ValueAccessor<const BoolTreeType>& maskAcc,
910 const tree::ValueAccessor<const TreeType>& distAcc) const {
911
912 const Coord& origin = node.origin();
913 Coord ijk(0, 0, 0), nijk;
914 int step = -1;
915
916 if (UpWind) {
917 step = 1;
918 ijk[2] = int(BoolLeafNodeType::DIM) - 1;
919 }
920
921
2/2
✓ Branch 0 taken 2000 times.
✓ Branch 1 taken 250 times.
4500 for (ijk[0] = 0; ijk[0] < int(BoolLeafNodeType::DIM); ++ijk[0]) {
922 4000 const Index xPos = ijk[0] << (2 * int(BoolLeafNodeType::LOG2DIM));
923
924
2/2
✓ Branch 0 taken 16000 times.
✓ Branch 1 taken 2000 times.
36000 for (ijk[1] = 0; ijk[1] < int(BoolLeafNodeType::DIM); ++ijk[1]) {
925 32000 const Index pos = ijk[2] + xPos + (ijk[1] << int(BoolLeafNodeType::LOG2DIM));
926
927
4/4
✓ Branch 0 taken 15295 times.
✓ Branch 1 taken 705 times.
✓ Branch 3 taken 8273 times.
✓ Branch 4 taken 7022 times.
32000 if (valueMask[pos] == 0 && node.isValueOn(pos)) {
928
929 16546 nijk = origin + ijk.offsetBy(0, 0, step);
930
4/4
✓ Branch 1 taken 770 times.
✓ Branch 2 taken 7503 times.
✓ Branch 4 taken 385 times.
✓ Branch 5 taken 385 times.
16546 if (!maskAcc.isValueOn(nijk) && distAcc.getValue(nijk) > mIsovalue) {
931 770 valueMask[pos] = 1;
932 }
933 }
934 }
935 }
936 }
937
938 //////////
939
940 TreeType const * const mTree;
941 BoolTreeType const * const mFillMask;
942 BoolLeafNodeType const * const * const mFillNodes;
943 BoolLeafNodeType ** const mNewNodes;
944 ValueType const mIsovalue;
945 }; // FillMaskBoundary
946
947
948 /// @brief Constructs a memory light char tree that represents the exterior region with @c +1
949 /// and the interior regions with @c -1.
950 template <class TreeType>
951 typename TreeType::template ValueConverter<char>::Type::Ptr
952
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 computeEnclosedRegionMask(const TreeType& tree, typename TreeType::ValueType isovalue,
953 const typename TreeType::template ValueConverter<bool>::Type* fillMask)
954 {
955 using LeafNodeType = typename TreeType::LeafNodeType;
956 using RootNodeType = typename TreeType::RootNodeType;
957 using NodeChainType = typename RootNodeType::NodeChainType;
958 using InternalNodeType = typename NodeChainType::template Get<1>;
959
960 using CharTreeType = typename TreeType::template ValueConverter<char>::Type;
961 using CharLeafNodeType = typename CharTreeType::LeafNodeType;
962
963 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
964 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
965
966 const TreeType* treePt = &tree;
967
968 size_t numLeafNodes = 0, numInternalNodes = 0;
969
970 std::vector<const LeafNodeType*> nodes;
971 std::vector<size_t> leafnodeCount;
972
973 {
974 // compute the prefix sum of the leafnode count in each internal node.
975 std::vector<const InternalNodeType*> internalNodes;
976 treePt->getNodes(internalNodes);
977
978 numInternalNodes = internalNodes.size();
979
980
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 leafnodeCount.push_back(0);
981
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
44 for (size_t n = 0; n < numInternalNodes; ++n) {
982
1/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
40 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
983 }
984
985 4 numLeafNodes = leafnodeCount.back();
986
987 // extract all leafnodes
988
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 nodes.reserve(numLeafNodes);
989
990
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
44 for (size_t n = 0; n < numInternalNodes; ++n) {
991
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
40 internalNodes[n]->getNodes(nodes);
992 }
993 }
994
995 // create mask leafnodes
996
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
4 std::unique_ptr<CharLeafNodeType*[]> maskNodes(new CharLeafNodeType*[numLeafNodes]);
997
998
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
999 LabelBoundaryVoxels<LeafNodeType>(isovalue, nodes.data(), maskNodes.get()));
1000
1001 // create mask grid
1002
1/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8 typename CharTreeType::Ptr maskTree(new CharTreeType(1));
1003
1004
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 PopulateTree<CharTreeType> populate(*maskTree, maskNodes.get(), leafnodeCount.data(), 1);
1005
3/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
4 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
1006
1007 // optionally evaluate the fill mask
1008
1009 std::vector<CharLeafNodeType*> extraMaskNodes;
1010
1011
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
4 if (fillMask) {
1012
1013 std::vector<const BoolLeafNodeType*> fillMaskNodes;
1014 fillMask->getNodes(fillMaskNodes);
1015
1016 std::unique_ptr<BoolLeafNodeType*[]> boundaryMaskNodes(
1017
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 new BoolLeafNodeType*[fillMaskNodes.size()]);
1018
1019
2/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2 tbb::parallel_for(tbb::blocked_range<size_t>(0, fillMaskNodes.size()),
1020 FillMaskBoundary<TreeType>(tree, isovalue, *fillMask, fillMaskNodes.data(),
1021 boundaryMaskNodes.get()));
1022
1023 tree::ValueAccessor<CharTreeType> maskAcc(*maskTree);
1024
1025
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 1 times.
260 for (size_t n = 0, N = fillMaskNodes.size(); n < N; ++n) {
1026
1027
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 23 times.
258 if (boundaryMaskNodes[n] == nullptr) continue;
1028
1029 const BoolLeafNodeType& boundaryNode = *boundaryMaskNodes[n];
1030 const Coord& origin = boundaryNode.origin();
1031
1032 46 CharLeafNodeType* maskNodePt = maskAcc.probeLeaf(origin);
1033
1034
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
46 if (!maskNodePt) {
1035
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 maskNodePt = maskAcc.touchLeaf(origin);
1036
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 extraMaskNodes.push_back(maskNodePt);
1037 }
1038
1039
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 char* data = maskNodePt->buffer().data();
1040
1041 typename BoolLeafNodeType::ValueOnCIter it = boundaryNode.cbeginValueOn();
1042
2/2
✓ Branch 0 taken 1094 times.
✓ Branch 1 taken 23 times.
2234 for (; it; ++it) {
1043
1/2
✓ Branch 0 taken 1094 times.
✗ Branch 1 not taken.
2188 if (data[it.pos()] != 0) data[it.pos()] = -1;
1044 }
1045
1046
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
46 delete boundaryMaskNodes[n];
1047 }
1048 }
1049
1050 // eliminate enclosed regions
1051
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 tools::traceExteriorBoundaries(*maskTree);
1052
1053 // flip voxel sign to negative inside and positive outside.
1054
3/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
4 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
1055 FlipRegionSign<CharLeafNodeType>(maskNodes.get()));
1056
1057
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
4 if (!extraMaskNodes.empty()) {
1058
1/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 tbb::parallel_for(tbb::blocked_range<size_t>(0, extraMaskNodes.size()),
1059 FlipRegionSign<CharLeafNodeType>(extraMaskNodes.data()));
1060 }
1061
1062 // propagate sign information into tile region
1063
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 tools::signedFloodFill(*maskTree);
1064
1065 4 return maskTree;
1066 } // computeEnclosedRegionMask()
1067
1068
1069 template <class TreeType>
1070 typename TreeType::template ValueConverter<bool>::Type::Ptr
1071 60 computeInteriorMask(const TreeType& tree, typename TreeType::ValueType iso)
1072 {
1073 using ValueType = typename TreeType::ValueType;
1074 using LeafNodeType = typename TreeType::LeafNodeType;
1075 using RootNodeType = typename TreeType::RootNodeType;
1076 using NodeChainType = typename RootNodeType::NodeChainType;
1077 using InternalNodeType = typename NodeChainType::template Get<1>;
1078
1079 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
1080 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
1081 using BoolRootNodeType = typename BoolTreeType::RootNodeType;
1082 using BoolNodeChainType = typename BoolRootNodeType::NodeChainType;
1083 using BoolInternalNodeType = typename BoolNodeChainType::template Get<1>;
1084
1085 /////
1086
1087 // Clamp the isovalue to the level set's background value minus epsilon.
1088 // (In a valid narrow-band level set, all voxels, including background voxels,
1089 // have values less than or equal to the background value, so an isovalue
1090 // greater than or equal to the background value would produce a mask with
1091 // effectively infinite extent.)
1092
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
60 iso = std::min(iso,
1093
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
60 static_cast<ValueType>(tree.background() - math::Tolerance<ValueType>::value()));
1094
1095 size_t numLeafNodes = 0, numInternalNodes = 0;
1096
1097 std::vector<const LeafNodeType*> nodes;
1098 std::vector<size_t> leafnodeCount;
1099
1100 {
1101 // compute the prefix sum of the leafnode count in each internal node.
1102 std::vector<const InternalNodeType*> internalNodes;
1103 tree.getNodes(internalNodes);
1104
1105 numInternalNodes = internalNodes.size();
1106
1107
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 leafnodeCount.push_back(0);
1108
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 30 times.
424 for (size_t n = 0; n < numInternalNodes; ++n) {
1109
1/4
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
364 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
1110 }
1111
1112 60 numLeafNodes = leafnodeCount.back();
1113
1114 // extract all leafnodes
1115
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 nodes.reserve(numLeafNodes);
1116
1117
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 30 times.
424 for (size_t n = 0; n < numInternalNodes; ++n) {
1118
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
364 internalNodes[n]->getNodes(nodes);
1119 }
1120 }
1121
1122 // create mask leafnodes
1123
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
60 std::unique_ptr<BoolLeafNodeType*[]> maskNodes(new BoolLeafNodeType*[numLeafNodes]);
1124
1125
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 tbb::parallel_for(tbb::blocked_range<size_t>(0, numLeafNodes),
1126 MaskInteriorVoxels<LeafNodeType>(iso, nodes.data(), maskNodes.get()));
1127
1128
1129 // create mask grid
1130
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
120 typename BoolTreeType::Ptr maskTree(new BoolTreeType(false));
1131
1132
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 PopulateTree<BoolTreeType> populate(*maskTree, maskNodes.get(), leafnodeCount.data(), false);
1133
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
60 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
1134
1135
1136 // evaluate tile values
1137 std::vector<BoolInternalNodeType*> internalMaskNodes;
1138 maskTree->getNodes(internalMaskNodes);
1139
1140
2/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
60 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalMaskNodes.size()),
1141 MaskInteriorTiles<TreeType, BoolInternalNodeType>(iso, tree, internalMaskNodes.data()));
1142
1143 tree::ValueAccessor<const TreeType> acc(tree);
1144
1145
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 typename BoolTreeType::ValueAllIter it(*maskTree);
1146 60 it.setMaxDepth(BoolTreeType::ValueAllIter::LEAF_DEPTH - 2);
1147
1148
2/2
✓ Branch 0 taken 4882279 times.
✓ Branch 1 taken 30 times.
9764618 for ( ; it; ++it) {
1149
2/4
✓ Branch 1 taken 4882279 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4882279 times.
9764558 if (acc.getValue(it.getCoord()) < iso) {
1150 it.setValue(true);
1151 it.setActiveState(true);
1152 }
1153 }
1154
1155 60 return maskTree;
1156 } // computeInteriorMask()
1157
1158
1159 template<typename InputTreeType>
1160 struct MaskIsovalueCrossingVoxels
1161 {
1162 using InputValueType = typename InputTreeType::ValueType;
1163 using InputLeafNodeType = typename InputTreeType::LeafNodeType;
1164 using BoolTreeType = typename InputTreeType::template ValueConverter<bool>::Type;
1165 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
1166
1167 6 MaskIsovalueCrossingVoxels(
1168 const InputTreeType& inputTree,
1169 const std::vector<const InputLeafNodeType*>& inputLeafNodes,
1170 BoolTreeType& maskTree,
1171 InputValueType iso)
1172 : mInputAccessor(inputTree)
1173
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
6 , mInputNodes(!inputLeafNodes.empty() ? &inputLeafNodes.front() : nullptr)
1174
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 , mMaskTree(false)
1175 , mMaskAccessor(maskTree)
1176 6 , mIsovalue(iso)
1177 {
1178 }
1179
1180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
14 MaskIsovalueCrossingVoxels(MaskIsovalueCrossingVoxels& rhs, tbb::split)
1181 : mInputAccessor(rhs.mInputAccessor.tree())
1182 14 , mInputNodes(rhs.mInputNodes)
1183
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
14 , mMaskTree(false)
1184 , mMaskAccessor(mMaskTree)
1185 14 , mIsovalue(rhs.mIsovalue)
1186 {
1187 }
1188
1189 274 void operator()(const tbb::blocked_range<size_t>& range) {
1190
1191 274 const InputValueType iso = mIsovalue;
1192 Coord ijk(0, 0, 0);
1193
1194 BoolLeafNodeType* maskNodePt = nullptr;
1195
1196
3/4
✓ Branch 0 taken 274 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✓ Branch 3 taken 137 times.
548 for (size_t n = range.begin(); mInputNodes && (n != range.end()); ++n) {
1197
1198 274 const InputLeafNodeType& node = *mInputNodes[n];
1199
1200
1/2
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
274 if (!maskNodePt) maskNodePt = new BoolLeafNodeType(node.origin(), false);
1201 else maskNodePt->setOrigin(node.origin());
1202
1203 bool collectedData = false;
1204
1205
2/2
✓ Branch 0 taken 23140 times.
✓ Branch 1 taken 137 times.
46554 for (typename InputLeafNodeType::ValueOnCIter it = node.cbeginValueOn(); it; ++it) {
1206
1207 46280 bool isUnder = *it < iso;
1208
1209 46280 ijk = it.getCoord();
1210
1211 46280 ++ijk[2];
1212 46280 bool signChange = isUnder != (mInputAccessor.getValue(ijk) < iso); // +z edge
1213 46280 --ijk[2];
1214
1215
2/2
✓ Branch 0 taken 21460 times.
✓ Branch 1 taken 1680 times.
46280 if (!signChange) {
1216 42920 --ijk[2];
1217 42920 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso); // -z edge
1218 42920 ++ijk[2];
1219 }
1220
1221
2/2
✓ Branch 0 taken 19780 times.
✓ Branch 1 taken 3360 times.
46280 if (!signChange) {
1222 39560 ++ijk[1];
1223 39560 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso); // +y edge
1224 39560 --ijk[1];
1225 }
1226
1227
2/2
✓ Branch 0 taken 18180 times.
✓ Branch 1 taken 4960 times.
46280 if (!signChange) {
1228 36360 --ijk[1];
1229 36360 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso); // -y edge
1230 36360 ++ijk[1];
1231 }
1232
1233
2/2
✓ Branch 0 taken 16580 times.
✓ Branch 1 taken 6560 times.
46280 if (!signChange) {
1234 33160 ++ijk[0];
1235 33160 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso); // +x edge
1236 33160 --ijk[0];
1237 }
1238
1239
2/2
✓ Branch 0 taken 14976 times.
✓ Branch 1 taken 8164 times.
46280 if (!signChange) {
1240 29952 --ijk[0];
1241 29952 signChange = isUnder != (mInputAccessor.getValue(ijk) < iso); // -x edge
1242 29952 ++ijk[0];
1243 }
1244
1245
2/2
✓ Branch 0 taken 9768 times.
✓ Branch 1 taken 13372 times.
46280 if (signChange) {
1246 collectedData = true;
1247 19536 maskNodePt->setValueOn(it.pos(), true);
1248 }
1249 }
1250
1251
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 40 times.
274 if (collectedData) {
1252 194 mMaskAccessor.addLeaf(maskNodePt);
1253 maskNodePt = nullptr;
1254 }
1255 }
1256
1257
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 97 times.
274 if (maskNodePt) delete maskNodePt;
1258 }
1259
1260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
14 void join(MaskIsovalueCrossingVoxels& rhs) {
1261 14 mMaskAccessor.tree().merge(rhs.mMaskAccessor.tree());
1262 }
1263
1264 private:
1265 tree::ValueAccessor<const InputTreeType> mInputAccessor;
1266 InputLeafNodeType const * const * const mInputNodes;
1267
1268 BoolTreeType mMaskTree;
1269 tree::ValueAccessor<BoolTreeType> mMaskAccessor;
1270
1271 InputValueType mIsovalue;
1272 }; // MaskIsovalueCrossingVoxels
1273
1274
1275 ////////////////////////////////////////
1276
1277
1278 template<typename NodeType>
1279 766 struct NodeMaskSegment
1280 {
1281 using Ptr = SharedPtr<NodeMaskSegment>;
1282 using NodeMaskType = typename NodeType::NodeMaskType;
1283
1284
1/2
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
1532 NodeMaskSegment() : connections(), mask(false), origin(0,0,0), visited(false) {}
1285
1286 std::vector<NodeMaskSegment*> connections;
1287 NodeMaskType mask;
1288 Coord origin;
1289 bool visited;
1290 }; // struct NodeMaskSegment
1291
1292
1293 template<typename NodeType>
1294 void
1295 766 nodeMaskSegmentation(const NodeType& node,
1296 std::vector<typename NodeMaskSegment<NodeType>::Ptr>& segments)
1297 {
1298 using NodeMaskType = typename NodeType::NodeMaskType;
1299 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1300 using NodeMaskSegmentTypePtr = typename NodeMaskSegmentType::Ptr;
1301
1302 NodeMaskType nodeMask(node.getValueMask());
1303 std::deque<Index> indexList;
1304
1305
2/2
✓ Branch 0 taken 766 times.
✓ Branch 1 taken 766 times.
2298 while (!nodeMask.isOff()) {
1306
1307
1/2
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
766 NodeMaskSegmentTypePtr segment(new NodeMaskSegmentType());
1308 766 segment->origin = node.origin();
1309
1310 766 NodeMaskType& mask = segment->mask;
1311
1312
2/6
✓ Branch 2 taken 766 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 766 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
766 indexList.push_back(nodeMask.findFirstOn());
1313 766 nodeMask.setOff(indexList.back()); // mark as visited
1314 Coord ijk(0, 0, 0);
1315
1316
2/2
✓ Branch 0 taken 234480 times.
✓ Branch 1 taken 766 times.
235246 while (!indexList.empty()) {
1317
1318
2/2
✓ Branch 0 taken 233334 times.
✓ Branch 1 taken 1146 times.
234480 const Index pos = indexList.back();
1319 indexList.pop_back();
1320
1321
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 234480 times.
234480 if (mask.isOn(pos)) continue;
1322 234480 mask.setOn(pos);
1323
1324 234480 ijk = NodeType::offsetToLocalCoord(pos);
1325
1326 234480 Index npos = pos - 1;
1327
4/4
✓ Branch 0 taken 203488 times.
✓ Branch 1 taken 30992 times.
✓ Branch 3 taken 27824 times.
✓ Branch 4 taken 175664 times.
234480 if (ijk[2] != 0 && nodeMask.isOn(npos)) {
1328 27824 nodeMask.setOff(npos);
1329
1/2
✓ Branch 1 taken 27824 times.
✗ Branch 2 not taken.
27824 indexList.push_back(npos);
1330 }
1331
1332 234480 npos = pos + 1;
1333
4/4
✓ Branch 0 taken 206253 times.
✓ Branch 1 taken 28227 times.
✓ Branch 3 taken 63338 times.
✓ Branch 4 taken 142915 times.
234480 if (ijk[2] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1334 63338 nodeMask.setOff(npos);
1335
1/2
✓ Branch 1 taken 63338 times.
✗ Branch 2 not taken.
63338 indexList.push_back(npos);
1336 }
1337
1338 234480 npos = pos - NodeType::DIM;
1339
4/4
✓ Branch 0 taken 203488 times.
✓ Branch 1 taken 30992 times.
✓ Branch 3 taken 31514 times.
✓ Branch 4 taken 171974 times.
234480 if (ijk[1] != 0 && nodeMask.isOn(npos)) {
1340 31514 nodeMask.setOff(npos);
1341
1/2
✓ Branch 1 taken 31514 times.
✗ Branch 2 not taken.
31514 indexList.push_back(npos);
1342 }
1343
1344 234480 npos = pos + NodeType::DIM;
1345
4/4
✓ Branch 0 taken 206253 times.
✓ Branch 1 taken 28227 times.
✓ Branch 3 taken 32645 times.
✓ Branch 4 taken 173608 times.
234480 if (ijk[1] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1346 32645 nodeMask.setOff(npos);
1347
1/2
✓ Branch 1 taken 32645 times.
✗ Branch 2 not taken.
32645 indexList.push_back(npos);
1348 }
1349
1350 234480 npos = pos - NodeType::DIM * NodeType::DIM;
1351
4/4
✓ Branch 0 taken 203420 times.
✓ Branch 1 taken 31060 times.
✓ Branch 3 taken 38121 times.
✓ Branch 4 taken 165299 times.
234480 if (ijk[0] != 0 && nodeMask.isOn(npos)) {
1352 38121 nodeMask.setOff(npos);
1353
1/2
✓ Branch 1 taken 38121 times.
✗ Branch 2 not taken.
38121 indexList.push_back(npos);
1354 }
1355
1356 234480 npos = pos + NodeType::DIM * NodeType::DIM;
1357
4/4
✓ Branch 0 taken 206638 times.
✓ Branch 1 taken 27842 times.
✓ Branch 3 taken 40272 times.
✓ Branch 4 taken 166366 times.
234480 if (ijk[0] != (NodeType::DIM - 1) && nodeMask.isOn(npos)) {
1358 40272 nodeMask.setOff(npos);
1359
1/2
✓ Branch 1 taken 40272 times.
✗ Branch 2 not taken.
40272 indexList.push_back(npos);
1360 }
1361
1362 }
1363
1364
1/2
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
766 segments.push_back(segment);
1365 }
1366 766 }
1367
1368
1369 template<typename NodeType>
1370 struct SegmentNodeMask
1371 {
1372 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1373 using NodeMaskSegmentTypePtr = typename NodeMaskSegmentType::Ptr;
1374 using NodeMaskSegmentVector = typename std::vector<NodeMaskSegmentTypePtr>;
1375
1376
2/40
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
3 SegmentNodeMask(std::vector<NodeType*>& nodes, NodeMaskSegmentVector* nodeMaskArray)
1377
2/40
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
3 : mNodes(!nodes.empty() ? &nodes.front() : nullptr)
1378
2/40
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✓ Branch 43 taken 2 times.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
3 , mNodeMaskArray(nodeMaskArray)
1379 {
1380 }
1381
1382 356 void operator()(const tbb::blocked_range<size_t>& range) const {
1383
2/2
✓ Branch 0 taken 766 times.
✓ Branch 1 taken 356 times.
1122 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1384 766 NodeType& node = *mNodes[n];
1385 766 nodeMaskSegmentation(node, mNodeMaskArray[n]);
1386
1387 // hack origin data to store array offset
1388 Coord& origin = const_cast<Coord&>(node.origin());
1389 766 origin[0] = static_cast<int>(n);
1390 }
1391 356 }
1392
1393 NodeType * const * const mNodes;
1394 NodeMaskSegmentVector * const mNodeMaskArray;
1395 }; // struct SegmentNodeMask
1396
1397
1398 template<typename TreeType, typename NodeType>
1399 struct ConnectNodeMaskSegments
1400 {
1401 using NodeMaskType = typename NodeType::NodeMaskType;
1402 using NodeMaskSegmentType = NodeMaskSegment<NodeType>;
1403 using NodeMaskSegmentTypePtr = typename NodeMaskSegmentType::Ptr;
1404 using NodeMaskSegmentVector = typename std::vector<NodeMaskSegmentTypePtr>;
1405
1406 3 ConnectNodeMaskSegments(const TreeType& tree, NodeMaskSegmentVector* nodeMaskArray)
1407 : mTree(&tree)
1408
2/40
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✓ Branch 43 taken 2 times.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
3 , mNodeMaskArray(nodeMaskArray)
1409 {
1410 }
1411
1412 353 void operator()(const tbb::blocked_range<size_t>& range) const {
1413
1414 353 tree::ValueAccessor<const TreeType> acc(*mTree);
1415
1416
2/2
✓ Branch 0 taken 766 times.
✓ Branch 1 taken 353 times.
1119 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1417
1418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 766 times.
766 NodeMaskSegmentVector& segments = mNodeMaskArray[n];
1419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 766 times.
766 if (segments.empty()) continue;
1420
1421
1/4
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1532 std::vector<std::set<NodeMaskSegmentType*> > connections(segments.size());
1422
1423 766 Coord ijk = segments[0]->origin;
1424
1425 766 const NodeType* node = acc.template probeConstNode<NodeType>(ijk);
1426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 766 times.
766 if (!node) continue;
1427
1428 // get neighbour nodes
1429
1430 766 ijk[2] += NodeType::DIM;
1431 766 const NodeType* nodeZUp = acc.template probeConstNode<NodeType>(ijk);
1432 766 ijk[2] -= (NodeType::DIM + NodeType::DIM);
1433 766 const NodeType* nodeZDown = acc.template probeConstNode<NodeType>(ijk);
1434 766 ijk[2] += NodeType::DIM;
1435
1436 766 ijk[1] += NodeType::DIM;
1437 766 const NodeType* nodeYUp = acc.template probeConstNode<NodeType>(ijk);
1438 766 ijk[1] -= (NodeType::DIM + NodeType::DIM);
1439 766 const NodeType* nodeYDown = acc.template probeConstNode<NodeType>(ijk);
1440 766 ijk[1] += NodeType::DIM;
1441
1442 766 ijk[0] += NodeType::DIM;
1443 766 const NodeType* nodeXUp = acc.template probeConstNode<NodeType>(ijk);
1444 766 ijk[0] -= (NodeType::DIM + NodeType::DIM);
1445 766 const NodeType* nodeXDown = acc.template probeConstNode<NodeType>(ijk);
1446 766 ijk[0] += NodeType::DIM;
1447
1448 766 const Index startPos = node->getValueMask().findFirstOn();
1449
2/2
✓ Branch 0 taken 367552 times.
✓ Branch 1 taken 766 times.
368318 for (Index pos = startPos; pos < NodeMaskType::SIZE; ++pos) {
1450
1451
2/2
✓ Branch 1 taken 133072 times.
✓ Branch 2 taken 234480 times.
367552 if (!node->isValueOn(pos)) continue;
1452
1453 234480 ijk = NodeType::offsetToLocalCoord(pos);
1454
1455 #ifdef _MSC_FULL_VER
1456 #if _MSC_FULL_VER >= 190000000 && _MSC_FULL_VER < 190024210
1457 // Visual Studio 2015 had a codegen bug that wasn't fixed until Update 3
1458 volatile Index npos = 0;
1459 #else
1460 Index npos = 0;
1461 #endif
1462 #else
1463 Index npos = 0;
1464 #endif
1465
1466
2/2
✓ Branch 0 taken 30992 times.
✓ Branch 1 taken 203488 times.
234480 if (ijk[2] == 0) {
1467 30992 npos = pos + (NodeType::DIM - 1);
1468
4/4
✓ Branch 0 taken 28330 times.
✓ Branch 1 taken 2662 times.
✓ Branch 3 taken 28227 times.
✓ Branch 4 taken 103 times.
30992 if (nodeZDown && nodeZDown->isValueOn(npos)) {
1469 28227 NodeMaskSegmentType* nsegment =
1470 28227 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeZDown)], npos);
1471 28227 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1472
1/2
✓ Branch 1 taken 28227 times.
✗ Branch 2 not taken.
28227 connections[idx].insert(nsegment);
1473 }
1474
2/2
✓ Branch 0 taken 28227 times.
✓ Branch 1 taken 175261 times.
203488 } else if (ijk[2] == (NodeType::DIM - 1)) {
1475 28227 npos = pos - (NodeType::DIM - 1);
1476
2/4
✓ Branch 0 taken 28227 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 28227 times.
✗ Branch 4 not taken.
28227 if (nodeZUp && nodeZUp->isValueOn(npos)) {
1477 28227 NodeMaskSegmentType* nsegment =
1478 28227 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeZUp)], npos);
1479 28227 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1480
1/2
✓ Branch 1 taken 28227 times.
✗ Branch 2 not taken.
28227 connections[idx].insert(nsegment);
1481 }
1482 }
1483
1484
2/2
✓ Branch 0 taken 30992 times.
✓ Branch 1 taken 203488 times.
234480 if (ijk[1] == 0) {
1485 30992 npos = pos + (NodeType::DIM - 1) * NodeType::DIM;
1486
4/4
✓ Branch 0 taken 28330 times.
✓ Branch 1 taken 2662 times.
✓ Branch 3 taken 28227 times.
✓ Branch 4 taken 103 times.
30992 if (nodeYDown && nodeYDown->isValueOn(npos)) {
1487 28227 NodeMaskSegmentType* nsegment =
1488 28227 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeYDown)], npos);
1489 28227 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1490
1/2
✓ Branch 1 taken 28227 times.
✗ Branch 2 not taken.
28227 connections[idx].insert(nsegment);
1491 }
1492
2/2
✓ Branch 0 taken 28227 times.
✓ Branch 1 taken 175261 times.
203488 } else if (ijk[1] == (NodeType::DIM - 1)) {
1493 28227 npos = pos - (NodeType::DIM - 1) * NodeType::DIM;
1494
2/4
✓ Branch 0 taken 28227 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 28227 times.
✗ Branch 4 not taken.
28227 if (nodeYUp && nodeYUp->isValueOn(npos)) {
1495 28227 NodeMaskSegmentType* nsegment =
1496 28227 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeYUp)], npos);
1497 28227 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1498
1/2
✓ Branch 1 taken 28227 times.
✗ Branch 2 not taken.
28227 connections[idx].insert(nsegment);
1499 }
1500 }
1501
1502
2/2
✓ Branch 0 taken 31060 times.
✓ Branch 1 taken 203420 times.
234480 if (ijk[0] == 0) {
1503 31060 npos = pos + (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1504
4/4
✓ Branch 0 taken 28417 times.
✓ Branch 1 taken 2643 times.
✓ Branch 3 taken 27842 times.
✓ Branch 4 taken 575 times.
31060 if (nodeXDown && nodeXDown->isValueOn(npos)) {
1505 27842 NodeMaskSegmentType* nsegment =
1506 27842 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeXDown)], npos);
1507 27842 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1508
1/2
✓ Branch 1 taken 27842 times.
✗ Branch 2 not taken.
27842 connections[idx].insert(nsegment);
1509 }
1510
2/2
✓ Branch 0 taken 27842 times.
✓ Branch 1 taken 175578 times.
203420 } else if (ijk[0] == (NodeType::DIM - 1)) {
1511 27842 npos = pos - (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1512
2/4
✓ Branch 0 taken 27842 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 27842 times.
✗ Branch 4 not taken.
27842 if (nodeXUp && nodeXUp->isValueOn(npos)) {
1513 27842 NodeMaskSegmentType* nsegment =
1514 27842 findNodeMaskSegment(mNodeMaskArray[getNodeOffset(*nodeXUp)], npos);
1515 27842 const Index idx = findNodeMaskSegmentIndex(segments, pos);
1516
1/2
✓ Branch 1 taken 27842 times.
✗ Branch 2 not taken.
27842 connections[idx].insert(nsegment);
1517 }
1518 }
1519 }
1520
1521
2/2
✓ Branch 0 taken 766 times.
✓ Branch 1 taken 766 times.
1532 for (size_t i = 0, I = connections.size(); i < I; ++i) {
1522
1523 typename std::set<NodeMaskSegmentType*>::iterator
1524
1/2
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
766 it = connections[i].begin(), end = connections[i].end();
1525
1526
1/2
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
766 std::vector<NodeMaskSegmentType*>& segmentConnections = segments[i]->connections;
1527
1/2
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
766 segmentConnections.reserve(connections.size());
1528
2/2
✓ Branch 0 taken 3750 times.
✓ Branch 1 taken 766 times.
4516 for (; it != end; ++it) {
1529
1/2
✓ Branch 1 taken 3750 times.
✗ Branch 2 not taken.
3750 segmentConnections.push_back(*it);
1530 }
1531 }
1532 } // end range loop
1533 353 }
1534
1535 private:
1536
1537 static inline size_t getNodeOffset(const NodeType& node) {
1538 168592 return static_cast<size_t>(node.origin()[0]);
1539 }
1540
1541 static inline NodeMaskSegmentType*
1542 168592 findNodeMaskSegment(NodeMaskSegmentVector& segments, Index pos)
1543 {
1544 NodeMaskSegmentType* segment = nullptr;
1545
1546
1/2
✓ Branch 0 taken 168592 times.
✗ Branch 1 not taken.
168592 for (size_t n = 0, N = segments.size(); n < N; ++n) {
1547
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 168592 times.
168592 if (segments[n]->mask.isOn(pos)) {
1548 segment = segments[n].get();
1549 break;
1550 }
1551 }
1552
1553 168592 return segment;
1554 }
1555
1556 static inline Index
1557 168592 findNodeMaskSegmentIndex(NodeMaskSegmentVector& segments, Index pos)
1558 {
1559
1/2
✓ Branch 0 taken 168592 times.
✗ Branch 1 not taken.
168592 for (Index n = 0, N = Index(segments.size()); n < N; ++n) {
1560
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 168592 times.
168592 if (segments[n]->mask.isOn(pos)) return n;
1561 }
1562 return Index(-1);
1563 }
1564
1565 TreeType const * const mTree;
1566 NodeMaskSegmentVector * const mNodeMaskArray;
1567 }; // struct ConnectNodeMaskSegments
1568
1569
1570 template<typename TreeType>
1571 13 struct MaskSegmentGroup
1572 {
1573 using LeafNodeType = typename TreeType::LeafNodeType;
1574 using TreeTypePtr = typename TreeType::Ptr;
1575 using NodeMaskSegmentType = NodeMaskSegment<LeafNodeType>;
1576
1577
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 MaskSegmentGroup(const std::vector<NodeMaskSegmentType*>& segments)
1578
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 : mSegments(!segments.empty() ? &segments.front() : nullptr)
1579 4 , mTree(new TreeType(false))
1580 {
1581 4 }
1582
1583 13 MaskSegmentGroup(const MaskSegmentGroup& rhs, tbb::split)
1584 13 : mSegments(rhs.mSegments)
1585 13 , mTree(new TreeType(false))
1586 {
1587 13 }
1588
1589 TreeTypePtr& mask() { return mTree; }
1590
1591 13 void join(MaskSegmentGroup& rhs) { mTree->merge(*rhs.mTree); }
1592
1593 355 void operator()(const tbb::blocked_range<size_t>& range) {
1594
1595 tree::ValueAccessor<TreeType> acc(*mTree);
1596
1597
2/2
✓ Branch 0 taken 656 times.
✓ Branch 1 taken 355 times.
1011 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1598 656 NodeMaskSegmentType& segment = *mSegments[n];
1599
1/2
✓ Branch 1 taken 656 times.
✗ Branch 2 not taken.
656 LeafNodeType* node = acc.touchLeaf(segment.origin);
1600 node->getValueMask() |= segment.mask;
1601 }
1602 355 }
1603
1604 private:
1605 NodeMaskSegmentType * const * const mSegments;
1606 TreeTypePtr mTree;
1607 }; // struct MaskSegmentGroup
1608
1609
1610 ////////////////////////////////////////
1611
1612
1613 template<typename TreeType>
1614 9 struct ExpandLeafNodeRegion
1615 {
1616 using ValueType = typename TreeType::ValueType;
1617 using LeafNodeType = typename TreeType::LeafNodeType;
1618 using NodeMaskType = typename LeafNodeType::NodeMaskType;
1619
1620 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
1621 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
1622
1623 /////
1624
1625 6 ExpandLeafNodeRegion(const TreeType& distTree, BoolTreeType& maskTree,
1626 std::vector<BoolLeafNodeType*>& maskNodes)
1627 : mDistTree(&distTree)
1628 , mMaskTree(&maskTree)
1629
1/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6 , mMaskNodes(!maskNodes.empty() ? &maskNodes.front() : nullptr)
1630
1/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 , mNewMaskTree(false)
1631 {
1632 }
1633
1634 3 ExpandLeafNodeRegion(const ExpandLeafNodeRegion& rhs, tbb::split)
1635 3 : mDistTree(rhs.mDistTree)
1636 3 , mMaskTree(rhs.mMaskTree)
1637 3 , mMaskNodes(rhs.mMaskNodes)
1638 3 , mNewMaskTree(false)
1639 {
1640 }
1641
1642 BoolTreeType& newMaskTree() { return mNewMaskTree; }
1643
1644 3 void join(ExpandLeafNodeRegion& rhs) { mNewMaskTree.merge(rhs.mNewMaskTree); }
1645
1646 252 void operator()(const tbb::blocked_range<size_t>& range) {
1647
1648 using NodeType = LeafNodeType;
1649
1650 252 tree::ValueAccessor<const TreeType> distAcc(*mDistTree);
1651
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 tree::ValueAccessor<const BoolTreeType> maskAcc(*mMaskTree);
1652
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 tree::ValueAccessor<BoolTreeType> newMaskAcc(mNewMaskTree);
1653
1654 NodeMaskType maskZUp, maskZDown, maskYUp, maskYDown, maskXUp, maskXDown;
1655
1656
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
504 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1657
1658 252 BoolLeafNodeType& maskNode = *mMaskNodes[n];
1659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
252 if (maskNode.isEmpty()) continue;
1660
1661 252 Coord ijk = maskNode.origin(), nijk;
1662
1663 const LeafNodeType* distNode = distAcc.probeConstLeaf(ijk);
1664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
252 if (!distNode) continue;
1665
1666 252 const ValueType *dataZUp = nullptr, *dataZDown = nullptr,
1667 252 *dataYUp = nullptr, *dataYDown = nullptr,
1668 252 *dataXUp = nullptr, *dataXDown = nullptr;
1669
1670 252 ijk[2] += NodeType::DIM;
1671
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 getData(ijk, distAcc, maskAcc, maskZUp, dataZUp);
1672 252 ijk[2] -= (NodeType::DIM + NodeType::DIM);
1673
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 getData(ijk, distAcc, maskAcc, maskZDown, dataZDown);
1674 252 ijk[2] += NodeType::DIM;
1675
1676 252 ijk[1] += NodeType::DIM;
1677
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 getData(ijk, distAcc, maskAcc, maskYUp, dataYUp);
1678 252 ijk[1] -= (NodeType::DIM + NodeType::DIM);
1679
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 getData(ijk, distAcc, maskAcc, maskYDown, dataYDown);
1680 252 ijk[1] += NodeType::DIM;
1681
1682 252 ijk[0] += NodeType::DIM;
1683
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 getData(ijk, distAcc, maskAcc, maskXUp, dataXUp);
1684 252 ijk[0] -= (NodeType::DIM + NodeType::DIM);
1685
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 getData(ijk, distAcc, maskAcc, maskXDown, dataXDown);
1686 252 ijk[0] += NodeType::DIM;
1687
1688
2/2
✓ Branch 0 taken 23140 times.
✓ Branch 1 taken 126 times.
46532 for (typename BoolLeafNodeType::ValueOnIter it = maskNode.beginValueOn(); it; ++it) {
1689
1690 const Index pos = it.pos();
1691
1/2
✓ Branch 1 taken 23140 times.
✗ Branch 2 not taken.
46280 const ValueType val = std::abs(distNode->getValue(pos));
1692
1693 46280 ijk = BoolLeafNodeType::offsetToLocalCoord(pos);
1694 nijk = ijk + maskNode.origin();
1695
1696
4/4
✓ Branch 0 taken 15432 times.
✓ Branch 1 taken 7708 times.
✓ Branch 2 taken 2736 times.
✓ Branch 3 taken 12696 times.
46280 if (dataZUp && ijk[2] == (BoolLeafNodeType::DIM - 1)) {
1697 5472 const Index npos = pos - (NodeType::DIM - 1);
1698
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2736 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
5472 if (maskZUp.isOn(npos) && std::abs(dataZUp[npos]) > val) {
1699 newMaskAcc.setValueOn(nijk.offsetBy(0, 0, 1));
1700 }
1701
4/4
✓ Branch 0 taken 18752 times.
✓ Branch 1 taken 1652 times.
✓ Branch 2 taken 2736 times.
✓ Branch 3 taken 16016 times.
40808 } else if (dataZDown && ijk[2] == 0) {
1702 5472 const Index npos = pos + (NodeType::DIM - 1);
1703
3/4
✓ Branch 1 taken 137 times.
✓ Branch 2 taken 2599 times.
✓ Branch 3 taken 137 times.
✗ Branch 4 not taken.
5472 if (maskZDown.isOn(npos) && std::abs(dataZDown[npos]) > val) {
1704
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
274 newMaskAcc.setValueOn(nijk.offsetBy(0, 0, -1));
1705 }
1706 }
1707
1708
4/4
✓ Branch 0 taken 15432 times.
✓ Branch 1 taken 7708 times.
✓ Branch 2 taken 12696 times.
✓ Branch 3 taken 2736 times.
46280 if (dataYUp && ijk[1] == (BoolLeafNodeType::DIM - 1)) {
1709 5472 const Index npos = pos - (NodeType::DIM - 1) * NodeType::DIM;
1710
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2736 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
5472 if (maskYUp.isOn(npos) && std::abs(dataYUp[npos]) > val) {
1711 newMaskAcc.setValueOn(nijk.offsetBy(0, 1, 0));
1712 }
1713
4/4
✓ Branch 0 taken 18752 times.
✓ Branch 1 taken 1652 times.
✓ Branch 2 taken 2736 times.
✓ Branch 3 taken 16016 times.
40808 } else if (dataYDown && ijk[1] == 0) {
1714 5472 const Index npos = pos + (NodeType::DIM - 1) * NodeType::DIM;
1715
3/4
✓ Branch 1 taken 137 times.
✓ Branch 2 taken 2599 times.
✓ Branch 3 taken 137 times.
✗ Branch 4 not taken.
5472 if (maskYDown.isOn(npos) && std::abs(dataYDown[npos]) > val) {
1716
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
274 newMaskAcc.setValueOn(nijk.offsetBy(0, -1, 0));
1717 }
1718 }
1719
1720
4/4
✓ Branch 0 taken 19283 times.
✓ Branch 1 taken 3857 times.
✓ Branch 2 taken 16549 times.
✓ Branch 3 taken 2734 times.
46280 if (dataXUp && ijk[0] == (BoolLeafNodeType::DIM - 1)) {
1721 5468 const Index npos = pos - (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1722
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2734 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
5468 if (maskXUp.isOn(npos) && std::abs(dataXUp[npos]) > val) {
1723 newMaskAcc.setValueOn(nijk.offsetBy(1, 0, 0));
1724 }
1725
4/4
✓ Branch 0 taken 19237 times.
✓ Branch 1 taken 1169 times.
✓ Branch 2 taken 2826 times.
✓ Branch 3 taken 16411 times.
40812 } else if (dataXDown && ijk[0] == 0) {
1726 5652 const Index npos = pos + (NodeType::DIM - 1) * NodeType::DIM * NodeType::DIM;
1727
3/4
✓ Branch 1 taken 622 times.
✓ Branch 2 taken 2204 times.
✓ Branch 3 taken 622 times.
✗ Branch 4 not taken.
5652 if (maskXDown.isOn(npos) && std::abs(dataXDown[npos]) > val) {
1728
1/2
✓ Branch 1 taken 622 times.
✗ Branch 2 not taken.
1244 newMaskAcc.setValueOn(nijk.offsetBy(-1, 0, 0));
1729 }
1730 }
1731
1732 } // end value on loop
1733 } // end range loop
1734 }
1735
1736 private:
1737
1738 static inline void
1739 1512 getData(const Coord& ijk, tree::ValueAccessor<const TreeType>& distAcc,
1740 tree::ValueAccessor<const BoolTreeType>& maskAcc, NodeMaskType& mask,
1741 const ValueType*& data)
1742 {
1743 1512 const LeafNodeType* node = distAcc.probeConstLeaf(ijk);
1744
2/2
✓ Branch 0 taken 583 times.
✓ Branch 1 taken 173 times.
1512 if (node) {
1745 1166 data = node->buffer().data();
1746 mask = node->getValueMask();
1747 1166 const BoolLeafNodeType* maskNodePt = maskAcc.probeConstLeaf(ijk);
1748
2/2
✓ Branch 0 taken 507 times.
✓ Branch 1 taken 76 times.
1166 if (maskNodePt) mask -= maskNodePt->getValueMask();
1749 }
1750 }
1751
1752 TreeType const * const mDistTree;
1753 BoolTreeType * const mMaskTree;
1754 BoolLeafNodeType ** const mMaskNodes;
1755
1756 BoolTreeType mNewMaskTree;
1757 }; // struct ExpandLeafNodeRegion
1758
1759
1760 template<typename TreeType>
1761 struct FillLeafNodeVoxels
1762 {
1763 using ValueType = typename TreeType::ValueType;
1764 using LeafNodeType = typename TreeType::LeafNodeType;
1765 using NodeMaskType = typename LeafNodeType::NodeMaskType;
1766 using BoolLeafNodeType = tree::LeafNode<bool, LeafNodeType::LOG2DIM>;
1767
1768 6 FillLeafNodeVoxels(const TreeType& tree, std::vector<BoolLeafNodeType*>& maskNodes)
1769 6 : mTree(&tree), mMaskNodes(!maskNodes.empty() ? &maskNodes.front() : nullptr)
1770 {
1771 }
1772
1773 252 void operator()(const tbb::blocked_range<size_t>& range) const {
1774
1775 252 tree::ValueAccessor<const TreeType> distAcc(*mTree);
1776
1777 std::vector<Index> indexList;
1778
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 indexList.reserve(NodeMaskType::SIZE);
1779
1780
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
504 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1781
1782 252 BoolLeafNodeType& maskNode = *mMaskNodes[n];
1783
1784 const LeafNodeType * distNode = distAcc.probeConstLeaf(maskNode.origin());
1785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
252 if (!distNode) continue;
1786
1787 NodeMaskType mask(distNode->getValueMask());
1788 NodeMaskType& narrowbandMask = maskNode.getValueMask();
1789
1790
2/2
✓ Branch 1 taken 47664 times.
✓ Branch 2 taken 126 times.
95580 for (Index pos = narrowbandMask.findFirstOn(); pos < NodeMaskType::SIZE; ++pos) {
1791
3/4
✓ Branch 1 taken 10566 times.
✓ Branch 2 taken 37098 times.
✓ Branch 4 taken 10566 times.
✗ Branch 5 not taken.
95328 if (narrowbandMask.isOn(pos)) indexList.push_back(pos);
1792 }
1793
1794 mask -= narrowbandMask; // bitwise difference
1795 narrowbandMask.setOff();
1796
1797
1/2
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
252 const ValueType* data = distNode->buffer().data();
1798 Coord ijk(0, 0, 0);
1799
1800
2/2
✓ Branch 0 taken 23140 times.
✓ Branch 1 taken 126 times.
46532 while (!indexList.empty()) {
1801
1802 46280 const Index pos = indexList.back();
1803 indexList.pop_back();
1804
1805
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 23140 times.
46280 if (narrowbandMask.isOn(pos)) continue;
1806 46280 narrowbandMask.setOn(pos);
1807
1808 46280 const ValueType dist = std::abs(data[pos]);
1809
1810 46280 ijk = LeafNodeType::offsetToLocalCoord(pos);
1811
1812 46280 Index npos = pos - 1;
1813
6/6
✓ Branch 0 taken 20404 times.
✓ Branch 1 taken 2736 times.
✓ Branch 3 taken 8866 times.
✓ Branch 4 taken 11538 times.
✓ Branch 5 taken 2038 times.
✓ Branch 6 taken 6828 times.
46280 if (ijk[2] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1814 4076 mask.setOff(npos);
1815
1/2
✓ Branch 1 taken 2038 times.
✗ Branch 2 not taken.
4076 indexList.push_back(npos);
1816 }
1817
1818 46280 npos = pos + 1;
1819
2/2
✓ Branch 1 taken 2600 times.
✓ Branch 2 taken 17804 times.
40808 if ((ijk[2] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1820
4/4
✓ Branch 0 taken 20404 times.
✓ Branch 1 taken 2736 times.
✓ Branch 2 taken 2408 times.
✓ Branch 3 taken 192 times.
51480 && std::abs(data[npos]) > dist)
1821 {
1822 4816 mask.setOff(npos);
1823
1/2
✓ Branch 1 taken 2408 times.
✗ Branch 2 not taken.
4816 indexList.push_back(npos);
1824 }
1825
1826 46280 npos = pos - LeafNodeType::DIM;
1827
6/6
✓ Branch 0 taken 20404 times.
✓ Branch 1 taken 2736 times.
✓ Branch 3 taken 9026 times.
✓ Branch 4 taken 11378 times.
✓ Branch 5 taken 2059 times.
✓ Branch 6 taken 6967 times.
46280 if (ijk[1] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1828 4118 mask.setOff(npos);
1829
1/2
✓ Branch 1 taken 2059 times.
✗ Branch 2 not taken.
4118 indexList.push_back(npos);
1830 }
1831
1832 46280 npos = pos + LeafNodeType::DIM;
1833
2/2
✓ Branch 1 taken 2264 times.
✓ Branch 2 taken 18140 times.
40808 if ((ijk[1] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1834
4/4
✓ Branch 0 taken 20404 times.
✓ Branch 1 taken 2736 times.
✓ Branch 2 taken 2166 times.
✓ Branch 3 taken 98 times.
50808 && std::abs(data[npos]) > dist)
1835 {
1836 4332 mask.setOff(npos);
1837
1/2
✓ Branch 1 taken 2166 times.
✗ Branch 2 not taken.
4332 indexList.push_back(npos);
1838 }
1839
1840 46280 npos = pos - LeafNodeType::DIM * LeafNodeType::DIM;
1841
6/6
✓ Branch 0 taken 20314 times.
✓ Branch 1 taken 2826 times.
✓ Branch 3 taken 9568 times.
✓ Branch 4 taken 10746 times.
✓ Branch 5 taken 1825 times.
✓ Branch 6 taken 7743 times.
46280 if (ijk[0] != 0 && mask.isOn(npos) && std::abs(data[npos]) > dist) {
1842 3650 mask.setOff(npos);
1843
1/2
✓ Branch 1 taken 1825 times.
✗ Branch 2 not taken.
3650 indexList.push_back(npos);
1844 }
1845
1846 46280 npos = pos + LeafNodeType::DIM * LeafNodeType::DIM;
1847
2/2
✓ Branch 1 taken 2614 times.
✓ Branch 2 taken 17792 times.
40812 if ((ijk[0] != (LeafNodeType::DIM - 1)) && mask.isOn(npos)
1848
4/4
✓ Branch 0 taken 20406 times.
✓ Branch 1 taken 2734 times.
✓ Branch 2 taken 2078 times.
✓ Branch 3 taken 536 times.
51508 && std::abs(data[npos]) > dist)
1849 {
1850 4156 mask.setOff(npos);
1851
1/2
✓ Branch 1 taken 2078 times.
✗ Branch 2 not taken.
4156 indexList.push_back(npos);
1852 }
1853 } // end flood fill loop
1854 } // end range loop
1855 }
1856
1857 TreeType const * const mTree;
1858 BoolLeafNodeType ** const mMaskNodes;
1859 }; // FillLeafNodeVoxels
1860
1861
1862 template<typename TreeType>
1863 struct ExpandNarrowbandMask
1864 {
1865 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
1866 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
1867 using BoolTreeTypePtr = typename BoolTreeType::Ptr;
1868
1869 1 ExpandNarrowbandMask(const TreeType& tree, std::vector<BoolTreeTypePtr>& segments)
1870 1 : mTree(&tree), mSegments(!segments.empty() ? &segments.front() : nullptr)
1871 {
1872 }
1873
1874 4 void operator()(const tbb::blocked_range<size_t>& range) const {
1875
1876 4 const TreeType& distTree = *mTree;
1877 std::vector<BoolLeafNodeType*> nodes;
1878
1879
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
8 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1880
1881
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 BoolTreeType& narrowBandMask = *mSegments[n];
1882
1883
1/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
8 BoolTreeType candidateMask(narrowBandMask, false, TopologyCopy());
1884
1885 while (true) {
1886
1887 nodes.clear();
1888 candidateMask.getNodes(nodes);
1889
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 if (nodes.empty()) break;
1890
1891 const tbb::blocked_range<size_t> nodeRange(0, nodes.size());
1892
1893
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 tbb::parallel_for(nodeRange, FillLeafNodeVoxels<TreeType>(distTree, nodes));
1894
1895 narrowBandMask.topologyUnion(candidateMask);
1896
1897 ExpandLeafNodeRegion<TreeType> op(distTree, narrowBandMask, nodes);
1898
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 tbb::parallel_reduce(nodeRange, op);
1899
1900
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
12 if (op.newMaskTree().empty()) break;
1901
1902
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 candidateMask.clear();
1903
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 candidateMask.merge(op.newMaskTree());
1904 } // end expand loop
1905 } // end range loop
1906 }
1907
1908 TreeType const * const mTree;
1909 BoolTreeTypePtr * const mSegments;
1910 }; // ExpandNarrowbandMask
1911
1912
1913 template<typename TreeType>
1914 struct FloodFillSign
1915 {
1916 using TreeTypePtr = typename TreeType::Ptr;
1917 using ValueType = typename TreeType::ValueType;
1918 using LeafNodeType = typename TreeType::LeafNodeType;
1919 using RootNodeType = typename TreeType::RootNodeType;
1920 using NodeChainType = typename RootNodeType::NodeChainType;
1921 using InternalNodeType = typename NodeChainType::template Get<1>;
1922
1923 2 FloodFillSign(const TreeType& tree, std::vector<TreeTypePtr>& segments)
1924 : mTree(&tree)
1925
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 , mSegments(!segments.empty() ? &segments.front() : nullptr)
1926
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 , mMinValue(ValueType(0.0))
1927 {
1928
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 ValueType minSDFValue = std::numeric_limits<ValueType>::max();
1929
1930 {
1931 std::vector<const InternalNodeType*> nodes;
1932 tree.getNodes(nodes);
1933
1934
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 if (!nodes.empty()) {
1935 FindMinTileValue<InternalNodeType> minOp(nodes.data());
1936
2/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
1937 2 minSDFValue = std::min(minSDFValue, minOp.minValue);
1938 }
1939 }
1940
1941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if (minSDFValue > ValueType(0.0)) {
1942 std::vector<const LeafNodeType*> nodes;
1943 tree.getNodes(nodes);
1944 if (!nodes.empty()) {
1945 FindMinVoxelValue<LeafNodeType> minOp(nodes.data());
1946 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
1947 minSDFValue = std::min(minSDFValue, minOp.minValue);
1948 }
1949 }
1950
1951 2 mMinValue = minSDFValue;
1952 }
1953
1954 4 void operator()(const tbb::blocked_range<size_t>& range) const {
1955 4 const ValueType interiorValue = -std::abs(mMinValue);
1956 4 const ValueType exteriorValue = std::abs(mTree->background());
1957
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
8 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1958 4 tools::signedFloodFillWithValues(*mSegments[n], exteriorValue, interiorValue);
1959 }
1960 }
1961
1962 private:
1963
1964 TreeType const * const mTree;
1965 TreeTypePtr * const mSegments;
1966 ValueType mMinValue;
1967 }; // FloodFillSign
1968
1969
1970 template<typename TreeType>
1971 struct MaskedCopy
1972 {
1973 using TreeTypePtr = typename TreeType::Ptr;
1974 using ValueType = typename TreeType::ValueType;
1975 using LeafNodeType = typename TreeType::LeafNodeType;
1976
1977 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
1978 using BoolTreeTypePtr = typename BoolTreeType::Ptr;
1979 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
1980
1981 2 MaskedCopy(const TreeType& tree, std::vector<TreeTypePtr>& segments,
1982 std::vector<BoolTreeTypePtr>& masks)
1983 : mTree(&tree)
1984
2/48
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
2 , mSegments(!segments.empty() ? &segments.front() : nullptr)
1985
2/48
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
2 , mMasks(!masks.empty() ? &masks.front() : nullptr)
1986 {
1987 }
1988
1989 8 void operator()(const tbb::blocked_range<size_t>& range) const {
1990
1991 std::vector<const BoolLeafNodeType*> nodes;
1992
1993
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
16 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
1994
1995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
8 const BoolTreeType& mask = *mMasks[n];
1996
1997 nodes.clear();
1998 mask.getNodes(nodes);
1999
2000
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 Copy op(*mTree, nodes);
2001
1/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
2002 8 mSegments[n] = op.outputTree();
2003 }
2004 }
2005
2006 private:
2007
2008 11 struct Copy {
2009 8 Copy(const TreeType& inputTree, std::vector<const BoolLeafNodeType*>& maskNodes)
2010 : mInputTree(&inputTree)
2011
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 , mMaskNodes(!maskNodes.empty() ? &maskNodes.front() : nullptr)
2012
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
16 , mOutputTreePtr(new TreeType(inputTree.background()))
2013 {
2014 }
2015
2016 22 Copy(const Copy& rhs, tbb::split)
2017 22 : mInputTree(rhs.mInputTree)
2018 22 , mMaskNodes(rhs.mMaskNodes)
2019 22 , mOutputTreePtr(new TreeType(mInputTree->background()))
2020 {
2021 }
2022
2023 TreeTypePtr& outputTree() { return mOutputTreePtr; }
2024
2025 11 void join(Copy& rhs) { mOutputTreePtr->merge(*rhs.mOutputTreePtr); }
2026
2027 804 void operator()(const tbb::blocked_range<size_t>& range) {
2028
2029 804 tree::ValueAccessor<const TreeType> inputAcc(*mInputTree);
2030 tree::ValueAccessor<TreeType> outputAcc(*mOutputTreePtr);
2031
2032
2/2
✓ Branch 0 taken 685 times.
✓ Branch 1 taken 402 times.
2174 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2033
2034 1370 const BoolLeafNodeType& maskNode = *mMaskNodes[n];
2035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 685 times.
1370 if (maskNode.isEmpty()) continue;
2036
2037 const Coord& ijk = maskNode.origin();
2038
2039 const LeafNodeType* inputNode = inputAcc.probeConstLeaf(ijk);
2040
2/2
✓ Branch 0 taken 405 times.
✓ Branch 1 taken 280 times.
1370 if (inputNode) {
2041
2042
1/2
✓ Branch 1 taken 405 times.
✗ Branch 2 not taken.
810 LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
2043
2044
2/2
✓ Branch 0 taken 81352 times.
✓ Branch 1 taken 405 times.
163514 for (typename BoolLeafNodeType::ValueOnCIter it = maskNode.cbeginValueOn();
2045 it; ++it)
2046 {
2047 const Index idx = it.pos();
2048
1/2
✓ Branch 1 taken 81352 times.
✗ Branch 2 not taken.
162704 outputNode->setValueOn(idx, inputNode->getValue(idx));
2049 }
2050 } else {
2051 560 const int valueDepth = inputAcc.getValueDepth(ijk);
2052
1/2
✓ Branch 0 taken 280 times.
✗ Branch 1 not taken.
560 if (valueDepth >= 0) {
2053
2/5
✓ Branch 1 taken 280 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 280 times.
✗ Branch 5 not taken.
560 outputAcc.addTile(TreeType::RootNodeType::LEVEL - valueDepth,
2054 ijk, inputAcc.getValue(ijk), true);
2055 }
2056 }
2057 }
2058 }
2059
2060 private:
2061 TreeType const * const mInputTree;
2062 BoolLeafNodeType const * const * const mMaskNodes;
2063 TreeTypePtr mOutputTreePtr;
2064 }; // struct Copy
2065
2066 TreeType const * const mTree;
2067 TreeTypePtr * const mSegments;
2068 BoolTreeTypePtr * const mMasks;
2069 }; // MaskedCopy
2070
2071
2072 ////////////////////////////////////////
2073
2074
2075 template<typename VolumePtrType>
2076 struct ComputeActiveVoxelCount
2077 {
2078
2/40
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
2 ComputeActiveVoxelCount(std::vector<VolumePtrType>& segments, size_t *countArray)
2079
2/40
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
2 : mSegments(!segments.empty() ? &segments.front() : nullptr)
2080
2/40
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
2 , mCountArray(countArray)
2081 {
2082 }
2083
2084 8 void operator()(const tbb::blocked_range<size_t>& range) const {
2085
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
16 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
2086 8 mCountArray[n] = mSegments[n]->activeVoxelCount();
2087 }
2088 }
2089
2090 VolumePtrType * const mSegments;
2091 size_t * const mCountArray;
2092 };
2093
2094
2095 struct GreaterCount
2096 {
2097 2 GreaterCount(const size_t *countArray) : mCountArray(countArray) {}
2098
2099 inline bool operator() (const size_t& lhs, const size_t& rhs) const
2100 {
2101
2/34
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 2 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 2 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
4 return (mCountArray[lhs] > mCountArray[rhs]);
2102 }
2103
2104 size_t const * const mCountArray;
2105 };
2106
2107 ////////////////////////////////////////
2108
2109
2110 template<typename TreeType>
2111 struct GridOrTreeConstructor
2112 {
2113 using TreeTypePtr = typename TreeType::Ptr;
2114 using BoolTreePtrType = typename TreeType::template ValueConverter<bool>::Type::Ptr;
2115
2116 static BoolTreePtrType constructMask(const TreeType&, BoolTreePtrType& maskTree)
2117 { return maskTree; }
2118 static TreeTypePtr construct(const TreeType&, TreeTypePtr& tree) { return tree; }
2119 };
2120
2121
2122 template<typename TreeType>
2123 struct GridOrTreeConstructor<Grid<TreeType> >
2124 {
2125 using GridType = Grid<TreeType>;
2126 using GridTypePtr = typename Grid<TreeType>::Ptr;
2127 using TreeTypePtr = typename TreeType::Ptr;
2128
2129 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2130 using BoolTreePtrType = typename BoolTreeType::Ptr;
2131 using BoolGridType = Grid<BoolTreeType>;
2132 using BoolGridPtrType = typename BoolGridType::Ptr;
2133
2134 58 static BoolGridPtrType constructMask(const GridType& grid, BoolTreePtrType& maskTree) {
2135
2/4
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
116 BoolGridPtrType maskGrid(BoolGridType::create(maskTree));
2136
2/6
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
58 maskGrid->setTransform(grid.transform().copy());
2137 58 return maskGrid;
2138 }
2139
2140 18 static GridTypePtr construct(const GridType& grid, TreeTypePtr& maskTree) {
2141
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
36 GridTypePtr maskGrid(GridType::create(maskTree));
2142
3/8
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
36 maskGrid->setTransform(grid.transform().copy());
2143
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 maskGrid->insertMeta(grid);
2144 18 return maskGrid;
2145 }
2146 };
2147
2148
2149 } // namespace level_set_util_internal
2150
2151
2152 /// @endcond OPENVDB_DOCS_INTERNAL
2153
2154 ////////////////////////////////////////
2155
2156
2157 template <class GridType>
2158 void
2159
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 sdfToFogVolume(GridType& grid, typename GridType::ValueType cutoffDistance)
2160 {
2161 using ValueType = typename GridType::ValueType;
2162 using TreeType = typename GridType::TreeType;
2163 using LeafNodeType = typename TreeType::LeafNodeType;
2164 using RootNodeType = typename TreeType::RootNodeType;
2165 using NodeChainType = typename RootNodeType::NodeChainType;
2166 using InternalNodeType = typename NodeChainType::template Get<1>;
2167
2168 //////////
2169
2170 TreeType& tree = grid.tree();
2171
2172 size_t numLeafNodes = 0, numInternalNodes = 0;
2173
2174 std::vector<LeafNodeType*> nodes;
2175 std::vector<size_t> leafnodeCount;
2176
2177 {
2178 // Compute the prefix sum of the leafnode count in each internal node.
2179 std::vector<InternalNodeType*> internalNodes;
2180 tree.getNodes(internalNodes);
2181
2182 numInternalNodes = internalNodes.size();
2183
2184
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 leafnodeCount.push_back(0);
2185
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 18 times.
384 for (size_t n = 0; n < numInternalNodes; ++n) {
2186
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
348 leafnodeCount.push_back(leafnodeCount.back() + internalNodes[n]->leafCount());
2187 }
2188
2189 36 numLeafNodes = leafnodeCount.back();
2190
2191 // Steal all leafnodes (Removes them from the tree and transfers ownership.)
2192
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 nodes.reserve(numLeafNodes);
2193
2194
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 18 times.
384 for (size_t n = 0; n < numInternalNodes; ++n) {
2195
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
348 internalNodes[n]->stealNodes(nodes, tree.background(), false);
2196 }
2197
2198 // Clamp cutoffDistance to min sdf value
2199
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 ValueType minSDFValue = std::numeric_limits<ValueType>::max();
2200
2201 {
2202 level_set_util_internal::FindMinTileValue<InternalNodeType> minOp(internalNodes.data());
2203
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
36 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), minOp);
2204 36 minSDFValue = std::min(minSDFValue, minOp.minValue);
2205 }
2206
2207
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
36 if (minSDFValue > ValueType(0.0)) {
2208 level_set_util_internal::FindMinVoxelValue<LeafNodeType> minOp(nodes.data());
2209
2/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), minOp);
2210 2 minSDFValue = std::min(minSDFValue, minOp.minValue);
2211 }
2212
2213 36 cutoffDistance = -std::abs(cutoffDistance);
2214
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 cutoffDistance = minSDFValue > cutoffDistance ? minSDFValue : cutoffDistance;
2215 }
2216
2217 // Transform voxel values and delete leafnodes that are uniformly zero after the transformation.
2218 // (Positive values are set to zero with inactive state and negative values are remapped
2219 // from zero to one with active state.)
2220
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 tbb::parallel_for(tbb::blocked_range<size_t>(0, nodes.size()),
2221 level_set_util_internal::SDFVoxelsToFogVolume<LeafNodeType>(nodes.data(), cutoffDistance));
2222
2223 // Populate a new tree with the remaining leafnodes
2224
1/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
72 typename TreeType::Ptr newTree(new TreeType(ValueType(0.0)));
2225
2226
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 level_set_util_internal::PopulateTree<TreeType> populate(
2227 *newTree, nodes.data(), leafnodeCount.data(), 0);
2228
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
36 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, numInternalNodes), populate);
2229
2230 // Transform tile values (Negative valued tiles are set to 1.0 with active state.)
2231 std::vector<InternalNodeType*> internalNodes;
2232 newTree->getNodes(internalNodes);
2233
2234
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
36 tbb::parallel_for(tbb::blocked_range<size_t>(0, internalNodes.size()),
2235 level_set_util_internal::SDFTilesToFogVolume<TreeType, InternalNodeType>(
2236 tree, internalNodes.data()));
2237
2238 {
2239 tree::ValueAccessor<const TreeType> acc(tree);
2240
2241
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 typename TreeType::ValueAllIter it(*newTree);
2242 36 it.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 2);
2243
2244
2/2
✓ Branch 0 taken 3899220 times.
✓ Branch 1 taken 18 times.
7798476 for ( ; it; ++it) {
2245
3/4
✓ Branch 1 taken 3899220 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 3899212 times.
7798440 if (acc.getValue(it.getCoord()) < ValueType(0.0)) {
2246
2/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16 it.setValue(ValueType(1.0));
2247 it.setActiveState(true);
2248 }
2249 }
2250 }
2251
2252 // Insert missing root level tiles. (The new tree is constructed from the remaining leafnodes
2253 // and will therefore not contain any root level tiles that may exist in the original tree.)
2254 {
2255
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 typename TreeType::ValueAllIter it(tree);
2256 36 it.setMaxDepth(TreeType::ValueAllIter::ROOT_DEPTH);
2257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
36 for ( ; it; ++it) {
2258 if (it.getValue() < ValueType(0.0)) {
2259 newTree->addTile(TreeType::ValueAllIter::ROOT_LEVEL, it.getCoord(),
2260 ValueType(1.0), true);
2261 }
2262 }
2263 }
2264
2265
1/4
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
36 grid.setTree(newTree);
2266
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 grid.setGridClass(GRID_FOG_VOLUME);
2267 }
2268
2269
2270 ////////////////////////////////////////
2271
2272
2273 template <class GridOrTreeType>
2274 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2275 56 sdfInteriorMask(const GridOrTreeType& volume, typename GridOrTreeType::ValueType isovalue)
2276 {
2277 using TreeType = typename TreeAdapter<GridOrTreeType>::TreeType;
2278 const TreeType& tree = TreeAdapter<GridOrTreeType>::tree(volume);
2279
2280 using BoolTreePtrType = typename TreeType::template ValueConverter<bool>::Type::Ptr;
2281 56 BoolTreePtrType mask = level_set_util_internal::computeInteriorMask(tree, isovalue);
2282
2283 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2284
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
112 volume, mask);
2285 }
2286
2287
2288 template<typename GridOrTreeType>
2289 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2290 4 extractEnclosedRegion(const GridOrTreeType& volume,
2291 typename GridOrTreeType::ValueType isovalue,
2292 const typename TreeAdapter<GridOrTreeType>::TreeType::template ValueConverter<bool>::Type*
2293 fillMask)
2294 {
2295 using TreeType = typename TreeAdapter<GridOrTreeType>::TreeType;
2296 const TreeType& tree = TreeAdapter<GridOrTreeType>::tree(volume);
2297
2298 using CharTreePtrType = typename TreeType::template ValueConverter<char>::Type::Ptr;
2299 4 CharTreePtrType regionMask = level_set_util_internal::computeEnclosedRegionMask(
2300 tree, isovalue, fillMask);
2301
2302 using BoolTreePtrType = typename TreeType::template ValueConverter<bool>::Type::Ptr;
2303
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 BoolTreePtrType mask = level_set_util_internal::computeInteriorMask(*regionMask, 0);
2304
2305 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2306
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
6 volume, mask);
2307 }
2308
2309
2310 ////////////////////////////////////////
2311
2312
2313 template<typename GridOrTreeType>
2314 typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr
2315
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 extractIsosurfaceMask(const GridOrTreeType& volume, typename GridOrTreeType::ValueType isovalue)
2316 {
2317 using TreeType = typename TreeAdapter<GridOrTreeType>::TreeType;
2318 const TreeType& tree = TreeAdapter<GridOrTreeType>::tree(volume);
2319
2320 std::vector<const typename TreeType::LeafNodeType*> nodes;
2321 tree.getNodes(nodes);
2322
2323 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2324
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
12 typename BoolTreeType::Ptr mask(new BoolTreeType(false));
2325
2326
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
12 level_set_util_internal::MaskIsovalueCrossingVoxels<TreeType> op(tree, nodes, *mask, isovalue);
2327
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
2328
2329 return level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2330
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
6 volume, mask);
2331 }
2332
2333
2334 ////////////////////////////////////////
2335
2336
2337 template<typename GridOrTreeType>
2338 void
2339 14 extractActiveVoxelSegmentMasks(const GridOrTreeType& volume,
2340 std::vector<typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr>& masks)
2341 {
2342 using TreeType = typename TreeAdapter<GridOrTreeType>::TreeType;
2343 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2344 using BoolTreePtrType = typename BoolTreeType::Ptr;
2345 using BoolLeafNodeType = typename BoolTreeType::LeafNodeType;
2346 using BoolGridOrTreePtrType = typename GridOrTreeType::template ValueConverter<bool>::Type::Ptr;
2347
2348 using NodeMaskSegmentType = level_set_util_internal::NodeMaskSegment<BoolLeafNodeType>;
2349 using NodeMaskSegmentPtrType = typename NodeMaskSegmentType::Ptr;
2350 using NodeMaskSegmentPtrVector = typename std::vector<NodeMaskSegmentPtrType>;
2351 using NodeMaskSegmentRawPtrVector = typename std::vector<NodeMaskSegmentType*>;
2352
2353 /////
2354
2355 const TreeType& tree = TreeAdapter<GridOrTreeType>::tree(volume);
2356
2357 20 BoolTreeType topologyMask(tree, false, TopologyCopy());
2358
2359 // prune out any inactive leaf nodes or inactive tiles
2360
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
14 tools::pruneInactive(topologyMask);
2361
2362
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
14 if (topologyMask.hasActiveTiles()) {
2363 topologyMask.voxelizeActiveTiles();
2364 }
2365
2366 std::vector<BoolLeafNodeType*> leafnodes;
2367 topologyMask.getNodes(leafnodes);
2368
2369
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
14 if (leafnodes.empty()) return;
2370
2371 // 1. Split node masks into disjoint segments
2372 // Note: The LeafNode origin coord is modified to record the 'leafnodes' array offset.
2373
2374 6 std::unique_ptr<NodeMaskSegmentPtrVector[]> nodeSegmentArray(
2375
4/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 766 times.
✓ Branch 6 taken 3 times.
1538 new NodeMaskSegmentPtrVector[leafnodes.size()]);
2376
2377
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
2378 level_set_util_internal::SegmentNodeMask<BoolLeafNodeType>(
2379 leafnodes, nodeSegmentArray.get()));
2380
2381
2382 // 2. Compute segment connectivity
2383
2384
1/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 tbb::parallel_for(tbb::blocked_range<size_t>(0, leafnodes.size()),
2385 level_set_util_internal::ConnectNodeMaskSegments<BoolTreeType, BoolLeafNodeType>(
2386 topologyMask, nodeSegmentArray.get()));
2387
2388
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 topologyMask.clear();
2389
2390 size_t nodeSegmentCount = 0;
2391
2/2
✓ Branch 0 taken 766 times.
✓ Branch 1 taken 3 times.
1538 for (size_t n = 0, N = leafnodes.size(); n < N; ++n) {
2392 1532 nodeSegmentCount += nodeSegmentArray[n].size();
2393 }
2394
2395 // 3. Group connected segments
2396
2397 6 std::deque<NodeMaskSegmentRawPtrVector> nodeSegmentGroups;
2398
2399 6 NodeMaskSegmentType* nextSegment = nodeSegmentArray[0][0].get();
2400
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
16 while (nextSegment) {
2401
2402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
10 nodeSegmentGroups.push_back(NodeMaskSegmentRawPtrVector());
2403
2404 std::vector<NodeMaskSegmentType*>& segmentGroup = nodeSegmentGroups.back();
2405
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 segmentGroup.reserve(nodeSegmentCount);
2406
2407 std::deque<NodeMaskSegmentType*> segmentQueue;
2408
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 segmentQueue.push_back(nextSegment);
2409 10 nextSegment = nullptr;
2410
2411
2/2
✓ Branch 0 taken 1880 times.
✓ Branch 1 taken 5 times.
3770 while (!segmentQueue.empty()) {
2412
2413
2/2
✓ Branch 0 taken 1850 times.
✓ Branch 1 taken 30 times.
3760 NodeMaskSegmentType* segment = segmentQueue.back();
2414 segmentQueue.pop_back();
2415
2416
2/2
✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 766 times.
3760 if (segment->visited) continue;
2417 1532 segment->visited = true;
2418
2419
1/2
✓ Branch 1 taken 766 times.
✗ Branch 2 not taken.
1532 segmentGroup.push_back(segment);
2420
2421 // queue connected segments
2422 1532 std::vector<NodeMaskSegmentType*>& connections = segment->connections;
2423
2/2
✓ Branch 0 taken 3750 times.
✓ Branch 1 taken 766 times.
9032 for (size_t n = 0, N = connections.size(); n < N; ++n) {
2424
3/4
✓ Branch 0 taken 1875 times.
✓ Branch 1 taken 1875 times.
✓ Branch 3 taken 1875 times.
✗ Branch 4 not taken.
7500 if (!connections[n]->visited) segmentQueue.push_back(connections[n]);
2425 }
2426 }
2427
2428 // find first unvisited segment
2429
2/2
✓ Branch 0 taken 1422 times.
✓ Branch 1 taken 5 times.
2854 for (size_t n = 0, N = leafnodes.size(); n < N; ++n) {
2430 NodeMaskSegmentPtrVector& nodeSegments = nodeSegmentArray[n];
2431
2/2
✓ Branch 0 taken 1422 times.
✓ Branch 1 taken 1422 times.
5688 for (size_t i = 0, I = nodeSegments.size(); i < I; ++i) {
2432
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 1162 times.
2844 if (!nodeSegments[i]->visited) nextSegment = nodeSegments[i].get();
2433 }
2434 }
2435 }
2436
2437 // 4. Mask segment groups
2438
2439
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
6 if (nodeSegmentGroups.size() == 1) {
2440
2441
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 BoolTreePtrType mask(new BoolTreeType(tree, false, TopologyCopy()));
2442
2443
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 tools::pruneInactive(*mask);
2444
2445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if (mask->hasActiveTiles()) {
2446 mask->voxelizeActiveTiles();
2447 }
2448
2449
1/7
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2 masks.push_back(
2450 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2451 volume, mask));
2452
2453
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 } else if (nodeSegmentGroups.size() > 1) {
2454
2455
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
12 for (size_t n = 0, N = nodeSegmentGroups.size(); n < N; ++n) {
2456
2457 NodeMaskSegmentRawPtrVector& segmentGroup = nodeSegmentGroups[n];
2458
2459
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 level_set_util_internal::MaskSegmentGroup<BoolTreeType> op(segmentGroup);
2460
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, segmentGroup.size()), op);
2461
2462
1/7
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8 masks.push_back(
2463 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::constructMask(
2464 volume, op.mask()));
2465 }
2466 }
2467
2468 // 5. Sort segments in descending order based on the active voxel count.
2469
2470
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
6 if (masks.size() > 1) {
2471 const size_t segmentCount = masks.size();
2472
2473
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
4 std::unique_ptr<size_t[]> segmentOrderArray(new size_t[segmentCount]);
2474
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 std::unique_ptr<size_t[]> voxelCountArray(new size_t[segmentCount]);
2475
2476
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
12 for (size_t n = 0; n < segmentCount; ++n) {
2477 8 segmentOrderArray[n] = n;
2478 }
2479
2480
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 tbb::parallel_for(tbb::blocked_range<size_t>(0, segmentCount),
2481 level_set_util_internal::ComputeActiveVoxelCount<BoolGridOrTreePtrType>(
2482 masks, voxelCountArray.get()));
2483
2484 size_t *begin = segmentOrderArray.get();
2485
2/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 tbb::parallel_sort(begin, begin + masks.size(), level_set_util_internal::GreaterCount(
2486 voxelCountArray.get()));
2487
2488 4 std::vector<BoolGridOrTreePtrType> orderedMasks;
2489
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 orderedMasks.reserve(masks.size());
2490
2491
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
12 for (size_t n = 0; n < segmentCount; ++n) {
2492
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 orderedMasks.push_back(masks[segmentOrderArray[n]]);
2493 }
2494
2495 masks.swap(orderedMasks);
2496 }
2497
2498 } // extractActiveVoxelSegmentMasks()
2499
2500
2501 template<typename GridOrTreeType>
2502 void
2503
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 segmentActiveVoxels(const GridOrTreeType& volume,
2504 std::vector<typename GridOrTreeType::Ptr>& segments)
2505 {
2506 using TreeType = typename TreeAdapter<GridOrTreeType>::TreeType;
2507 using TreePtrType = typename TreeType::Ptr;
2508 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2509 using BoolTreePtrType = typename BoolTreeType::Ptr;
2510
2511 const TreeType& inputTree = TreeAdapter<GridOrTreeType>::tree(volume);
2512
2513 // 1. Segment active topology mask
2514 8 std::vector<BoolTreePtrType> maskSegmentArray;
2515
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 extractActiveVoxelSegmentMasks(inputTree, maskSegmentArray);
2516
2517 // 2. Export segments
2518
2519
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
8 const size_t numSegments = std::max(size_t(1), maskSegmentArray.size());
2520
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
16 std::vector<TreePtrType> outputSegmentArray(numSegments);
2521
2522
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
8 if (maskSegmentArray.empty()) {
2523 // if no active voxels in the original volume, copy just the background
2524 // value of the input tree
2525
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
8 outputSegmentArray[0] = TreePtrType(new TreeType(inputTree.background()));
2526
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
4 } else if (numSegments == 1) {
2527 // if there's only one segment with active voxels, copy the input tree
2528
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 TreePtrType segment(new TreeType(inputTree));
2529 // however, if the leaf counts do not match due to the pruning of inactive leaf
2530 // nodes in the mask, do a topology intersection to drop these inactive leafs
2531
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
2 if (segment->leafCount() != inputTree.leafCount()) {
2532 segment->topologyIntersection(*maskSegmentArray[0]);
2533 }
2534 outputSegmentArray[0] = segment;
2535 } else {
2536 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
2537
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 tbb::parallel_for(segmentRange,
2538 level_set_util_internal::MaskedCopy<TreeType>(inputTree, outputSegmentArray,
2539 maskSegmentArray));
2540 }
2541
2542
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
18 for (auto& segment : outputSegmentArray) {
2543
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
20 segments.push_back(
2544 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::construct(
2545 volume, segment));
2546 }
2547 }
2548
2549
2550 template<typename GridOrTreeType>
2551 void
2552 6 segmentSDF(const GridOrTreeType& volume, std::vector<typename GridOrTreeType::Ptr>& segments)
2553 {
2554 using TreeType = typename TreeAdapter<GridOrTreeType>::TreeType;
2555 using TreePtrType = typename TreeType::Ptr;
2556 using BoolTreeType = typename TreeType::template ValueConverter<bool>::Type;
2557 using BoolTreePtrType = typename BoolTreeType::Ptr;
2558
2559 const TreeType& inputTree = TreeAdapter<GridOrTreeType>::tree(volume);
2560
2561 // 1. Mask zero crossing voxels
2562 6 BoolTreePtrType mask = extractIsosurfaceMask(inputTree, lsutilGridZero<GridOrTreeType>());
2563
2564 // 2. Segment the zero crossing mask
2565 6 std::vector<BoolTreePtrType> maskSegmentArray;
2566
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 extractActiveVoxelSegmentMasks(*mask, maskSegmentArray);
2567
2568
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
6 const size_t numSegments = std::max(size_t(1), maskSegmentArray.size());
2569
3/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
12 std::vector<TreePtrType> outputSegmentArray(numSegments);
2570
2571
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
6 if (maskSegmentArray.empty()) {
2572 // if no active voxels in the original volume, copy just the background
2573 // value of the input tree
2574
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
8 outputSegmentArray[0] = TreePtrType(new TreeType(inputTree.background()));
2575 } else {
2576 const tbb::blocked_range<size_t> segmentRange(0, numSegments);
2577
2578 // 3. Expand zero crossing mask to capture sdf narrow band
2579
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 tbb::parallel_for(segmentRange,
2580 level_set_util_internal::ExpandNarrowbandMask<TreeType>(inputTree, maskSegmentArray));
2581
2582 // 4. Export sdf segments
2583
2584
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 tbb::parallel_for(segmentRange, level_set_util_internal::MaskedCopy<TreeType>(
2585 inputTree, outputSegmentArray, maskSegmentArray));
2586
2587
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 tbb::parallel_for(segmentRange,
2588 level_set_util_internal::FloodFillSign<TreeType>(inputTree, outputSegmentArray));
2589 }
2590
2591
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
14 for (auto& segment : outputSegmentArray) {
2592
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
16 segments.push_back(
2593 level_set_util_internal::GridOrTreeConstructor<GridOrTreeType>::construct(
2594 volume, segment));
2595 }
2596 }
2597
2598
2599 ////////////////////////////////////////
2600
2601
2602 // Explicit Template Instantiation
2603
2604 #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
2605
2606 #ifdef OPENVDB_INSTANTIATE_LEVELSETUTIL
2607 #include <openvdb/util/ExplicitInstantiation.h>
2608 #endif
2609
2610 #define _FUNCTION(TreeT) \
2611 void sdfToFogVolume(Grid<TreeT>&, TreeT::ValueType)
2612 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2613 #undef _FUNCTION
2614
2615 #define _FUNCTION(TreeT) \
2616 TreeT::ValueConverter<bool>::Type::Ptr sdfInteriorMask(const TreeT&, TreeT::ValueType)
2617 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2618 #undef _FUNCTION
2619
2620 #define _FUNCTION(TreeT) \
2621 Grid<TreeT>::ValueConverter<bool>::Type::Ptr sdfInteriorMask(const Grid<TreeT>&, TreeT::ValueType)
2622 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2623 #undef _FUNCTION
2624
2625 #define _FUNCTION(TreeT) \
2626 TreeT::ValueConverter<bool>::Type::Ptr extractEnclosedRegion(\
2627 const TreeT&, TreeT::ValueType, \
2628 const TreeAdapter<TreeT>::TreeType::ValueConverter<bool>::Type*)
2629 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2630 #undef _FUNCTION
2631
2632 #define _FUNCTION(TreeT) \
2633 Grid<TreeT>::ValueConverter<bool>::Type::Ptr extractEnclosedRegion(\
2634 const Grid<TreeT>&, TreeT::ValueType, \
2635 const TreeAdapter<Grid<TreeT>>::TreeType::ValueConverter<bool>::Type*)
2636 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2637 #undef _FUNCTION
2638
2639 #define _FUNCTION(TreeT) \
2640 TreeT::ValueConverter<bool>::Type::Ptr extractIsosurfaceMask(const TreeT&, TreeT::ValueType)
2641 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2642 #undef _FUNCTION
2643
2644 #define _FUNCTION(TreeT) \
2645 Grid<TreeT>::ValueConverter<bool>::Type::Ptr extractIsosurfaceMask(const Grid<TreeT>&, TreeT::ValueType)
2646 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2647 #undef _FUNCTION
2648
2649 #define _FUNCTION(TreeT) \
2650 void extractActiveVoxelSegmentMasks(\
2651 const TreeT&, std::vector<TreeT::ValueConverter<bool>::Type::Ptr>&)
2652 OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION)
2653 #undef _FUNCTION
2654
2655 #define _FUNCTION(TreeT) \
2656 void extractActiveVoxelSegmentMasks(\
2657 const Grid<TreeT>&, std::vector<Grid<TreeT>::ValueConverter<bool>::Type::Ptr>&)
2658 OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION)
2659 #undef _FUNCTION
2660
2661 #define _FUNCTION(TreeT) \
2662 void segmentActiveVoxels(const TreeT&, std::vector<TreeT::Ptr>&)
2663 OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION)
2664 #undef _FUNCTION
2665
2666 #define _FUNCTION(TreeT) \
2667 void segmentActiveVoxels(const Grid<TreeT>&, std::vector<Grid<TreeT>::Ptr>&)
2668 OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION)
2669 #undef _FUNCTION
2670
2671 #define _FUNCTION(TreeT) \
2672 void segmentSDF(const TreeT&, std::vector<TreeT::Ptr>&)
2673 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2674 #undef _FUNCTION
2675
2676 #define _FUNCTION(TreeT) \
2677 void segmentSDF(const Grid<TreeT>&, std::vector<Grid<TreeT>::Ptr>&)
2678 OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION)
2679 #undef _FUNCTION
2680
2681 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
2682
2683
2684 } // namespace tools
2685 } // namespace OPENVDB_VERSION_NAME
2686 } // namespace openvdb
2687
2688 #endif // OPENVDB_TOOLS_LEVEL_SET_UTIL_HAS_BEEN_INCLUDED
2689