OpenVDB  12.1.0
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>
26 #include <openvdb/math/Transform.h>
28 #include <openvdb/util/Assert.h>
29 #include <openvdb/thread/Threading.h>
30 
31 #include <type_traits>
32 #include <tuple>
33 
34 namespace openvdb {
36 namespace OPENVDB_VERSION_NAME {
37 namespace 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
47 template <typename PointDataTreeOrGridT, typename TransferT>
48 inline void
49 rasterize(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 
223 private:
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  }
240 private:
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.
248 template <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 
274 private:
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
282 template <>
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.
295 template <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 
306  VolumeTransfer(TreeTypes*... trees);
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 
347 private:
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
355 template <typename TreeT>
356 struct 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) {
370  OPENVDB_ASSERT(tree);
371  }
372 
374  : VolumeTransfer(&tree) {}
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 
407 private:
408  TreeType* const mTree;
409  ValueType* mBuffer;
410  NodeMaskT* mMask;
411 };
412 
413 namespace transfer_internal
414 {
415 template<typename T, typename F, size_t... Is>
416 void 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 
422 template<typename T, typename F, size_t... Is>
423 void 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 
431 template<typename T, template <typename> class R, typename F, size_t... Is>
432 void 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 
441 template <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.");
452  OPENVDB_ASSERT(tree);
453  }, std::make_integer_sequence<size_t, Size>());
454 
455  mBuffers.fill(nullptr);
456  mMasks.fill(nullptr);
457 }
458 
459 template <typename ...TreeTypes>
460 inline void VolumeTransfer<TreeTypes...>::initialize(const Coord& origin, const size_t, const CoordBBox&)
461 {
462  transfer_internal::foreach(mTreeArray,
463  [&](auto&& tree, const size_t i) {
464  OPENVDB_ASSERT(tree);
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 
476 template <typename ...TreeTypes>
477 template <typename FunctorT>
478 inline void VolumeTransfer<TreeTypes...>::foreach(const FunctorT& functor)
479 {
480  transfer_internal::foreach<TreeTupleT, TypeResolver>(mBuffers.data(), functor,
481  std::make_integer_sequence<size_t, Size>());
482 }
483 
484 namespace transfer_internal
485 {
486 
489 
490 template <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 
646 private:
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 
685 private:
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 
698 template <typename PointDataTreeOrGridT, typename TransferT>
699 inline void
700 rasterize(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 
706  const auto& tree = TreeAdapter<PointDataTreeOrGridT>::tree(points);
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 
715  transfer_internal::RasterizePoints<TransferT, TreeT> raster(tree, transfer, bounds);
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
729 template <typename PointDataTreeOrGridT,
730  typename TransferT,
731  typename FilterT,
732  typename InterrupterT = util::NullInterrupter>
733 OPENVDB_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).")
735 inline void
736 rasterize(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 
745  const auto& tree = TreeAdapter<PointDataTreeOrGridT>::tree(points);
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 
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
void rasterize(const PointDataTreeOrGridT &points, TransferT &transfer, const FilterT &filter, InterrupterT *interrupter=nullptr)
Perform potentially complex rasterization from a user defined transfer scheme.
Definition: PointTransfer.h:736
FilteredTransfer module, when derived from allows for schemes to apply point filtering. Note that this module handles the thread safe intialization and storage of the filter, but derived schemes must call FilteredTransfer::filter() per point id and handle the result.
Definition: PointTransfer.h:249
const NodeMaskT * mask() const
Definition: PointTransfer.h:399
The VolumeTransfer module provides methods to automatically setup and access destination buffers for ...
Definition: PointTransfer.h:296
int32_t Int32
Definition: Types.h:56
Iterator begin() const
Definition: LeafManager.h:156
const math::Transform & sourceTransform() const
Definition: PointTransfer.h:220
const NodeMaskT * mask(const size_t idx) const
Definition: PointTransfer.h:342
typename std::tuple_element< Idx, std::tuple< TreeTypes... >>::type TreeType
Definition: PointTransfer.h:301
OPENVDB_IMPORT void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types. Also initializes blosc (if enabled).
void foreach(const FunctorT &functor)
Definition: PointTransfer.h:478
typename TreeType::LeafNodeType::NodeMaskType NodeMaskT
Definition: PointTransfer.h:360
VolumeTransfer(TreeType &tree)
Definition: PointTransfer.h:373
typename TreeType< Idx >::ValueType ValueType
Definition: PointTransfer.h:302
ValueType * buffer()
Definition: PointTransfer.h:402
const ValueType< Idx > * buffer() const
Definition: PointTransfer.h:331
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:203
bool startPointLeaf(const PointDataTree::LeafNodeType &)
Definition: PointTransfer.h:287
auto transformSourceToTarget(const T &value) const
Definition: PointTransfer.h:207
void foreach(T &&t, const F &func, std::integer_sequence< size_t, Is... >)
Definition: PointTransfer.h:416
void operator()(const typename LeafManagerT::LeafRange &range) const
Definition: PointTransfer.h:639
FilteredTransfer(const FilterT &filter)
Definition: PointTransfer.h:251
VolumeTransfer(TreeType *tree)
Definition: PointTransfer.h:366
bool interrupted() const
Definition: PointTransfer.h:234
const ValueType * buffer() const
Definition: PointTransfer.h:397
typename LeafManagerT::LeafNodeType LeafNodeT
Definition: PointTransfer.h:497
Index32 Index
Definition: Types.h:54
NodeMaskT * mask()
Definition: PointTransfer.h:398
void initialize(const Coord &origin, const size_t, const CoordBBox &)
Definition: PointTransfer.h:460
ValueType * buffer()
Definition: PointTransfer.h:396
TreeT TreeType
Definition: PointTransfer.h:358
TransformTransfer(const math::Transform &st, const math::Transform &tt)
Definition: PointTransfer.h:201
auto transformTargetToSource(const T &value) const
Definition: PointTransfer.h:214
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:51
Vec3< int32_t > Vec3i
Definition: Vec3.h:662
Base class for interrupters.
Definition: NullInterrupter.h:25
typename TreeType::ValueType ValueType
Definition: PointTransfer.h:359
GridTypes::Transform< internal::ToTreeType > TreeTypes
Definition: openvdb.h:123
const NodeMaskT * mask() const
Definition: PointTransfer.h:405
const math::Transform & targetTransform() const
Definition: PointTransfer.h:221
InterruptableTransfer(util::NullInterrupter *const interrupt)
Definition: PointTransfer.h:232
void(const Coord &, const Index, const CoordBBox &) RasterizePointSignature
Definition: PointTransfer.h:499
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
VolumeTransfer(const VolumeTransfer &other)
Definition: PointTransfer.h:376
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
Coord worldToIndexCellCentered(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:111
const ValueType * buffer() const
Definition: PointTransfer.h:403
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
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
void initialize(const Coord &, const size_t, const CoordBBox &)
Definition: PointTransfer.h:258
#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
bool startPointLeaf(const PointDataTree::LeafNodeType &leaf)
Definition: PointTransfer.h:263
Definition: Exceptions.h:13
RasterizePoints(const points::PointDataTree &tree, const TransferT &transfer, const CoordBBox &pointBounds, const PointFilterT &filter=PointFilterT(), InterrupterT *interrupter=nullptr)
Definition: PointTransfer.h:510
void(const Coord &, const Index, const Index, const CoordBBox &) RasterizePointsSignature
Definition: PointTransfer.h:500
void initialize(const Coord &origin, const size_t, const CoordBBox &)
Definition: PointTransfer.h:383
LeafType LeafNodeType
Definition: LeafManager.h:93
typename TreeType< 0 >::LeafNodeType::NodeMaskType NodeMaskT
Definition: PointTransfer.h:304
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
VolumeTransfer(const VolumeTransfer &other)
Definition: PointTransfer.h:311
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
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:108
FilteredTransfer(const NullFilter &)
Definition: PointTransfer.h:285
NodeMaskT * mask(const size_t idx)
Definition: PointTransfer.h:338
NodeMaskT * mask()
Definition: PointTransfer.h:337
typename T::ValueType Type
Definition: PointTransfer.h:303
static NonConstTreeType & tree(NonConstTreeType &t)
Definition: Grid.h:1076
bool filter(const Index) const
Definition: PointTransfer.h:288
InterruptableTransfer module, when derived from allows for schemes to callback into a interrupter...
Definition: PointTransfer.h:230
ValueType< Idx > * buffer()
Definition: PointTransfer.h:325
typename _TreeType::ConstAccessor ConstAccessor
Definition: Grid.h:590
The TransformTransfer module should be used if the source transform of the input points and the targe...
Definition: PointTransfer.h:199
Definition: Transform.h:39
VolumeTransfer(TreeTypes &...trees)
Definition: PointTransfer.h:308
void operator()(LeafNodeT &leaf, const size_t idx) const
Definition: PointTransfer.h:521
TreeType< 0 > & topology()
Definition: PointTransfer.h:320
TreeType & topology()
Definition: PointTransfer.h:381
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
FilteredTransfer(const FilteredTransfer &other)
Definition: PointTransfer.h:254
bool filter(const Index id) const
Definition: PointTransfer.h:269
#define OPENVDB_HAS_INVOKABLE_MEMBER_FUNCTION(T, F,...)
Definition: Types.h:239
const NodeMaskT * mask() const
Definition: PointTransfer.h:341
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition: Platform.h:171
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
void initialize(const Coord &, const size_t, const CoordBBox &)
Definition: PointTransfer.h:286
_TreeType TreeType
Definition: Grid.h:1061
Definition: Tree.h:194
NodeMaskT * mask()
Definition: PointTransfer.h:404