Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @author Ken Museth | ||
5 | /// | ||
6 | /// @file tools/PointsToMask.h | ||
7 | /// | ||
8 | /// @brief This tool produces a grid where every voxel that contains a | ||
9 | /// point is active. It employs thread-local storage for best performance. | ||
10 | /// | ||
11 | /// The @c PointListT template argument below refers to any class | ||
12 | /// with the following interface (see unittest/TestPointsToMask.cc | ||
13 | /// and SOP_OpenVDB_From_Particles.cc for practical examples): | ||
14 | /// @code | ||
15 | /// | ||
16 | /// class PointList { | ||
17 | /// ... | ||
18 | /// public: | ||
19 | /// | ||
20 | /// // Return the total number of particles in list. | ||
21 | /// size_t size() const; | ||
22 | /// | ||
23 | /// // Get the world space position of the nth particle. | ||
24 | /// void getPos(size_t n, Vec3R& xyz) const; | ||
25 | /// }; | ||
26 | /// @endcode | ||
27 | /// | ||
28 | /// @note See unittest/TestPointsToMask.cc for an example. | ||
29 | /// | ||
30 | /// The @c InterruptT template argument below refers to any class | ||
31 | /// with the following interface: | ||
32 | /// @code | ||
33 | /// class Interrupter { | ||
34 | /// ... | ||
35 | /// public: | ||
36 | /// void start(const char* name = nullptr) // called when computations begin | ||
37 | /// void end() // called when computations end | ||
38 | /// bool wasInterrupted(int percent = -1) // return true to break computation | ||
39 | /// }; | ||
40 | /// @endcode | ||
41 | /// | ||
42 | /// @note If no template argument is provided for this InterruptT | ||
43 | /// the util::NullInterrupter is used which implies that all | ||
44 | /// interrupter calls are no-ops (i.e. incurs no computational overhead). | ||
45 | |||
46 | #ifndef OPENVDB_TOOLS_POINTSTOMASK_HAS_BEEN_INCLUDED | ||
47 | #define OPENVDB_TOOLS_POINTSTOMASK_HAS_BEEN_INCLUDED | ||
48 | |||
49 | |||
50 | #include "openvdb/openvdb.h" // for MaskGrid | ||
51 | #include "openvdb/Grid.h" | ||
52 | #include "openvdb/Types.h" | ||
53 | #include "openvdb/util/NullInterrupter.h" | ||
54 | #include "openvdb/thread/Threading.h" | ||
55 | |||
56 | #include <tbb/enumerable_thread_specific.h> | ||
57 | #include <tbb/parallel_for.h> | ||
58 | #include <tbb/parallel_reduce.h> | ||
59 | #include <tbb/blocked_range.h> | ||
60 | |||
61 | #include <vector> | ||
62 | |||
63 | |||
64 | namespace openvdb { | ||
65 | OPENVDB_USE_VERSION_NAMESPACE | ||
66 | namespace OPENVDB_VERSION_NAME { | ||
67 | namespace tools { | ||
68 | |||
69 | // Forward declaration of main class | ||
70 | template<typename GridT = MaskGrid, typename InterrupterT = util::NullInterrupter> | ||
71 | class PointsToMask; | ||
72 | |||
73 | /// @brief Makes every voxel of the @c grid active if it contains a point. | ||
74 | /// | ||
75 | /// @param points points that active the voxels of @c grid | ||
76 | /// @param grid on out its voxels with points are active | ||
77 | template<typename PointListT, typename GridT> | ||
78 | inline void | ||
79 | maskPoints(const PointListT& points, GridT& grid) | ||
80 | { | ||
81 | PointsToMask<GridT, util::NullInterrupter> tmp(grid, nullptr); | ||
82 | 1 | tmp.addPoints(points); | |
83 | } | ||
84 | |||
85 | /// @brief Return a MaskGrid where each binary voxel value | ||
86 | /// is on if the voxel contains one (or more) points (i.e. | ||
87 | /// the 3D position of a point is closer to this voxel than | ||
88 | /// any other voxels). | ||
89 | /// | ||
90 | /// @param points points that active the voxels in the returned grid. | ||
91 | /// @param xform transform from world space to voxels in grid space. | ||
92 | template<typename PointListT> | ||
93 | inline MaskGrid::Ptr | ||
94 | 1 | createPointMask(const PointListT& points, const math::Transform& xform) | |
95 | { | ||
96 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | MaskGrid::Ptr grid = createGrid<MaskGrid>( false ); |
97 |
3/8✓ 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.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
2 | grid->setTransform( xform.copy() ); |
98 | maskPoints( points, *grid ); | ||
99 | 1 | return grid; | |
100 | } | ||
101 | |||
102 | //////////////////////////////////////// | ||
103 | |||
104 | /// @brief Makes every voxel of a grid active if it contains a point. | ||
105 | template<typename GridT, typename InterrupterT> | ||
106 | class PointsToMask | ||
107 | { | ||
108 | public: | ||
109 | using ValueT = typename GridT::ValueType; | ||
110 | |||
111 | /// @brief Constructor from a grid and optional interrupter | ||
112 | /// | ||
113 | /// @param grid Grid whose voxels will have their state activated by points. | ||
114 | /// @param interrupter Optional interrupter to prematurely terminate execution. | ||
115 | 110 | explicit PointsToMask(GridT& grid, InterrupterT* interrupter = nullptr) | |
116 | : mGrid(&grid) | ||
117 |
7/14✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 103 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
|
111 | , mInterrupter(interrupter) |
118 | { | ||
119 | } | ||
120 | |||
121 | /// @brief Activates the state of any voxel in the input grid that contains a point. | ||
122 | /// | ||
123 | /// @param points List of points that active the voxels in the input grid. | ||
124 | /// @param grainSize Set the grain-size used for multi-threading. A value of 0 | ||
125 | /// disables multi-threading! | ||
126 | template<typename PointListT, typename VecT = Vec3R> | ||
127 | 220 | void addPoints(const PointListT& points, size_t grainSize = 1024) | |
128 | { | ||
129 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
220 | if (mInterrupter) mInterrupter->start("PointsToMask: adding points"); |
130 |
2/2✓ Branch 0 taken 109 times.
✓ Branch 1 taken 1 times.
|
220 | if (grainSize > 0) { |
131 | 218 | typename GridT::Ptr examplar = mGrid->copyWithNewTree(); | |
132 |
1/2✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
|
218 | PoolType pool( *examplar );//thread local storage pool of grids |
133 | AddPoints<PointListT, VecT> tmp(points, pool, grainSize, *this ); | ||
134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
218 | if ( this->interrupt() ) return; |
135 |
1/2✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
|
218 | ReducePool reducePool(pool, mGrid, size_t(0)); |
136 | } else { | ||
137 | 2 | const math::Transform& xform = mGrid->transform(); | |
138 | typename GridT::Accessor acc = mGrid->getAccessor(); | ||
139 | VecT wPos; | ||
140 |
2/2✓ Branch 0 taken 14992384 times.
✓ Branch 1 taken 1 times.
|
29984770 | for (size_t i = 0, n = points.size(); i < n; ++i) { |
141 |
2/4✓ Branch 1 taken 14992384 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14992384 times.
✗ Branch 4 not taken.
|
29984768 | if ( this->interrupt() ) break; |
142 | points.getPos(i, wPos); | ||
143 |
1/4✓ Branch 1 taken 14992384 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
59969536 | acc.setValueOn( xform.worldToIndexCellCentered( wPos ) ); |
144 | } | ||
145 | } | ||
146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
220 | if (mInterrupter) mInterrupter->end(); |
147 | } | ||
148 | |||
149 | private: | ||
150 | // Disallow copy construction and copy by assignment! | ||
151 | PointsToMask(const PointsToMask&);// not implemented | ||
152 | PointsToMask& operator=(const PointsToMask&);// not implemented | ||
153 | |||
154 | 29990578 | bool interrupt() const | |
155 | { | ||
156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14997767 times.
|
29990578 | if (mInterrupter && util::wasInterrupted(mInterrupter)) { |
157 | ✗ | thread::cancelGroupExecution(); | |
158 | ✗ | return true; | |
159 | } | ||
160 | return false; | ||
161 | } | ||
162 | |||
163 | // Private struct that implements concurrent thread-local | ||
164 | // insersion of points into a grid | ||
165 | using PoolType = tbb::enumerable_thread_specific<GridT>; | ||
166 | template<typename PointListT, typename VecT = Vec3R> struct AddPoints; | ||
167 | |||
168 | // Private class that implements concurrent reduction of a thread-local pool | ||
169 | struct ReducePool; | ||
170 | |||
171 | GridT* mGrid; | ||
172 | InterrupterT* mInterrupter; | ||
173 | };// PointsToMask | ||
174 | |||
175 | // Private member class that implements concurrent thread-local | ||
176 | // insersion of points into a grid | ||
177 | template<typename GridT, typename InterrupterT> | ||
178 | template<typename PointListT, typename VecT> | ||
179 | struct PointsToMask<GridT, InterrupterT>::AddPoints | ||
180 | { | ||
181 | 109 | AddPoints(const PointListT& points, | |
182 | PoolType& pool, | ||
183 | size_t grainSize, | ||
184 | const PointsToMask& parent) | ||
185 | : mPoints(&points) | ||
186 | , mParent(&parent) | ||
187 |
3/8✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 102 times.
✗ Branch 11 not taken.
|
109 | , mPool(&pool) |
188 | { | ||
189 |
6/16✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 19 taken 102 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 102 times.
✗ Branch 23 not taken.
|
109 | tbb::parallel_for(tbb::blocked_range<size_t>(0, mPoints->size(), grainSize), *this); |
190 | } | ||
191 | 10548 | void operator()(const tbb::blocked_range<size_t>& range) const | |
192 | { | ||
193 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5274 times.
|
10548 | if (mParent->interrupt()) return; |
194 | 10548 | GridT& grid = mPool->local(); | |
195 | const math::Transform& xform = grid.transform(); | ||
196 | typename GridT::Accessor acc = grid.getAccessor(); | ||
197 | VecT wPos; | ||
198 |
2/2✓ Branch 0 taken 53389252 times.
✓ Branch 1 taken 5274 times.
|
106789052 | for (size_t i=range.begin(), n=range.end(); i!=n; ++i) { |
199 |
1/2✓ Branch 1 taken 53389252 times.
✗ Branch 2 not taken.
|
106778504 | mPoints->getPos(i, wPos); |
200 |
1/4✓ Branch 1 taken 53389252 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
213557008 | acc.setValueOn( xform.worldToIndexCellCentered( wPos ) ); |
201 | } | ||
202 | } | ||
203 | const PointListT* mPoints; | ||
204 | const PointsToMask* mParent; | ||
205 | PoolType* mPool; | ||
206 | |||
207 | };// end of private member class AddPoints | ||
208 | |||
209 | // Private member class that implements concurrent reduction of a thread-local pool | ||
210 | template<typename GridT, typename InterrupterT> | ||
211 | struct PointsToMask<GridT, InterrupterT>::ReducePool | ||
212 | { | ||
213 | using VecT = std::vector<GridT*>; | ||
214 | using IterT = typename VecT::iterator; | ||
215 | using RangeT = tbb::blocked_range<IterT>; | ||
216 | |||
217 | 114 | ReducePool(PoolType& pool, GridT* grid, size_t grainSize = 1) | |
218 | : mOwnsGrid(false) | ||
219 | 114 | , mGrid(grid) | |
220 | { | ||
221 |
1/2✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
|
114 | if (grainSize == 0) { |
222 |
2/2✓ Branch 0 taken 193 times.
✓ Branch 1 taken 109 times.
|
315 | for (typename PoolType::const_iterator i = pool.begin(); i != pool.end(); ++i) { |
223 |
1/2✓ Branch 0 taken 193 times.
✗ Branch 1 not taken.
|
201 | mGrid->topologyUnion(*i); |
224 | } | ||
225 | } else { | ||
226 | ✗ | VecT grids( pool.size() ); | |
227 | typename PoolType::iterator i = pool.begin(); | ||
228 | ✗ | for (size_t j=0; j != pool.size(); ++i, ++j) grids[j] = &(*i); | |
229 | ✗ | tbb::parallel_reduce( RangeT( grids.begin(), grids.end(), grainSize ), *this ); | |
230 | } | ||
231 | 114 | } | |
232 | |||
233 | ✗ | ReducePool(const ReducePool&, tbb::split) | |
234 | : mOwnsGrid(true) | ||
235 | ✗ | , mGrid(new GridT()) | |
236 | { | ||
237 | } | ||
238 | |||
239 |
5/29✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 2 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 102 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
|
109 | ~ReducePool() { if (mOwnsGrid) delete mGrid; } |
240 | |||
241 | ✗ | void operator()(const RangeT& r) | |
242 | { | ||
243 | ✗ | for (IterT i=r.begin(); i!=r.end(); ++i) mGrid->topologyUnion( *(*i) ); | |
244 | } | ||
245 | |||
246 | ✗ | void join(ReducePool& other) { mGrid->topologyUnion(*other.mGrid); } | |
247 | |||
248 | const bool mOwnsGrid; | ||
249 | GridT* mGrid; | ||
250 | };// end of private member class ReducePool | ||
251 | |||
252 | } // namespace tools | ||
253 | } // namespace OPENVDB_VERSION_NAME | ||
254 | } // namespace openvdb | ||
255 | |||
256 | #endif // OPENVDB_TOOLS_POINTSTOMASK_HAS_BEEN_INCLUDED | ||
257 |