HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointMask.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file points/PointMask.h
5 ///
6 /// @author Dan Bailey
7 ///
8 /// @brief Methods for extracting masks from VDB Point grids.
9 
10 #ifndef OPENVDB_POINTS_POINT_MASK_HAS_BEEN_INCLUDED
11 #define OPENVDB_POINTS_POINT_MASK_HAS_BEEN_INCLUDED
12 
13 #include <openvdb/openvdb.h>
14 #include <openvdb/tools/ValueTransformer.h> // valxform::SumOp
15 
16 #include "PointDataGrid.h"
17 #include "IndexFilter.h"
18 
19 #include <tbb/combinable.h>
20 
21 #include <type_traits>
22 #include <vector>
23 
24 
25 namespace openvdb {
27 namespace OPENVDB_VERSION_NAME {
28 namespace points {
29 
30 
31 /// @brief Extract a Mask Grid from a Point Data Grid
32 /// @param grid the PointDataGrid to extract the mask from.
33 /// @param filter an optional index filter
34 /// @param threaded enable or disable threading (threading is enabled by default)
35 /// @note this method is only available for Bool Grids and Mask Grids
36 template <typename PointDataGridT,
37  typename MaskT = typename PointDataGridT::template ValueConverter<bool>::Type,
38  typename FilterT = NullFilter>
40  typename MaskT::Ptr>::type
41 convertPointsToMask(const PointDataGridT& grid,
42  const FilterT& filter = NullFilter(),
43  bool threaded = true);
44 
45 
46 /// @brief Extract a Mask Grid from a Point Data Grid using a new transform
47 /// @param grid the PointDataGrid to extract the mask from.
48 /// @param transform target transform for the mask.
49 /// @param filter an optional index filter
50 /// @param threaded enable or disable threading (threading is enabled by default)
51 /// @note this method is only available for Bool Grids and Mask Grids
52 template <typename PointDataGridT,
53  typename MaskT = typename PointDataGridT::template ValueConverter<bool>::Type,
54  typename FilterT = NullFilter>
56  typename MaskT::Ptr>::type
57 convertPointsToMask(const PointDataGridT& grid,
58  const openvdb::math::Transform& transform,
59  const FilterT& filter = NullFilter(),
60  bool threaded = true);
61 
62 
63 /// @brief No-op deformer (adheres to the deformer interface documented in PointMove.h)
65 {
66  template <typename LeafT>
67  void reset(LeafT&, size_t /*idx*/ = 0) { }
68 
69  template <typename IterT>
70  void apply(Vec3d&, IterT&) const { }
71 };
72 
73 /// @brief Deformer Traits for optionally configuring deformers to be applied
74 /// in index-space. The default is world-space.
75 template <typename DeformerT>
77 {
78  static const bool IndexSpace = false;
79 };
80 
81 
82 ////////////////////////////////////////
83 
84 
85 namespace point_mask_internal {
86 
87 template <typename LeafT>
88 void voxelSum(LeafT& leaf, const Index offset, const typename LeafT::ValueType& value)
89 {
90  leaf.modifyValue(offset, tools::valxform::SumOp<typename LeafT::ValueType>(value));
91 }
92 
93 // overload PointDataLeaf access to use setOffsetOn(), as modifyValue()
94 // is intentionally disabled to avoid accidental usage
95 
96 template <typename T, Index Log2Dim>
99 {
100  leaf.setOffsetOn(offset, leaf.getValue(offset) + value);
101 }
102 
103 
104 /// @brief Combines multiple grids into one by stealing leaf nodes and summing voxel values
105 /// This class is designed to work with thread local storage containers such as tbb::combinable
106 template<typename GridT>
108 {
109  using CombinableT = typename tbb::combinable<GridT>;
110 
111  using TreeT = typename GridT::TreeType;
112  using LeafT = typename TreeT::LeafNodeType;
113  using ValueType = typename TreeT::ValueType;
115 
116  GridCombinerOp(GridT& grid)
117  : mTree(grid.tree()) {}
118 
119  void operator()(const GridT& grid)
120  {
121  for (auto leaf = grid.tree().beginLeaf(); leaf; ++leaf) {
122  auto* newLeaf = mTree.probeLeaf(leaf->origin());
123  if (!newLeaf) {
124  // if the leaf doesn't yet exist in the new tree, steal it
125  auto& tree = const_cast<GridT&>(grid).tree();
126  mTree.addLeaf(tree.template stealNode<LeafT>(leaf->origin(),
127  zeroVal<ValueType>(), false));
128  }
129  else {
130  // otherwise increment existing values
131  for (auto iter = leaf->cbeginValueOn(); iter; ++iter) {
132  voxelSum(*newLeaf, iter.offset(), ValueType(*iter));
133  }
134  }
135  }
136  }
137 
138 private:
139  TreeT& mTree;
140 }; // struct GridCombinerOp
141 
142 
143 /// @brief Compute scalar grid from PointDataGrid while evaluating the point filter
144 template <typename GridT, typename PointDataGridT, typename FilterT>
146 {
147  using LeafT = typename GridT::TreeType::LeafNodeType;
148  using ValueT = typename LeafT::ValueType;
149 
150  PointsToScalarOp( const PointDataGridT& grid,
151  const FilterT& filter)
152  : mPointDataAccessor(grid.getConstAccessor())
153  , mFilter(filter) { }
154 
155  void operator()(LeafT& leaf, size_t /*idx*/) const {
156 
157  const auto* const pointLeaf =
158  mPointDataAccessor.probeConstLeaf(leaf.origin());
159 
160  // assumes matching topology
161  assert(pointLeaf);
162 
163  for (auto value = leaf.beginValueOn(); value; ++value) {
165  pointLeaf->beginIndexVoxel(value.getCoord(), mFilter));
166  if (count > Index64(0)) {
167  value.setValue(ValueT(count));
168  } else {
169  // disable any empty voxels
170  value.setValueOn(false);
171  }
172  }
173  }
174 
175 private:
176  const typename PointDataGridT::ConstAccessor mPointDataAccessor;
177  const FilterT& mFilter;
178 }; // struct PointsToScalarOp
179 
180 
181 /// @brief Compute scalar grid from PointDataGrid using a different transform
182 /// and while evaluating the point filter
183 template <typename GridT, typename PointDataGridT, typename FilterT, typename DeformerT>
185 {
186  using PointDataLeafT = typename PointDataGridT::TreeType::LeafNodeType;
187  using ValueT = typename GridT::TreeType::ValueType;
190 
192  const math::Transform& sourceTransform,
193  const FilterT& filter,
194  const DeformerT& deformer,
195  CombinableT& combinable)
196  : mTargetTransform(targetTransform)
197  , mSourceTransform(sourceTransform)
198  , mFilter(filter)
199  , mDeformer(deformer)
200  , mCombinable(combinable) { }
201 
202  void operator()(const PointDataLeafT& leaf, size_t idx) const
203  {
204  DeformerT deformer(mDeformer);
205 
206  auto& grid = mCombinable.local();
207  auto& countTree = grid.tree();
209 
210  deformer.reset(leaf, idx);
211 
212  auto handle = HandleT::create(leaf.constAttributeArray("P"));
213 
214  for (auto iter = leaf.beginIndexOn(mFilter); iter; iter++) {
215 
216  // extract index-space position
217 
218  Vec3d position = handle->get(*iter) + iter.getCoord().asVec3d();
219 
220  // if deformer is designed to be used in index-space, perform deformation prior
221  // to transforming position to world-space, otherwise perform deformation afterwards
222 
224  deformer.template apply<decltype(iter)>(position, iter);
225  position = mSourceTransform.indexToWorld(position);
226  }
227  else {
228  position = mSourceTransform.indexToWorld(position);
229  deformer.template apply<decltype(iter)>(position, iter);
230  }
231 
232  // determine coord of target grid
233 
234  const Coord ijk = mTargetTransform.worldToIndexCellCentered(position);
235 
236  // increment count in target voxel
237 
238  auto* newLeaf = accessor.touchLeaf(ijk);
239  assert(newLeaf);
240  voxelSum(*newLeaf, newLeaf->coordToOffset(ijk), ValueT(1));
241  }
242  }
243 
244 private:
245  const openvdb::math::Transform& mTargetTransform;
246  const openvdb::math::Transform& mSourceTransform;
247  const FilterT& mFilter;
248  const DeformerT& mDeformer;
249  CombinableT& mCombinable;
250 }; // struct PointsToTransformedScalarOp
251 
252 
253 template<typename GridT, typename PointDataGridT, typename FilterT>
254 inline typename GridT::Ptr convertPointsToScalar(
255  const PointDataGridT& points,
256  const FilterT& filter,
257  bool threaded = true)
258 {
260 
261  using GridTreeT = typename GridT::TreeType;
262  using ValueT = typename GridTreeT::ValueType;
263 
264  // copy the topology from the points grid
265 
266  typename GridTreeT::Ptr tree(new GridTreeT(points.constTree(),
267  false, openvdb::TopologyCopy()));
268  typename GridT::Ptr grid = GridT::create(tree);
269  grid->setTransform(points.transform().copy());
270 
271  // early exit if no leaves
272 
273  if (points.constTree().leafCount() == 0) return grid;
274 
275  // early exit if mask and no group logic
276 
277  if (std::is_same<ValueT, bool>::value && filter.state() == index::ALL) return grid;
278 
279  // evaluate point group filters to produce a subset of the generated mask
280 
281  tree::LeafManager<GridTreeT> leafManager(*tree);
282 
283  if (filter.state() == index::ALL) {
284  NullFilter nullFilter;
286  points, nullFilter);
287  leafManager.foreach(pointsToScalarOp, threaded);
288  } else {
289  // build mask from points in parallel only where filter evaluates to true
291  points, filter);
292  leafManager.foreach(pointsToScalarOp, threaded);
293  }
294 
295  return grid;
296 }
297 
298 
299 template<typename GridT, typename PointDataGridT, typename FilterT, typename DeformerT>
300 inline typename GridT::Ptr convertPointsToScalar(
301  PointDataGridT& points,
302  const openvdb::math::Transform& transform,
303  const FilterT& filter,
304  const DeformerT& deformer,
305  bool threaded = true)
306 {
309 
310  using CombinerOpT = GridCombinerOp<GridT>;
311  using CombinableT = typename GridCombinerOp<GridT>::CombinableT;
312 
313  // use the simpler method if the requested transform matches the existing one
314 
315  const openvdb::math::Transform& pointsTransform = points.constTransform();
316 
317  if (transform == pointsTransform && std::is_same<NullDeformer, DeformerT>()) {
318  return convertPointsToScalar<GridT>(points, filter, threaded);
319  }
320 
321  typename GridT::Ptr grid = GridT::create();
322  grid->setTransform(transform.copy());
323 
324  // early exit if no leaves
325 
326  if (points.constTree().leafCount() == 0) return grid;
327 
328  // compute mask grids in parallel using new transform
329 
330  CombinableT combiner;
331 
332  tree::LeafManager<typename PointDataGridT::TreeType> leafManager(points.tree());
333 
334  if (filter.state() == index::ALL) {
335  NullFilter nullFilter;
337  transform, pointsTransform, nullFilter, deformer, combiner);
338  leafManager.foreach(pointsToScalarOp, threaded);
339  } else {
341  transform, pointsTransform, filter, deformer, combiner);
342  leafManager.foreach(pointsToScalarOp, threaded);
343  }
344 
345  // combine the mask grids into one
346 
347  CombinerOpT combineOp(*grid);
348  combiner.combine_each(combineOp);
349 
350  return grid;
351 }
352 
353 
354 } // namespace point_mask_internal
355 
356 
357 ////////////////////////////////////////
358 
359 
360 template<typename PointDataGridT, typename MaskT, typename FilterT>
362  typename MaskT::Ptr>::type
364  const PointDataGridT& points,
365  const FilterT& filter,
366  bool threaded)
367 {
368  return point_mask_internal::convertPointsToScalar<MaskT>(
369  points, filter, threaded);
370 }
371 
372 
373 template<typename PointDataGridT, typename MaskT, typename FilterT>
375  typename MaskT::Ptr>::type
377  const PointDataGridT& points,
378  const openvdb::math::Transform& transform,
379  const FilterT& filter,
380  bool threaded)
381 {
382  // This is safe because the PointDataGrid can only be modified by the deformer
384  auto& nonConstPoints = const_cast<typename AdapterT::NonConstGridType&>(points);
385 
386  NullDeformer deformer;
387  return point_mask_internal::convertPointsToScalar<MaskT>(
388  nonConstPoints, transform, filter, deformer, threaded);
389 }
390 
391 
392 ////////////////////////////////////////
393 
394 
395 } // namespace points
396 } // namespace OPENVDB_VERSION_NAME
397 } // namespace openvdb
398 
399 #endif // OPENVDB_POINTS_POINT_MASK_HAS_BEEN_INCLUDED
Compute scalar grid from PointDataGrid using a different transform and while evaluating the point fil...
Definition: PointMask.h:184
PointsToTransformedScalarOp(const math::Transform &targetTransform, const math::Transform &sourceTransform, const FilterT &filter, const DeformerT &deformer, CombinableT &combinable)
Definition: PointMask.h:191
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1063
GLuint GLenum GLenum transform
Definition: glew.h:14742
std::enable_if< std::is_same< typename MaskT::ValueType, bool >::value, typename MaskT::Ptr >::type convertPointsToMask(const PointDataGridT &grid, const FilterT &filter=NullFilter(), bool threaded=true)
Extract a Mask Grid from a Point Data Grid.
Definition: PointMask.h:363
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:167
Index filters primarily designed to be used with a FilterIndexIter.
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:50
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1068
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:2981
Deformer Traits for optionally configuring deformers to be applied in index-space. The default is world-space.
Definition: PointMask.h:76
LeafNodeT * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one, but preserve the values and active states of all voxels.
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
void setOffsetOn(Index offset, const ValueType &val)
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:485
GridT::Ptr convertPointsToScalar(const PointDataGridT &points, const FilterT &filter, bool threaded=true)
Definition: PointMask.h:254
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1253
No-op deformer (adheres to the deformer interface documented in PointMove.h)
Definition: PointMask.h:64
PointsToScalarOp(const PointDataGridT &grid, const FilterT &filter)
Definition: PointMask.h:150
Combines multiple grids into one by stealing leaf nodes and summing voxel values This class is design...
Definition: PointMask.h:107
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3446
GLuint GLuint GLsizei count
Definition: glew.h:1253
void voxelSum(LeafT &leaf, const Index offset, const typename LeafT::ValueType &value)
Definition: PointMask.h:88
Compute scalar grid from PointDataGrid while evaluating the point filter.
Definition: PointMask.h:145
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:113
GLsizei const GLfloat * value
Definition: glew.h:1849
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
GLintptr offset
Definition: glew.h:1682