OpenVDB 12.1.0
Loading...
Searching...
No Matches
PointTransfer.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-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>
28#include <openvdb/util/Assert.h>
29#include <openvdb/thread/Threading.h>
30
31#include <type_traits>
32#include <tuple>
33
34namespace openvdb {
36namespace OPENVDB_VERSION_NAME {
37namespace points {
38
39/// @brief Perform potentially complex rasterization from a user defined
40/// transfer scheme. See below comments for the transfer scheme API.
41/// @details The method works by looping over a single Tree topology, looking
42/// up point data at a position relative to that topology and passing that
43/// data to a transfer scheme TransferT.
44/// @note Each thread receives a copy of the transfer scheme object.
45/// @param points the point data grid or tree to rasterize
46/// @param transfer the transfer scheme
47template <typename PointDataTreeOrGridT, typename TransferT>
48inline void
49rasterize(const PointDataTreeOrGridT& points, TransferT& transfer);
50
51/// @par A transfer scheme must be configured to call the provided rasterize
52/// methods. See below for an example, or the various native VDB files which
53/// implement schemes e.g.:
54/// - PointRasterizeSDF.h
55/// - PointRasterizeTrilinear.h
56/// - PrincipalComponentAnalysisImpl.h
57/// @code
58/// struct Transfer
59/// {
60/// /// @return Returns the tree topology to loop over. This can be different
61/// /// from the destination tree i.e. This can act as a mask.
62/// inline auto& topology();
63///
64/// /// @brief The maximum lookup range of this transfer scheme in index
65/// /// space of the source points.
66/// /// @details The return value represent how far away from the destination
67/// /// leaf node points should be accessed.
68/// /// @param origin The leaf origin of the topology being accessed
69/// /// @param idx The leaf index of the topology being accessed
70/// inline Int32 range(const Coord& origin, size_t idx) const;
71///
72/// /// @brief The initialize function, called on each leaf which has valid
73/// /// topology to write to.
74/// /// @param origin The leaf origin of the topology being accessed
75/// /// @param idx The leaf index of the topology being accessed
76/// /// @param bounds The active voxel bounds of the leaf
77/// inline void initialize(const Coord& origin, size_t idx, const CoordBBox& bounds);
78///
79/// /// @brief Run each time a point leaf is accessed. Typically this is
80/// /// where attribute handles can be constructed
81/// /// @param leaf The PointDataLeafNode which is being accessed.
82/// /// @return Return true to continue rasterization, false to early exit
83/// /// and skip the current leaf's contribution to the destination volume.
84/// inline bool startPointLeaf(const PointDataTree::LeafNodeType& leaf);
85///
86/// ///////////////////////////////////////////////////////////////////////
87///
88/// // Transfer scheme must implement either:
89/// // - rasterizePoint(Coord, Index, CoordBBox) OR
90/// // - rasterizePoints(Coord, Index, Index, CoordBBox)
91///
92/// /// @brief The point stamp function. Each point which contributes to
93/// /// the current leaf will call this function exactly once.
94/// /// @param ijk The current voxel containing the point being rasterized.
95/// /// May be outside the destination leaf node depending on the range()
96/// /// @param id The point index being rasterized
97/// /// @param bounds The active bounds of the leaf node.
98/// void rasterizePoint(const Coord& ijk,
99/// const Index id,
100/// const CoordBBox& bounds);
101///
102/// /// @brief Same as above, except this is passed a range of points
103/// /// that all belong to the same voxel
104/// /// @param ijk The current voxel containing the point being rasterized.
105/// /// May be outside the destination leaf node depending on the range()
106/// /// @param start The start point index being rasterized
107/// /// @param end The end point index being rasterized
108/// /// @param bounds The active bounds of the leaf node.
109/// void rasterizePoints(const Coord& ijk,
110/// const Index start,
111/// const Index end,
112/// const CoordBBox& bounds);
113///
114/// ///////////////////////////////////////////////////////////////////////
115///
116/// /// @brief Run each time a point leaf is finished with.
117/// /// @param leaf The PointDataLeafNode which was being accessed.
118/// /// @return Return true to continue rasterization, false to early exit
119/// /// and stop rasterization to the destination leaf node.
120/// inline bool endPointLeaf(const PointDataTree::LeafNodeType& leaf);
121///
122/// /// @brief The finalization function for the given destination tree(s).
123/// /// @param origin The leaf origin of the topology being accessed
124/// /// @param idx The leaf index of the topology being accessed
125/// /// @return Return true to stop, false to recursively rasterize
126/// inline bool finalize(const Coord& origin, size_t idx);
127/// };
128/// @endcode
129///
130///
131/// Below is a full example using the native components.
132///
133/// @code
134/// /// @brief Sum point distances into a target float tree
135/// /// Note: Using TransformTransfer to handle different index spaces, and
136/// /// VolumeTransfer for automatic buffer setup
137/// struct MyTransfer :
138/// public TransformTransfer,
139/// public VolumeTransfer<FloatTree>
140/// {
141/// MyTransfer(FloatGrid& dest, const PointDataGrid& source)
142/// : TransformTransfer(source.transform(), dest.transform())
143/// , VolumeTransfer(dest.tree()) {}
144///
145/// MyTransfer(const MyTransfer& other)
146/// : TransformTransfer(other)
147/// , VolumeTransfer(other) {}
148///
149/// /// @brief Range in index space of the source points
150/// Vec3i range(const Coord&, size_t) const { return Vec3i(1); }
151///
152/// /// @brief Every time we start a new point leaf, init the position array.
153/// /// Always return true as we don't skip any leaf nodes.
154/// bool startPointLeaf(const PointDataTree::LeafNodeType& leaf)
155/// {
156/// // @note consider caching the indices to "P" and "mygroup" for faster lookups
157/// mHandle = std::make_unique<AttributeHandle<Vec3f>>(leaf.constAttributeArray("P"));
158/// mFilter = std::make_unique<GroupFilter>("mygroup", leaf.attributeSet());
159/// return true;
160/// }
161///
162/// /// @brief For each point, compute its relative index space position in
163/// /// the destination tree and sum the length of its distance
164/// void rasterizePoint(const Coord& ijk, const Index id, const CoordBBox& bounds)
165/// {
166/// // skip points not in "mygroup"
167/// if (!mFilter->valid(&id)) return;
168/// Vec3d P = ijk.asVec3d() + Vec3d(this->mHandle->get(id));
169/// P = this->transformSourceToTarget(P); // TransformTransfer::transformSourceToTarget
170/// // for each active voxel, accumulate distance
171/// const auto* mask = this->mask(); // VolumeTransfer::mask
172/// for (auto& coord : bounds) {
173/// const Index voxel = FloatTree::LeafNodeType::coordToOffset(coord);
174/// if (!mask->isOn(voxel)) continue;
175/// Vec3d dist = coord.asVec3d() - P;
176/// this->buffer()[voxel] += dist.length(); // VolumeTransfer::buffer
177/// }
178/// }
179///
180/// /// @brief Return true for endPointLeaf() to continue, false for finalize() so
181/// /// we don't recurse.
182/// bool endPointLeaf(const PointDataTree::LeafNodeType&) { return true; }
183/// bool finalize(const Coord&, size_t) { return false; }
184///
185/// private:
186/// std::unique_ptr<AttributeHandle<Vec3f>> mHandle {nullptr};
187/// std::unique_ptr<GroupFilter> mFilter {nullptr};
188/// };
189/// @endcode
190
191
192///////////////////////////////////////////////////
193///////////////////////////////////////////////////
194
195/// @brief The TransformTransfer module should be used if the source transform
196/// of the input points and the target transforms of the destination volumes
197/// differ. The default rasterizer will skip index to world (and vice versa)
198/// transformations unless a transfer scheme derives from a TransformTransfer.
200{
202 const math::Transform& tt)
203 : mSourceTransform(st)
204 , mTargetTransform(tt) {}
205
206 template <typename T>
207 inline auto transformSourceToTarget(const T& value) const
208 {
209 const auto result = mSourceTransform.indexToWorld(value);
210 return mTargetTransform.worldToIndex(result);
211 }
212
213 template <typename T>
214 inline auto transformTargetToSource(const T& value) const
215 {
216 const auto result = mTargetTransform.indexToWorld(value);
217 return mSourceTransform.worldToIndex(result);
218 }
219
220 const math::Transform& sourceTransform() const { return mSourceTransform; }
221 const math::Transform& targetTransform() const { return mTargetTransform; }
222
223private:
224 const math::Transform& mSourceTransform;
225 const math::Transform& mTargetTransform;
226};
227
228/// @brief InterruptableTransfer module, when derived from allows for schemes
229/// to callback into a interrupter, derived from util::NullInterrupter.
231{
233 : mInterrupt(interrupt) {}
234 inline bool interrupted() const
235 {
236 if (!util::wasInterrupted(mInterrupt)) return false;
237 thread::cancelGroupExecution();
238 return true;
239 }
240private:
241 util::NullInterrupter* const mInterrupt;
242};
243
244/// @brief FilteredTransfer module, when derived from allows for schemes
245/// to apply point filtering. Note that this module handles the thread safe
246/// intialization and storage of the filter, but derived schemes must call
247/// FilteredTransfer::filter() per point id and handle the result.
248template <typename FilterT>
250{
251 FilteredTransfer(const FilterT& filter)
252 : mFilter(filter)
253 , mLocalFilter(nullptr) {}
255 : mFilter(other.mFilter)
256 , mLocalFilter(nullptr) {}
257
258 inline void initialize(const Coord&, const size_t, const CoordBBox&)
259 {
260 mLocalFilter = std::make_unique<FilterT>(mFilter);
261 }
262
264 {
265 mLocalFilter->reset(leaf);
266 return true;
267 }
268
269 inline bool filter(const Index id) const
270 {
271 return mLocalFilter->valid(&id);
272 }
273
274private:
275 const FilterT& mFilter;
276 /// @note Not all of the filters are assignable (e.g. GroupFilter).
277 /// should really fix this and make this stack allocated.
278 std::unique_ptr<FilterT> mLocalFilter;
279};
280
281/// @brief Specialization of FilteredTransfer for NullFilters which do nothing
282template <>
284{
286 inline void initialize(const Coord&, const size_t, const CoordBBox&) {}
287 inline bool startPointLeaf(const PointDataTree::LeafNodeType&) { return true; }
288 inline bool filter(const Index) const { return true; }
289};
290
291/// @brief The VolumeTransfer module provides methods to automatically setup
292/// and access destination buffers for multiple target volumes of arbitrary
293/// types. Deriving from a VolumeTransfer ensures that the available
294/// buffers correlate to the order of the provided tree arguments.
295template <typename ...TreeTypes>
297{
298 static const size_t Size = sizeof...(TreeTypes);
299 using TreeTupleT = std::tuple<TreeTypes*...>;
300
301 template <size_t Idx> using TreeType = typename std::tuple_element<Idx, std::tuple<TreeTypes...>>::type;
302 template <size_t Idx> using ValueType = typename TreeType<Idx>::ValueType;
303 template <typename T> struct TypeResolver { using Type = typename T::ValueType; };
305
307
309 : VolumeTransfer(&trees...) {}
310
312 : mTreeArray(other.mTreeArray)
313 , mBuffers()
314 , mMasks()
315 {
316 mBuffers.fill(nullptr);
317 mMasks.fill(nullptr);
318 }
319
320 inline TreeType<0>& topology() { return *(std::get<0>(mTreeArray)); }
321
322 inline void initialize(const Coord& origin, const size_t, const CoordBBox&);
323
324 template <size_t Idx>
326 {
327 return static_cast<ValueType<Idx>*>(mBuffers[Idx]);
328 }
329
330 template <size_t Idx>
331 inline const ValueType<Idx>* buffer() const
332 {
333 return static_cast<ValueType<Idx>*>(mBuffers[Idx]);
334 }
335
336 template <size_t Idx>
337 inline NodeMaskT* mask() { return mMasks[Idx]; }
338 inline NodeMaskT* mask(const size_t idx) { return mMasks[idx]; }
339
340 template <size_t Idx>
341 inline const NodeMaskT* mask() const { return mMasks[Idx]; }
342 inline const NodeMaskT* mask(const size_t idx) const { return mMasks[idx]; }
343
344 template <typename FunctorT>
345 inline void foreach(const FunctorT& functor);
346
347private:
348 const TreeTupleT mTreeArray;
349 std::array<void*, Size> mBuffers;
350 std::array<NodeMaskT*, Size> mMasks;
351};
352
353/// @brief VolumeTransfer specialization for a single target volume
354/// @todo this specialization should avoid the probe
355template <typename TreeT>
356struct VolumeTransfer<TreeT>
357{
358 using TreeType = TreeT;
359 using ValueType = typename TreeType::ValueType;
360 using NodeMaskT = typename TreeType::LeafNodeType::NodeMaskType;
361
362 static_assert(std::is_base_of<TreeBase, TreeType>::value,
363 "One or more template arguments to VolumeTransfer "
364 "are not a valid openvdb::Tree type.");
365
367 : mTree(tree)
368 , mBuffer(nullptr)
369 , mMask(nullptr) {
371 }
372
375
377 : mTree(other.mTree)
378 , mBuffer(nullptr)
379 , mMask(nullptr) {}
380
381 inline TreeType& topology() { return *mTree; }
382
383 inline void initialize(const Coord& origin, const size_t, const CoordBBox&)
384 {
385 OPENVDB_ASSERT(mTree);
386 if (auto leaf = mTree->probeLeaf(origin)) {
387 mBuffer = leaf->buffer().data();
388 mMask = &(leaf->getValueMask());
389 }
390 else {
391 mBuffer = nullptr;
392 mMask = nullptr;
393 }
394 }
395
396 inline ValueType* buffer() { return mBuffer; }
397 inline const ValueType* buffer() const { return mBuffer; }
398 inline NodeMaskT* mask() { return mMask; }
399 inline const NodeMaskT* mask() const { return mMask; }
400
401 // compatibility with multi tree containers
402 template <size_t> inline ValueType* buffer() { return this->buffer(); }
403 template <size_t> inline const ValueType* buffer() const { return this->buffer(); }
404 template <size_t> inline NodeMaskT* mask() { return this->mask(); }
405 template <size_t> inline const NodeMaskT* mask() const { return this->mask(); }
406
407private:
408 TreeType* const mTree;
409 ValueType* mBuffer;
410 NodeMaskT* mMask;
411};
412
414{
415template<typename T, typename F, size_t... Is>
416void foreach(T&& t, const F& func, std::integer_sequence<size_t, Is...>)
417{
418 auto init = { (func(std::get<Is>(t), Is), 0)... };
419 (void)init;
420}
421
422template<typename T, typename F, size_t... Is>
423void foreach(void** buffers, const F& func, std::integer_sequence<size_t, Is...>)
424{
425 int init[sizeof...(Is)] = {
426 (func(static_cast<typename std::tuple_element<Is, T>::type*>
427 (*(buffers + Is)), Is), 0)...
428 };
429}
430
431template<typename T, template <typename> class R, typename F, size_t... Is>
432void foreach(void** buffers, const F& func, std::integer_sequence<size_t, Is...>)
433{
434 int init[sizeof...(Is)] = {
435 (func(static_cast<typename R<typename std::tuple_element<Is, T>::type>::Type*>
436 (*(buffers + Is)), Is), 0)...
437 };
438}
439}
440
441template <typename ...TreeTypes>
443 : mTreeArray({ trees... })
444 , mBuffers()
445 , mMasks()
446{
447 transfer_internal::foreach(mTreeArray, [](auto&& tree, const size_t) {
448 using TreeT = typename std::remove_pointer<typename std::decay<decltype(tree)>::type>::type;
449 static_assert(std::is_base_of<TreeBase, TreeT>::value,
450 "One or more template arguments to VolumeTransfer "
451 "are not a valid openvdb::Tree type.");
453 }, std::make_integer_sequence<size_t, Size>());
454
455 mBuffers.fill(nullptr);
456 mMasks.fill(nullptr);
457}
458
459template <typename ...TreeTypes>
460inline void VolumeTransfer<TreeTypes...>::initialize(const Coord& origin, const size_t, const CoordBBox&)
461{
463 [&](auto&& tree, const size_t i) {
465 if (auto leaf = tree->probeLeaf(origin)) {
466 mBuffers[i] = static_cast<void*>(leaf->buffer().data());
467 mMasks[i] = &(leaf->getValueMask());
468 }
469 else {
470 mBuffers[i] = nullptr;
471 mMasks[i] = nullptr;
472 }
473 }, std::make_integer_sequence<size_t, Size>());
474}
475
476template <typename ...TreeTypes>
477template <typename FunctorT>
478inline void VolumeTransfer<TreeTypes...>::foreach(const FunctorT& functor)
479{
481 std::make_integer_sequence<size_t, Size>());
482}
483
484namespace transfer_internal
485{
486
489
490template <typename TransferT,
491 typename TopologyT,
492 typename PointFilterT = points::NullFilter,
493 typename InterrupterT = util::NullInterrupter>
495{
498
499 using RasterizePointSignature = void(const Coord&, const Index, const CoordBBox&);
500 using RasterizePointsSignature = void(const Coord&, const Index, const Index, const CoordBBox&);
501
502 static const Index DIM = TopologyT::LeafNodeType::DIM;
503 static const Int32 DIM32 = static_cast<Int32>(DIM);
504 static const Index LOG2DIM = TopologyT::LeafNodeType::LOG2DIM;
505 static constexpr bool UseRasterizePoints =
506 OPENVDB_HAS_INVOKABLE_MEMBER_FUNCTION(TransferT, rasterizePoints, Coord, Index, Index, CoordBBox);
507 static constexpr bool UseRasterizePoint =
508 OPENVDB_HAS_INVOKABLE_MEMBER_FUNCTION(TransferT, rasterizePoint, Coord, Index, CoordBBox);
509
511 const TransferT& transfer,
512 const CoordBBox& pointBounds,
513 const PointFilterT& filter = PointFilterT(),
514 InterrupterT* interrupter = nullptr)
515 : mPointAccessor(tree)
516 , mTransfer(transfer)
517 , mPointBounds(pointBounds)
518 , mFilter(filter)
519 , mInterrupter(interrupter) {}
520
521 void operator()(LeafNodeT& leaf, const size_t idx) const
522 {
523 if (this->interrupted()) return;
524
525 const Coord& origin = leaf.origin();
526 auto& mask = leaf.getValueMask();
527
528 CoordBBox bounds;
529
530 bool state;
531 if (mask.isConstant(state)) {
532 if (!state) return; // all inactive
533 else bounds = leaf.getNodeBoundingBox();
534 }
535 else {
536 // Use evalActiveBoundingBox over getNodeBoundingBox()
537 // to get a better approximation
538 leaf.evalActiveBoundingBox(bounds);
539 OPENVDB_ASSERT(!bounds.empty());
540 }
541
542 mTransfer.initialize(origin, idx, bounds);
543
544 CoordBBox search = bounds;
545 const Vec3i range(mTransfer.range(origin, idx));
546 search.min() -= Coord(range);
547 search.max() += Coord(range);
548 this->transform<>(search);
549 search.intersect(mPointBounds);
550
551 // start the iteration from a leaf origin
552 const Coord min = (search.min() & ~(DIM-1));
553 const Coord& max = search.max();
554
555 /// @todo remove this - with the introduction of rasterizePoints we no
556 /// longer accept a filter at this level (it's expected to be handled)
557 /// in the transfer scheme
558 PointFilterT localFilter(mFilter);
559
560 // loop over overlapping leaf nodes
561 Coord leafOrigin;
562 for (leafOrigin[0] = min[0]; leafOrigin[0] <= max[0]; leafOrigin[0]+=DIM32) {
563 for (leafOrigin[1] = min[1]; leafOrigin[1] <= max[1]; leafOrigin[1]+=DIM32) {
564 for (leafOrigin[2] = min[2]; leafOrigin[2] <= max[2]; leafOrigin[2]+=DIM32) {
565
566 // if no overlap, continue
567 CoordBBox pbox = CoordBBox::createCube(leafOrigin, DIM32);
568 pbox.intersect(search);
569 if (pbox.empty()) continue;
570
571 // if no points, continue
572 const auto* pointLeaf = mPointAccessor.probeConstLeaf(leafOrigin);
573 if (!pointLeaf) continue;
574 if (!mTransfer.startPointLeaf(*pointLeaf)) continue;
575 localFilter.reset(*pointLeaf);
576
577 if (this->interrupted()) return;
578
579 // It's actually faster to go through the ValueIter API than
580 // the leaf API as the value iterators cache the value buffer
581 // ptrs (the leaf buffer API has to check the ptr on every
582 // access).
583 // @todo Once we've improved the leaf buffer impl this
584 // should be removed
585 const auto valiter = pointLeaf->cbeginValueAll();
586
587 // loop over point voxels which contribute to this leaf
588 const Coord& pmin(pbox.min());
589 const Coord& pmax(pbox.max());
590 for (Coord ijk = pmin; ijk.x() <= pmax.x(); ++ijk.x()) {
591 const Index i = ((ijk.x() & (DIM-1u)) << 2*LOG2DIM); // unsigned bit shift mult
592 for (ijk.y() = pmin.y(); ijk.y() <= pmax.y(); ++ijk.y()) {
593 const Index ij = i + ((ijk.y() & (DIM-1u)) << LOG2DIM);
594 for (ijk.z() = pmin.z(); ijk.z() <= pmax.z(); ++ijk.z()) {
595 // voxel should be in this points leaf
596 OPENVDB_ASSERT((ijk & ~(DIM-1u)) == leafOrigin);
597 const Index index = ij + /*k*/(ijk.z() & (DIM-1u));
598 const Index end = valiter.getItem(index);
599 Index id = (index == 0) ? 0 : Index(valiter.getItem(index - 1));
600 if (this->interrupted()) return;
601
602 if constexpr (UseRasterizePoints)
603 {
604 // No filter support here, must be on the transfer scheme
605 mTransfer.rasterizePoints(ijk, id, end, bounds);
606 }
607 else if constexpr (UseRasterizePoint)
608 {
609 for (; id < end; ++id) {
610 if (!localFilter.valid(&id)) continue;
611 mTransfer.rasterizePoint(ijk, id, bounds);
612 } //point idx
613 }
614 else {
615 static_assert(UseRasterizePoints || UseRasterizePoint,
616 "Invalid transfer scheme in openvdb::tools::rasterize. Must correctly Implement rasterizePoints or rasterizePoint.");
617 }
618 }
619 }
620 } // outer point voxel
621
622 if (!mTransfer.endPointLeaf(*pointLeaf)) {
623 // rescurse if necessary
624 if (!mTransfer.finalize(origin, idx)) {
625 this->operator()(leaf, idx);
626 }
627 return;
628 }
629 }
630 }
631 } // outer leaf node
632
633 // rescurse if necessary
634 if (!mTransfer.finalize(origin, idx)) {
635 this->operator()(leaf, idx);
636 }
637 }
638
639 void operator()(const typename LeafManagerT::LeafRange& range) const
640 {
641 for (auto leaf = range.begin(); leaf; ++leaf) {
642 (*this)(*leaf, leaf.pos());
643 }
644 }
645
646private:
647
648 template <typename EnableT = TransferT>
649 typename std::enable_if<std::is_base_of<TransformTransfer, EnableT>::value>::type
650 transform(CoordBBox& bounds) const
651 {
652 const TransformTransfer* transform =
653 static_cast<TransformTransfer*>(&mTransfer);
654 const BBoxd bbox(bounds.min().asVec3d(), bounds.max().asVec3d());
655 bounds = transform->sourceTransform().worldToIndexCellCentered(
656 transform->targetTransform().indexToWorld(bbox));
657 }
658
659 template <typename EnableT = TransferT>
660 typename std::enable_if<!std::is_base_of<TransformTransfer, EnableT>::value>::type
661 transform(CoordBBox&) const {}
662
663 template <typename EnableT = TransferT>
664 typename std::enable_if<std::is_base_of<InterruptableTransfer, EnableT>::value, bool>::type
665 interrupted() const
666 {
667 return mTransfer.interrupted();
668 }
669
670 template <typename EnableT = TransferT>
671 constexpr typename std::enable_if<!std::is_base_of<InterruptableTransfer, EnableT>::value, bool>::type
672 interrupted() const
673 {
674 // @todo This method should just return false once the old rasterize signature is deprecated
675 if constexpr (std::is_same<InterrupterT, util::NullInterrupter>::value) return false;
676 else {
677 if (util::wasInterrupted(mInterrupter)) {
678 thread::cancelGroupExecution();
679 return true;
680 }
681 return false;
682 }
683 }
684
685private:
686 const PointDataGrid::ConstAccessor mPointAccessor;
687 mutable TransferT mTransfer;
688 const CoordBBox& mPointBounds;
689 const PointFilterT& mFilter; // @todo remove
690 InterrupterT* mInterrupter; // @todo remove
691};
692
693} // namespace transfer_internal
694
695///////////////////////////////////////////////////
696///////////////////////////////////////////////////
697
698template <typename PointDataTreeOrGridT, typename TransferT>
699inline void
700rasterize(const PointDataTreeOrGridT& points, TransferT& transfer)
701{
702 using PointTreeT = typename TreeAdapter<PointDataTreeOrGridT>::TreeType;
703 static_assert(std::is_base_of<TreeBase, PointTreeT>::value,
704 "Provided points to rasterize is not a derived TreeBase type.");
705
707 auto& topology = transfer.topology();
708 using TreeT = typename std::decay<decltype(topology)>::type;
709
710 // Compute max search bounds
711 CoordBBox bounds;
712 tree.evalLeafBoundingBox(bounds);
713
714 tree::LeafManager<TreeT> manager(topology);
716 manager.foreach(raster);
717}
718
719/// @brief Perform potentially complex rasterization from a user defined
720/// transfer scheme.
721/// @details The method works by looping over a single Tree topology, looking
722/// up point data at a position relative to that topology and passing that
723/// data to a transfer scheme TransferT.
724/// @note Each thread receives a copy of the transfer scheme object.
725/// @param points the point data grid to rasterize
726/// @param transfer the transfer scheme
727/// @param filter optional point filter
728/// @param interrupter optional interrupter
729template <typename PointDataTreeOrGridT,
730 typename TransferT,
731 typename FilterT,
732 typename InterrupterT = util::NullInterrupter>
733OPENVDB_DEPRECATED_MESSAGE("openvdb::tools::rasterize no longer takes a filter or "
734"interrupter. Implement this on your transfer scheme (see PointTransfer.h for an example).")
735inline void
736rasterize(const PointDataTreeOrGridT& points,
737 TransferT& transfer,
738 const FilterT& filter,
739 InterrupterT* interrupter = nullptr)
740{
741 using PointTreeT = typename TreeAdapter<PointDataTreeOrGridT>::TreeType;
742 static_assert(std::is_base_of<TreeBase, PointTreeT>::value,
743 "Provided points to rasterize is not a derived TreeBase type.");
744
746
747 auto& topology = transfer.topology();
748 using TreeT = typename std::decay<decltype(topology)>::type;
749
750 // Compute max search bounds
751 CoordBBox bounds;
752 tree.evalLeafBoundingBox(bounds);
753
754 tree::LeafManager<TreeT> manager(topology);
756 raster(tree, transfer, bounds, filter, interrupter);
757 manager.foreach(raster);
758}
759
760} // namespace points
761} // namespace OPENVDB_VERSION_NAME
762} // namespace openvdb
763
764#endif //OPENVEB_POINTS_TRANSFER_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition Platform.h:171
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition Coord.h:316
typename PointDataTree::ConstAccessor ConstAccessor
Definition Grid.h:590
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition Coord.h:359
const Coord & min() const
Definition Coord.h:324
const Coord & max() const
Definition Coord.h:325
void intersect(const CoordBBox &bbox)
Intersect this bounding box with the given bounding box.
Definition Coord.h:447
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Vec3d asVec3d() const
Definition Coord.h:144
Int32 y() const
Definition Coord.h:132
Int32 x() const
Definition Coord.h:131
Int32 z() const
Definition Coord.h:133
Definition Transform.h:40
Coord worldToIndexCellCentered(const Vec3d &xyz) const
Definition Transform.h:111
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition Transform.h:108
A no-op filter that can be used when iterating over all indices.
Definition IndexIterator.h:52
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
void foreach(const LeafOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to each leaf node in the LeafManager.
Definition LeafManager.h:484
LeafType LeafNodeType
Definition LeafManager.h:93
Vec3< int32_t > Vec3i
Definition Vec3.h:662
Definition IndexIterator.h:35
Definition PointTransfer.h:414
void foreach(T &&t, const F &func, std::integer_sequence< size_t, Is... >)
Definition PointTransfer.h:416
Definition AttributeArray.h:42
tree::Tree< tree::RootNode< tree::InternalNode< tree::InternalNode< PointDataLeafNode< PointDataIndex32, 3 >, 4 >, 5 > > > PointDataTree
Point index tree configured to match the default VDB configurations.
Definition PointDataGrid.h:190
void rasterize(const PointDataTreeOrGridT &points, TransferT &transfer)
Perform potentially complex rasterization from a user defined transfer scheme. See below comments for...
Definition PointTransfer.h:700
Definition PointDataGrid.h:170
bool wasInterrupted(T *i, int percent=-1)
Definition NullInterrupter.h:49
Index32 Index
Definition Types.h:54
GridTypes::Transform< internal::ToTreeType > TreeTypes
Definition openvdb.h:123
math::BBox< Vec3d > BBoxd
Definition Types.h:84
int32_t Int32
Definition Types.h:56
Definition Exceptions.h:13
#define OPENVDB_HAS_INVOKABLE_MEMBER_FUNCTION(T, F,...)
Definition Types.h:239
#define OPENVDB_INIT_INVOKABLE_MEMBER_FUNCTION(F)
Macros to help determine whether or not a class has a particular member function.
Definition Types.h:225
static NonConstTreeType & tree(NonConstTreeType &t)
Definition Grid.h:1076
_TreeType TreeType
Definition Grid.h:1061
bool filter(const Index) const
Definition PointTransfer.h:288
FilteredTransfer(const NullFilter &)
Definition PointTransfer.h:285
void initialize(const Coord &, const size_t, const CoordBBox &)
Definition PointTransfer.h:286
bool startPointLeaf(const PointDataTree::LeafNodeType &)
Definition PointTransfer.h:287
bool filter(const Index id) const
Definition PointTransfer.h:269
bool startPointLeaf(const PointDataTree::LeafNodeType &leaf)
Definition PointTransfer.h:263
FilteredTransfer(const FilterT &filter)
Definition PointTransfer.h:251
void initialize(const Coord &, const size_t, const CoordBBox &)
Definition PointTransfer.h:258
FilteredTransfer(const FilteredTransfer &other)
Definition PointTransfer.h:254
bool interrupted() const
Definition PointTransfer.h:234
InterruptableTransfer(util::NullInterrupter *const interrupt)
Definition PointTransfer.h:232
The TransformTransfer module should be used if the source transform of the input points and the targe...
Definition PointTransfer.h:200
auto transformTargetToSource(const T &value) const
Definition PointTransfer.h:214
const math::Transform & sourceTransform() const
Definition PointTransfer.h:220
const math::Transform & targetTransform() const
Definition PointTransfer.h:221
auto transformSourceToTarget(const T &value) const
Definition PointTransfer.h:207
TransformTransfer(const math::Transform &st, const math::Transform &tt)
Definition PointTransfer.h:201
typename T::ValueType Type
Definition PointTransfer.h:303
const NodeMaskT * mask() const
Definition PointTransfer.h:405
typename TreeType::ValueType ValueType
Definition PointTransfer.h:359
void initialize(const Coord &origin, const size_t, const CoordBBox &)
Definition PointTransfer.h:383
const ValueType * buffer() const
Definition PointTransfer.h:403
const NodeMaskT * mask() const
Definition PointTransfer.h:399
ValueType * buffer()
Definition PointTransfer.h:402
VolumeTransfer(TreeType &tree)
Definition PointTransfer.h:373
NodeMaskT * mask()
Definition PointTransfer.h:398
VolumeTransfer(TreeType *tree)
Definition PointTransfer.h:366
VolumeTransfer(const VolumeTransfer &other)
Definition PointTransfer.h:376
const ValueType * buffer() const
Definition PointTransfer.h:397
NodeMaskT * mask()
Definition PointTransfer.h:404
typename TreeType::LeafNodeType::NodeMaskType NodeMaskT
Definition PointTransfer.h:360
ValueType * buffer()
Definition PointTransfer.h:396
TreeType & topology()
Definition PointTransfer.h:381
TreeT TreeType
Definition PointTransfer.h:358
const NodeMaskT * mask() const
Definition PointTransfer.h:341
VolumeTransfer(TreeTypes *... trees)
Definition PointTransfer.h:442
void initialize(const Coord &origin, const size_t, const CoordBBox &)
Definition PointTransfer.h:460
const ValueType< Idx > * buffer() const
Definition PointTransfer.h:331
ValueType< Idx > * buffer()
Definition PointTransfer.h:325
typename std::tuple_element< Idx, std::tuple< TreeTypes... > >::type TreeType
Definition PointTransfer.h:301
TreeType< 0 > & topology()
Definition PointTransfer.h:320
typename TreeType< 0 >::LeafNodeType::NodeMaskType NodeMaskT
Definition PointTransfer.h:304
VolumeTransfer(const VolumeTransfer &other)
Definition PointTransfer.h:311
std::tuple< TreeTypes *... > TreeTupleT
Definition PointTransfer.h:299
NodeMaskT * mask()
Definition PointTransfer.h:337
void foreach(const FunctorT &functor)
Definition PointTransfer.h:478
NodeMaskT * mask(const size_t idx)
Definition PointTransfer.h:338
const NodeMaskT * mask(const size_t idx) const
Definition PointTransfer.h:342
static const size_t Size
Definition PointTransfer.h:298
VolumeTransfer(TreeTypes &... trees)
Definition PointTransfer.h:308
typename TreeType< Idx >::ValueType ValueType
Definition PointTransfer.h:302
void(const Coord &, const Index, const Index, const CoordBBox &) RasterizePointsSignature
Definition PointTransfer.h:500
static constexpr bool UseRasterizePoint
Definition PointTransfer.h:507
void(const Coord &, const Index, const CoordBBox &) RasterizePointSignature
Definition PointTransfer.h:499
static const Index DIM
Definition PointTransfer.h:502
tree::LeafManager< TopologyT > LeafManagerT
Definition PointTransfer.h:496
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition PointTransfer.h:639
static const Int32 DIM32
Definition PointTransfer.h:503
typename LeafManagerT::LeafNodeType LeafNodeT
Definition PointTransfer.h:497
static constexpr bool UseRasterizePoints
Definition PointTransfer.h:505
static const Index LOG2DIM
Definition PointTransfer.h:504
void operator()(LeafNodeT &leaf, const size_t idx) const
Definition PointTransfer.h:521
RasterizePoints(const points::PointDataTree &tree, const TransferT &transfer, const CoordBBox &pointBounds, const PointFilterT &filter=PointFilterT(), InterrupterT *interrupter=nullptr)
Definition PointTransfer.h:510
Base class for interrupters.
Definition NullInterrupter.h:26
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218