OpenVDB  8.1.1
PointMask.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
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 
36 template <typename PointDataGridT,
37  typename MaskT = typename PointDataGridT::template ValueConverter<bool>::Type,
38  typename FilterT = NullFilter>
39 inline typename std::enable_if<std::is_same<typename MaskT::ValueType, bool>::value,
40  typename MaskT::Ptr>::type
41 convertPointsToMask(const PointDataGridT& grid,
42  const FilterT& filter = NullFilter(),
43  bool threaded = true);
44 
45 
52 template <typename PointDataGridT,
53  typename MaskT = typename PointDataGridT::template ValueConverter<bool>::Type,
54  typename FilterT = NullFilter>
55 inline typename std::enable_if<std::is_same<typename MaskT::ValueType, bool>::value,
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 
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 
75 template <typename DeformerT>
77 {
78  static const bool IndexSpace = false;
79 };
80 
81 
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>
97 void voxelSum(PointDataLeafNode<T, Log2Dim>& leaf, const Index offset,
98  const typename PointDataLeafNode<T, Log2Dim>::ValueType& value)
99 {
100  leaf.setOffsetOn(offset, leaf.getValue(offset) + value);
101 }
102 
103 
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 
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) {
164  const Index64 count = points::iterCount(
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 
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 
358 
359 
360 template<typename PointDataGridT, typename MaskT, typename FilterT>
361 inline typename std::enable_if<std::is_same<typename MaskT::ValueType, bool>::value,
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>
374 inline typename std::enable_if<std::is_same<typename MaskT::ValueType, bool>::value,
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 
393 
394 
395 } // namespace points
396 } // namespace OPENVDB_VERSION_NAME
397 } // namespace openvdb
398 
399 #endif // OPENVDB_POINTS_POINT_MASK_HAS_BEEN_INCLUDED
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: LeafNode.h:1063
GridT::Ptr convertPointsToScalar(PointDataGridT &points, const openvdb::math::Transform &transform, const FilterT &filter, const DeformerT &deformer, bool threaded=true)
Definition: PointMask.h:300
Definition: ValueAccessor.h:182
void operator()(LeafT &leaf, size_t) const
Definition: PointMask.h:155
typename PointDataGridT::TreeType::LeafNodeType PointDataLeafT
Definition: PointMask.h:186
PointsToScalarOp(const PointDataGridT &grid, const FilterT &filter)
Definition: PointMask.h:150
void setOffsetOn(Index offset, const ValueType &val)
Definition: PointDataGrid.h:1104
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.
Definition: ValueAccessor.h:348
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
Definition: IndexIterator.h:314
GridCombinerOp(GridT &grid)
Definition: PointMask.h:116
This adapter allows code that is templated on a Tree type to accept either a Tree type or a Grid type...
Definition: Grid.h:1070
typename TreeT::ValueType ValueType
Definition: PointMask.h:113
PointsToTransformedScalarOp(const math::Transform &targetTransform, const math::Transform &sourceTransform, const FilterT &filter, const DeformerT &deformer, CombinableT &combinable)
Definition: PointMask.h:191
Definition: AttributeArray.h:800
typename LeafT::ValueType ValueT
Definition: PointMask.h:148
Definition: ValueTransformer.h:250
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:50
typename GridT::TreeType::ValueType ValueT
Definition: PointMask.h:187
void apply(Vec3d &, IterT &) const
Definition: PointMask.h:70
Index filters primarily designed to be used with a FilterIndexIter.
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
Index32 Index
Definition: openvdb/Types.h:50
typename GridT::TreeType TreeT
Definition: PointMask.h:111
Vec3< double > Vec3d
Definition: Vec3.h:668
Definition: PointDataGrid.h:181
Deformer Traits for optionally configuring deformers to be applied in index-space. The default is world-space.
Definition: PointMask.h:76
Combines multiple grids into one by stealing leaf nodes and summing voxel values This class is design...
Definition: PointMask.h:107
Definition: openvdb/Exceptions.h:13
void reset(LeafT &, size_t=0)
Definition: PointMask.h:67
uint64_t Index64
Definition: openvdb/Types.h:49
std::enable_if< std::is_same< typename MaskT::ValueType, bool >::value, typename MaskT::Ptr >::type convertPointsToMask(const PointDataGridT &grid, const openvdb::math::Transform &transform, const FilterT &filter=NullFilter(), bool threaded=true)
Extract a Mask Grid from a Point Data Grid using a new transform.
Definition: PointMask.h:376
typename GridCombinerOp< GridT >::CombinableT CombinableT
Definition: PointMask.h:189
Definition: IndexIterator.h:43
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: openvdb/Types.h:560
typename TreeT::LeafNodeType LeafT
Definition: PointMask.h:112
Compute scalar grid from PointDataGrid while evaluating the point filter.
Definition: PointMask.h:145
void operator()(const PointDataLeafT &leaf, size_t idx) const
Definition: PointMask.h:202
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
No-op deformer (adheres to the deformer interface documented in PointMove.h)
Definition: PointMask.h:64
typename tbb::combinable< GridT > CombinableT
Definition: PointMask.h:109
typename GridT::TreeType::LeafNodeType LeafT
Definition: PointMask.h:147
void operator()(const GridT &grid)
Definition: PointMask.h:119
Compute scalar grid from PointDataGrid using a different transform and while evaluating the point fil...
Definition: PointMask.h:184
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
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:483
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:178
Definition: Transform.h:39
T ValueType
Definition: PointDataGrid.h:245
void voxelSum(PointDataLeafNode< T, Log2Dim > &leaf, const Index offset, const typename PointDataLeafNode< T, Log2Dim >::ValueType &value)
Definition: PointMask.h:97