| 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 |