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 |