Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | // | ||
4 | /// @author Nick Avramoussis | ||
5 | /// | ||
6 | /// @file PointTransfer.h | ||
7 | /// | ||
8 | /// @brief Framework methods for rasterizing PointDataGrid data to Trees. | ||
9 | /// | ||
10 | /// @details Provides a generic inherited interface for deriving transfer | ||
11 | /// schemes that represent how point data should be rasterized. The provided | ||
12 | /// components together support the transfer of multiple attributes to | ||
13 | /// arbitrary and multiple grid types. Target grids must have the same | ||
14 | /// transform, but this transform can differ from the source PointDataGrid | ||
15 | /// (multiple instantiations of rasterize() should instead be invoked to | ||
16 | /// transfer to grids of different transforms). Arbitrary attributes can be | ||
17 | /// accessed and transfered to arbitrary trees. | ||
18 | /// | ||
19 | |||
20 | #ifndef OPENVEB_POINTS_TRANSFER_HAS_BEEN_INCLUDED | ||
21 | #define OPENVEB_POINTS_TRANSFER_HAS_BEEN_INCLUDED | ||
22 | |||
23 | #include <openvdb/openvdb.h> | ||
24 | #include <openvdb/Types.h> | ||
25 | #include <openvdb/Grid.h> | ||
26 | #include <openvdb/math/Transform.h> | ||
27 | #include <openvdb/util/NullInterrupter.h> | ||
28 | #include <openvdb/thread/Threading.h> | ||
29 | |||
30 | #include <type_traits> | ||
31 | #include <tuple> | ||
32 | |||
33 | namespace openvdb { | ||
34 | OPENVDB_USE_VERSION_NAMESPACE | ||
35 | namespace OPENVDB_VERSION_NAME { | ||
36 | namespace points { | ||
37 | |||
38 | /// @par A transfer scheme must be configured to call the provided | ||
39 | /// rasterize methods. See below for an example or | ||
40 | /// PointRasterizeSDF.h/PointRasterizeTrilinear.h for implementations. | ||
41 | /// @code | ||
42 | /// struct Transfer | ||
43 | /// { | ||
44 | /// /// @return Returns the tree topology to loop over. This can be different | ||
45 | /// /// from the destination tree i.e. This can act as a mask. | ||
46 | /// inline auto& topology(); | ||
47 | /// | ||
48 | /// /// @brief The maximum lookup range of this transfer scheme in index | ||
49 | /// /// space of the source points. | ||
50 | /// /// @details The return value represent how far away from the destination | ||
51 | /// /// leaf node points should be accessed. | ||
52 | /// /// @param origin The leaf origin of the topology being accessed | ||
53 | /// /// @param idx The leaf index of the topology being accessed | ||
54 | /// inline Int32 range(const Coord& origin, size_t idx) const; | ||
55 | /// | ||
56 | /// /// @brief The initialize function, called on each leaf which has valid | ||
57 | /// /// topology to write to. | ||
58 | /// /// @param origin The leaf origin of the topology being accessed | ||
59 | /// /// @param idx The leaf index of the topology being accessed | ||
60 | /// /// @param bounds The active voxel bounds of the leaf | ||
61 | /// inline void initialize(const Coord& origin, size_t idx, const CoordBBox& bounds); | ||
62 | /// | ||
63 | /// /// @brief Run each time a point leaf is accessed. Typically this is | ||
64 | /// /// where attribute handles can be constructed | ||
65 | /// /// @param leaf The PointDataLeafNode which is being accessed. | ||
66 | /// /// @return Return true to continue rasterization, false to early exit | ||
67 | /// /// and skip the current leaf's contribution to the destination volume. | ||
68 | /// inline bool startPointLeaf(const PointDataTree::LeafNodeType& leaf); | ||
69 | /// | ||
70 | /// /// @brief The point stamp function. Each point which contributes to | ||
71 | /// /// the current leaf will call this function exactly once. | ||
72 | /// /// @param ijk The current voxel containing the point being rasterized. | ||
73 | /// /// May be outside the destination leaf node depending on the range() | ||
74 | /// /// @param id The point index being rasterized | ||
75 | /// /// @param bounds The active bounds of the leaf node. | ||
76 | /// void rasterizePoint(const Coord& ijk, | ||
77 | /// const Index id, | ||
78 | /// const CoordBBox& bounds); | ||
79 | /// | ||
80 | /// /// @brief Run each time a point leaf is finished with. | ||
81 | /// /// @param leaf The PointDataLeafNode which was being accessed. | ||
82 | /// /// @return Return true to continue rasterization, false to early exit | ||
83 | /// /// and stop rasterization to the destination leaf node. | ||
84 | /// inline bool endPointLeaf(const PointDataTree::LeafNodeType& leaf); | ||
85 | /// | ||
86 | /// /// @brief The finalization function for the given destination tree(s). | ||
87 | /// /// @param origin The leaf origin of the topology being accessed | ||
88 | /// /// @param idx The leaf index of the topology being accessed | ||
89 | /// /// @return Return true to stop, false to recursively rasterize | ||
90 | /// inline bool finalize(const Coord& origin, size_t idx); | ||
91 | /// }; | ||
92 | /// @endcode | ||
93 | /// | ||
94 | /// | ||
95 | /// Below is a full example using the native components. | ||
96 | /// | ||
97 | /// @code | ||
98 | /// /// @brief Sum point distances into a target float tree | ||
99 | /// /// Note: Using TransformTransfer to handle different index spaces, and | ||
100 | /// /// VolumeTransfer for automatic buffer setup | ||
101 | /// struct MyTransfer : | ||
102 | /// public TransformTransfer, | ||
103 | /// public VolumeTransfer<FloatTree> | ||
104 | /// { | ||
105 | /// MyTransfer(FloatGrid& dest, const PointDataGrid& source) | ||
106 | /// : TransformTransfer(source.transform(), dest.transform()) | ||
107 | /// , VolumeTransfer(dest.tree()) | ||
108 | /// , mHandle(nullptr) {} | ||
109 | /// | ||
110 | /// MyTransfer(const MyTransfer& other) | ||
111 | /// : TransformTransfer(other) | ||
112 | /// , VolumeTransfer(other) | ||
113 | /// , mHandle(nullptr) {} | ||
114 | /// | ||
115 | /// /// @brief Range in index space of the source points | ||
116 | /// Int32 range(const Coord&, size_t) const { return Int32(1); } | ||
117 | /// | ||
118 | /// /// @brief Every time we start a new point leaf, init the position array. | ||
119 | /// /// Always return true as we don't skip any leaf nodes. | ||
120 | /// bool startPointLeaf(const PointDataTree::LeafNodeType& leaf) | ||
121 | /// { | ||
122 | /// mHandle.reset(new AttributeHandle<Vec3f>(leaf.constAttributeArray("P")); | ||
123 | /// return true; | ||
124 | /// } | ||
125 | /// | ||
126 | /// /// @brief For each point, compute its relative index space position in | ||
127 | /// /// the destination tree and sum the length of its distance | ||
128 | /// void rasterizePoint(const Coord& ijk, const Index id, const CoordBBox& bounds) | ||
129 | /// { | ||
130 | /// Vec3d P = ijk.asVec3d() + Vec3d(this->mHandle->get(id)); | ||
131 | /// P = this->transformSourceToTarget(P); // TransformTransfer::transformSourceToTarget | ||
132 | /// // for each active voxel, accumulate distance | ||
133 | /// const auto* mask = this->mask(); // VolumeTransfer::mask | ||
134 | /// for (auto& coord : bounds) { | ||
135 | /// const Index voxel = FloatTree::LeafNodeType::coordToOffset(coord); | ||
136 | /// if (!mask->isOn(voxel)) continue; | ||
137 | /// Vec3d dist = coord.asVec3d() - P; | ||
138 | /// this->buffer()[voxel] += dist.length(); // VolumeTransfer::buffer | ||
139 | /// } | ||
140 | /// } | ||
141 | /// | ||
142 | /// /// @brief Return true for endPointLeaf() to continue, false for finalize() so | ||
143 | /// /// we don't recurse. | ||
144 | /// bool endPointLeaf(const PointDataTree::LeafNodeType&) { return true; } | ||
145 | /// bool finalize(const Coord&, size_t) { return false; } | ||
146 | /// | ||
147 | /// private: | ||
148 | /// std::unique_ptr<AttributeHandle<Vec3f>> mHandle; | ||
149 | /// }; | ||
150 | /// @endcode | ||
151 | |||
152 | |||
153 | /// @brief Perform potentially complex rasterization from a user defined | ||
154 | /// transfer scheme. | ||
155 | /// @details The method works by looping over a single Tree topology, looking | ||
156 | /// up point data at a position relative to that topology and passing that | ||
157 | /// data to a transfer scheme TransferT. | ||
158 | /// @note Each thread receives a copy of the transfer scheme object. | ||
159 | /// @param points the point data grid to rasterize | ||
160 | /// @param transfer the transfer scheme | ||
161 | /// @param filter optional point filter | ||
162 | /// @param interrupter optional interrupter | ||
163 | template <typename PointDataTreeOrGridT, | ||
164 | typename TransferT, | ||
165 | typename FilterT = NullFilter, | ||
166 | typename InterrupterT = util::NullInterrupter> | ||
167 | inline void | ||
168 | rasterize(const PointDataTreeOrGridT& points, | ||
169 | TransferT& transfer, | ||
170 | const FilterT& filter = NullFilter(), | ||
171 | InterrupterT* interrupter = nullptr); | ||
172 | |||
173 | |||
174 | /////////////////////////////////////////////////// | ||
175 | |||
176 | /// @brief The TransformTransfer module should be used if the source transform | ||
177 | /// of the input points and the target transforms of the destination volumes | ||
178 | /// differ. The default rasterizer will skip index to world (and vice versa) | ||
179 | /// transformations unless a transfer scheme derives from a TransformTransfer. | ||
180 | struct TransformTransfer | ||
181 | { | ||
182 | TransformTransfer(const math::Transform& st, | ||
183 | const math::Transform& tt) | ||
184 | 49 | : mSourceTransform(st) | |
185 | 12 | , mTargetTransform(tt) {} | |
186 | |||
187 | template <typename T> | ||
188 | 3677 | inline auto transformSourceToTarget(const T& value) const | |
189 | { | ||
190 | 3677 | const auto result = mSourceTransform.indexToWorld(value); | |
191 | 3677 | return mTargetTransform.worldToIndex(result); | |
192 | } | ||
193 | |||
194 | template <typename T> | ||
195 | inline auto transformTargetToSource(const T& value) const | ||
196 | { | ||
197 | const auto result = mTargetTransform.indexToWorld(value); | ||
198 | return mSourceTransform.worldToIndex(result); | ||
199 | } | ||
200 | |||
201 | 2739 | const math::Transform& sourceTransform() const { return mSourceTransform; } | |
202 | 104346 | const math::Transform& targetTransform() const { return mTargetTransform; } | |
203 | |||
204 | private: | ||
205 | const math::Transform& mSourceTransform; | ||
206 | const math::Transform& mTargetTransform; | ||
207 | }; | ||
208 | |||
209 | /// @brief The VolumeTransfer module provides methods to automatically setup | ||
210 | /// and access destination buffers for multiple target volumes of arbitrary | ||
211 | /// types. Deriving from a VolumeTransfer ensures that the available | ||
212 | /// buffers correlate to the order of the provided tree arguments. | ||
213 | template <typename ...TreeTypes> | ||
214 | struct VolumeTransfer | ||
215 | { | ||
216 | static const size_t Size = sizeof...(TreeTypes); | ||
217 | using TreeTupleT = std::tuple<TreeTypes*...>; | ||
218 | |||
219 | template <size_t Idx> using TreeType = typename std::tuple_element<Idx, std::tuple<TreeTypes...>>::type; | ||
220 | template <size_t Idx> using ValueType = typename TreeType<Idx>::ValueType; | ||
221 | template <typename T> struct TypeResolver { using Type = typename T::ValueType; }; | ||
222 | using NodeMaskT = typename TreeType<0>::LeafNodeType::NodeMaskType; | ||
223 | |||
224 | VolumeTransfer(TreeTypes*... trees); | ||
225 | |||
226 | 2 | VolumeTransfer(TreeTypes&... trees) | |
227 | 2 | : VolumeTransfer(&trees...) {} | |
228 | |||
229 | 301 | VolumeTransfer(const VolumeTransfer& other) | |
230 | : mTreeArray(other.mTreeArray) | ||
231 | , mBuffers() | ||
232 |
4/4✓ Branch 0 taken 295 times.
✓ Branch 1 taken 295 times.
✓ Branch 2 taken 295 times.
✓ Branch 3 taken 295 times.
|
1204 | , mMasks() |
233 | { | ||
234 | mBuffers.fill(nullptr); | ||
235 | mMasks.fill(nullptr); | ||
236 | 301 | } | |
237 | |||
238 | 14 | inline TreeType<0>& topology() { return *(std::get<0>(mTreeArray)); } | |
239 | |||
240 | inline void initialize(const Coord& origin, const size_t, const CoordBBox&); | ||
241 | |||
242 | template <size_t Idx> | ||
243 | inline ValueType<Idx>* buffer() | ||
244 | { | ||
245 | 3448 | return static_cast<ValueType<Idx>*>(mBuffers[Idx]); | |
246 | } | ||
247 | |||
248 | template <size_t Idx> | ||
249 | inline const ValueType<Idx>* buffer() const | ||
250 | { | ||
251 | return static_cast<ValueType<Idx>*>(mBuffers[Idx]); | ||
252 | } | ||
253 | |||
254 | template <size_t Idx> | ||
255 |
2/8✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 192 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 20 taken 192 times.
✗ Branch 21 not taken.
|
4945 | inline NodeMaskT* mask() { return mMasks[Idx]; } |
256 | inline NodeMaskT* mask(const size_t idx) { return mMasks[idx]; } | ||
257 | |||
258 | template <size_t Idx> | ||
259 | inline const NodeMaskT* mask() const { return mMasks[Idx]; } | ||
260 | inline const NodeMaskT* mask(const size_t idx) const { return mMasks[idx]; } | ||
261 | |||
262 | template <typename FunctorT> | ||
263 | inline void foreach(const FunctorT& functor); | ||
264 | |||
265 | private: | ||
266 | const TreeTupleT mTreeArray; | ||
267 | std::array<void*, Size> mBuffers; | ||
268 | std::array<NodeMaskT*, Size> mMasks; | ||
269 | }; | ||
270 | |||
271 | /// @brief VolumeTransfer specialization for a single target volume | ||
272 | /// @todo this specialization should avoid the probe | ||
273 | template <typename TreeT> | ||
274 | struct VolumeTransfer<TreeT> | ||
275 | { | ||
276 | using TreeType = TreeT; | ||
277 | using ValueType = typename TreeType::ValueType; | ||
278 | using NodeMaskT = typename TreeType::LeafNodeType::NodeMaskType; | ||
279 | |||
280 | static_assert(std::is_base_of<TreeBase, TreeType>::value, | ||
281 | "One or more template arguments to VolumeTransfer " | ||
282 | "are not a valid openvdb::Tree type."); | ||
283 | |||
284 | 48 | VolumeTransfer(TreeType* tree) | |
285 | : mTree(tree) | ||
286 | , mBuffer(nullptr) | ||
287 |
13/70✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 16 taken 8 times.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 22 taken 17 times.
✗ 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 taken 1 times.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✓ Branch 70 taken 1 times.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✓ Branch 82 taken 1 times.
✗ Branch 83 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✓ Branch 94 taken 1 times.
✗ Branch 95 not taken.
✓ Branch 97 taken 1 times.
✗ Branch 98 not taken.
✓ Branch 100 taken 1 times.
✗ Branch 101 not taken.
✓ Branch 103 taken 1 times.
✗ Branch 104 not taken.
|
48 | , mMask(nullptr) { |
288 | assert(tree); | ||
289 | } | ||
290 | |||
291 | VolumeTransfer(TreeType& tree) | ||
292 | : VolumeTransfer(&tree) {} | ||
293 | |||
294 | 55 | VolumeTransfer(const VolumeTransfer& other) | |
295 | 55 | : mTree(other.mTree) | |
296 | , mBuffer(nullptr) | ||
297 | 55 | , mMask(nullptr) {} | |
298 | |||
299 | 48 | inline TreeType& topology() { return *mTree; } | |
300 | |||
301 | 1755 | inline void initialize(const Coord& origin, const size_t, const CoordBBox&) | |
302 | { | ||
303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1695 times.
|
1755 | assert(mTree); |
304 |
1/2✓ Branch 0 taken 1695 times.
✗ Branch 1 not taken.
|
1755 | if (auto leaf = mTree->probeLeaf(origin)) { |
305 | 1755 | mBuffer = leaf->buffer().data(); | |
306 | 1755 | mMask = &(leaf->getValueMask()); | |
307 | } | ||
308 | else { | ||
309 | ✗ | mBuffer = nullptr; | |
310 | ✗ | mMask = nullptr; | |
311 | } | ||
312 | 1755 | } | |
313 | |||
314 | 5591 | inline ValueType* buffer() { return mBuffer; } | |
315 | inline const ValueType* buffer() const { return mBuffer; } | ||
316 |
4/8✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 502 times.
✓ Branch 11 taken 280 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 20 taken 790 times.
✓ Branch 21 taken 880 times.
|
9196 | inline NodeMaskT* mask() { return mMask; } |
317 | inline const NodeMaskT* mask() const { return mMask; } | ||
318 | |||
319 | // compatibility with multi tree containers | ||
320 | template <size_t> inline ValueType* buffer() { return this->buffer(); } | ||
321 | template <size_t> inline const ValueType* buffer() const { return this->buffer(); } | ||
322 | template <size_t> inline NodeMaskT* mask() { return this->mask(); } | ||
323 | template <size_t> inline const NodeMaskT* mask() const { return this->mask(); } | ||
324 | |||
325 | private: | ||
326 | TreeType* const mTree; | ||
327 | ValueType* mBuffer; | ||
328 | NodeMaskT* mMask; | ||
329 | }; | ||
330 | |||
331 | namespace transfer_internal | ||
332 | { | ||
333 | template<typename T, typename F, size_t... Is> | ||
334 | 1568 | void foreach(T&& t, const F& func, std::integer_sequence<size_t, Is...>) | |
335 | { | ||
336 | 1568 | auto init = { (func(std::get<Is>(t), Is), 0)... }; | |
337 | (void)init; | ||
338 | 1568 | } | |
339 | |||
340 | template<typename T, typename F, size_t... Is> | ||
341 | void foreach(void** buffers, const F& func, std::integer_sequence<size_t, Is...>) | ||
342 | { | ||
343 | int init[sizeof...(Is)] = { | ||
344 | (func(static_cast<typename std::tuple_element<Is, T>::type*> | ||
345 | (*(buffers + Is)), Is), 0)... | ||
346 | }; | ||
347 | } | ||
348 | |||
349 | template<typename T, template <typename> class R, typename F, size_t... Is> | ||
350 | void foreach(void** buffers, const F& func, std::integer_sequence<size_t, Is...>) | ||
351 | { | ||
352 | int init[sizeof...(Is)] = { | ||
353 | (func(static_cast<typename R<typename std::tuple_element<Is, T>::type>::Type*> | ||
354 | (*(buffers + Is)), Is), 0)... | ||
355 | }; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | template <typename ...TreeTypes> | ||
360 | 16 | VolumeTransfer<TreeTypes...>::VolumeTransfer(TreeTypes*... trees) | |
361 | : mTreeArray({ trees... }) | ||
362 | , mBuffers() | ||
363 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14 times.
|
48 | , mMasks() |
364 | { | ||
365 | 16 | transfer_internal::foreach(mTreeArray, [](auto&& tree, const size_t) { | |
366 | using TreeT = typename std::remove_pointer<typename std::decay<decltype(tree)>::type>::type; | ||
367 | static_assert(std::is_base_of<TreeBase, TreeT>::value, | ||
368 | "One or more template arguments to VolumeTransfer " | ||
369 | "are not a valid openvdb::Tree type."); | ||
370 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
|
14 | assert(tree); |
371 | }, std::make_integer_sequence<size_t, Size>()); | ||
372 | |||
373 | mBuffers.fill(nullptr); | ||
374 | mMasks.fill(nullptr); | ||
375 | 16 | } | |
376 | |||
377 | template <typename ...TreeTypes> | ||
378 | inline void VolumeTransfer<TreeTypes...>::initialize(const Coord& origin, const size_t, const CoordBBox&) | ||
379 | { | ||
380 | 772 | transfer_internal::foreach(mTreeArray, | |
381 | 3082 | [&](auto&& tree, const size_t i) { | |
382 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 769 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 769 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
|
1540 | assert(tree); |
383 |
4/8✓ Branch 0 taken 769 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 769 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1540 | if (auto leaf = tree->probeLeaf(origin)) { |
384 | 1540 | mBuffers[i] = static_cast<void*>(leaf->buffer().data()); | |
385 | 1540 | mMasks[i] = &(leaf->getValueMask()); | |
386 | } | ||
387 | else { | ||
388 | ✗ | mBuffers[i] = nullptr; | |
389 | ✗ | mMasks[i] = nullptr; | |
390 | } | ||
391 | }, std::make_integer_sequence<size_t, Size>()); | ||
392 | } | ||
393 | |||
394 | template <typename ...TreeTypes> | ||
395 | template <typename FunctorT> | ||
396 | inline void VolumeTransfer<TreeTypes...>::foreach(const FunctorT& functor) | ||
397 | { | ||
398 | transfer_internal::foreach<TreeTupleT, TypeResolver>(mBuffers.data(), functor, | ||
399 | std::make_integer_sequence<size_t, Size>()); | ||
400 | } | ||
401 | |||
402 | namespace transfer_internal | ||
403 | { | ||
404 | template <typename TransferT, | ||
405 | typename TopologyT, | ||
406 | typename PointFilterT = points::NullFilter, | ||
407 | typename InterrupterT = util::NullInterrupter> | ||
408 |
6/12✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
|
7 | struct RasterizePoints |
409 | { | ||
410 | using LeafManagerT = tree::LeafManager<TopologyT>; | ||
411 | using LeafNodeT = typename LeafManagerT::LeafNodeType; | ||
412 | |||
413 | static const Index DIM = TopologyT::LeafNodeType::DIM; | ||
414 | static const Int32 DIM32 = static_cast<Int32>(DIM); | ||
415 | static const Index LOG2DIM = TopologyT::LeafNodeType::LOG2DIM; | ||
416 | |||
417 |
6/16✓ 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 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 22 taken 3 times.
✗ Branch 23 not taken.
|
114 | RasterizePoints(const points::PointDataTree& tree, |
418 | const TransferT& transfer, | ||
419 | const PointFilterT& filter = PointFilterT(), | ||
420 | InterrupterT* interrupter = nullptr) | ||
421 | : mPointAccessor(tree) | ||
422 | , mTransfer(transfer) | ||
423 | , mFilter(filter) | ||
424 | 114 | , mInterrupter(interrupter) {} | |
425 | |||
426 | 4930 | void operator()(LeafNodeT& leaf, const size_t idx) const | |
427 | { | ||
428 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2465 times.
|
4930 | if (util::wasInterrupted(mInterrupter)) { |
429 | ✗ | thread::cancelGroupExecution(); | |
430 | ✗ | return; | |
431 | } | ||
432 | |||
433 | const Coord& origin = leaf.origin(); | ||
434 | auto& mask = leaf.getValueMask(); | ||
435 | |||
436 | 4930 | CoordBBox bounds; | |
437 | |||
438 | bool state; | ||
439 |
2/2✓ Branch 0 taken 416 times.
✓ Branch 1 taken 724 times.
|
2280 | if (mask.isConstant(state)) { |
440 |
1/2✓ Branch 0 taken 416 times.
✗ Branch 1 not taken.
|
832 | if (!state) return; // all inactive |
441 | 832 | else bounds = leaf.getNodeBoundingBox(); | |
442 | } | ||
443 | else { | ||
444 | // Use evalActiveBoundingBox over getNodeBoundingBox() | ||
445 | // to get a better approximation | ||
446 | 4098 | leaf.evalActiveBoundingBox(bounds); | |
447 | ✗ | assert(!bounds.empty()); | |
448 | } | ||
449 | |||
450 | 4898 | mTransfer.initialize(origin, idx, bounds); | |
451 | |||
452 | 4930 | CoordBBox search = bounds.expandBy(mTransfer.range(origin, idx)); | |
453 | 4790 | this->transform<>(search); | |
454 | |||
455 | // start the iteration from a leaf origin | ||
456 | const Coord min = (search.min() & ~(DIM-1)); | ||
457 | const Coord& max = search.max(); | ||
458 | 1020 | PointFilterT localFilter(mFilter); | |
459 | |||
460 | // loop over overlapping leaf nodes | ||
461 | Coord leafOrigin; | ||
462 |
2/2✓ Branch 0 taken 26386 times.
✓ Branch 1 taken 2465 times.
|
57702 | for (leafOrigin[0] = min[0]; leafOrigin[0] <= max[0]; leafOrigin[0]+=DIM32) { |
463 |
2/2✓ Branch 0 taken 1335361 times.
✓ Branch 1 taken 26386 times.
|
2723494 | for (leafOrigin[1] = min[1]; leafOrigin[1] <= max[1]; leafOrigin[1]+=DIM32) { |
464 |
2/2✓ Branch 0 taken 92466698 times.
✓ Branch 1 taken 1335361 times.
|
187604118 | for (leafOrigin[2] = min[2]; leafOrigin[2] <= max[2]; leafOrigin[2]+=DIM32) { |
465 | |||
466 | // if no overlap, continue | ||
467 | CoordBBox pbox = CoordBBox::createCube(leafOrigin, DIM32); | ||
468 | 184933396 | pbox.intersect(search); | |
469 | 184916854 | if (pbox.empty()) continue; | |
470 | |||
471 | // if no points, continue | ||
472 | 184933396 | const auto* pointLeaf = mPointAccessor.probeConstLeaf(leafOrigin); | |
473 |
2/2✓ Branch 0 taken 92458427 times.
✓ Branch 1 taken 8271 times.
|
184933396 | if (!pointLeaf) continue; |
474 |
3/4✓ Branch 1 taken 2287 times.
✓ Branch 2 taken 5977 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2287 times.
|
16528 | if (!mTransfer.startPointLeaf(*pointLeaf)) continue; |
475 |
1/2✓ Branch 1 taken 2288 times.
✗ Branch 2 not taken.
|
4576 | localFilter.reset(*pointLeaf); |
476 | |||
477 | // loop over point voxels which contribute to this leaf | ||
478 | const Coord& pmin(pbox.min()); | ||
479 | const Coord& pmax(pbox.max()); | ||
480 |
2/2✓ Branch 0 taken 56017 times.
✓ Branch 1 taken 8271 times.
|
128576 | for (Coord ijk = pmin; ijk.x() <= pmax.x(); ++ijk.x()) { |
481 | 112034 | const Index i = ((ijk.x() & (DIM-1u)) << 2*LOG2DIM); // unsigned bit shift mult | |
482 |
2/2✓ Branch 0 taken 386198 times.
✓ Branch 1 taken 56017 times.
|
884430 | for (ijk.y() = pmin.y(); ijk.y() <= pmax.y(); ++ijk.y()) { |
483 | 772396 | const Index ij = i + ((ijk.y() & (DIM-1u)) << LOG2DIM); | |
484 |
2/2✓ Branch 0 taken 2708203 times.
✓ Branch 1 taken 386198 times.
|
6188802 | for (ijk.z() = pmin.z(); ijk.z() <= pmax.z(); ++ijk.z()) { |
485 | // voxel should be in this points leaf | ||
486 | ✗ | assert((ijk & ~(DIM-1u)) == leafOrigin); | |
487 | 5416406 | const Index index = ij + /*k*/(ijk.z() & (DIM-1u)); | |
488 |
1/2✓ Branch 1 taken 2708203 times.
✗ Branch 2 not taken.
|
5416406 | const Index end = pointLeaf->getValue(index); |
489 |
3/4✓ Branch 0 taken 2703106 times.
✓ Branch 1 taken 5097 times.
✓ Branch 3 taken 2703106 times.
✗ Branch 4 not taken.
|
6984372 | Index id = (index == 0) ? 0 : Index(pointLeaf->getValue(index - 1)); |
490 |
2/2✓ Branch 0 taken 8233 times.
✓ Branch 1 taken 2708203 times.
|
5432872 | for (; id < end; ++id) { |
491 |
3/4✓ Branch 1 taken 2291 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1739 times.
✓ Branch 4 taken 552 times.
|
4582 | if (!localFilter.valid(&id)) continue; |
492 |
1/2✓ Branch 1 taken 6417 times.
✗ Branch 2 not taken.
|
12974 | mTransfer.rasterizePoint(ijk, id, bounds); |
493 | } //point idx | ||
494 | } | ||
495 | } | ||
496 | } // outer point voxel | ||
497 | |||
498 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4232 times.
|
8464 | if (!mTransfer.endPointLeaf(*pointLeaf)) { |
499 | // rescurse if necessary | ||
500 | ✗ | if (!mTransfer.finalize(origin, idx)) { | |
501 | ✗ | this->operator()(leaf, idx); | |
502 | } | ||
503 | ✗ | return; | |
504 | } | ||
505 | } | ||
506 | } | ||
507 | } // outer leaf node | ||
508 | |||
509 | // rescurse if necessary | ||
510 |
3/4✓ Branch 1 taken 317 times.
✓ Branch 2 taken 2143 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 317 times.
|
4920 | if (!mTransfer.finalize(origin, idx)) { |
511 | ✗ | this->operator()(leaf, idx); | |
512 | } | ||
513 | } | ||
514 | |||
515 | void operator()(const typename LeafManagerT::LeafRange& range) const | ||
516 | { | ||
517 | for (auto leaf = range.begin(); leaf; ++leaf) { | ||
518 | (*this)(*leaf, leaf.pos()); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | private: | ||
523 | |||
524 | template <typename EnableT = TransferT> | ||
525 | typename std::enable_if<std::is_base_of<TransformTransfer, EnableT>::value>::type | ||
526 | 4790 | transform(CoordBBox& bounds) const | |
527 | { | ||
528 | const TransformTransfer* transform = | ||
529 | static_cast<TransformTransfer*>(&mTransfer); | ||
530 | 4790 | const BBoxd bbox(bounds.min().asVec3d(), bounds.max().asVec3d()); | |
531 | 4790 | bounds = transform->sourceTransform().worldToIndexCellCentered( | |
532 | 4790 | transform->targetTransform().indexToWorld(bbox)); | |
533 | } | ||
534 | |||
535 | template <typename EnableT = TransferT> | ||
536 | typename std::enable_if<!std::is_base_of<TransformTransfer, EnableT>::value>::type | ||
537 | transform(CoordBBox&) const {} | ||
538 | |||
539 | private: | ||
540 | const PointDataGrid::ConstAccessor mPointAccessor; | ||
541 | mutable TransferT mTransfer; | ||
542 | const PointFilterT& mFilter; | ||
543 | InterrupterT* mInterrupter; | ||
544 | }; | ||
545 | |||
546 | } // namespace transfer_internal | ||
547 | |||
548 | /////////////////////////////////////////////////// | ||
549 | /////////////////////////////////////////////////// | ||
550 | |||
551 | template <typename PointDataTreeOrGridT, | ||
552 | typename TransferT, | ||
553 | typename FilterT, | ||
554 | typename InterrupterT> | ||
555 | inline void | ||
556 | 124 | rasterize(const PointDataTreeOrGridT& points, | |
557 | TransferT& transfer, | ||
558 | const FilterT& filter, | ||
559 | InterrupterT* interrupter) | ||
560 | { | ||
561 | using PointTreeT = typename TreeAdapter<PointDataTreeOrGridT>::TreeType; | ||
562 | static_assert(std::is_base_of<TreeBase, PointTreeT>::value, | ||
563 | "Provided points to rasterize is not a derived TreeBase type."); | ||
564 | |||
565 | const auto& tree = TreeAdapter<PointDataTreeOrGridT>::tree(points); | ||
566 | |||
567 | auto& topology = transfer.topology(); | ||
568 | using TreeT = typename std::decay<decltype(topology)>::type; | ||
569 | 248 | tree::LeafManager<TreeT> manager(topology); | |
570 | transfer_internal::RasterizePoints<TransferT, TreeT, FilterT, InterrupterT> | ||
571 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
220 | raster(tree, transfer, filter, interrupter); |
572 |
1/2✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
|
124 | manager.foreach(raster); |
573 | } | ||
574 | |||
575 | } // namespace points | ||
576 | } // namespace OPENVDB_VERSION_NAME | ||
577 | } // namespace openvdb | ||
578 | |||
579 | #endif //OPENVEB_POINTS_TRANSFER_HAS_BEEN_INCLUDED | ||
580 |