OpenVDB  12.1.0
PointRasterizeTrilinearImpl.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 PointRasterizeTrilinearImpl.h
7 ///
8 
9 #ifndef OPENVDB_POINTS_RASTERIZE_TRILINEAR_IMPL_HAS_BEEN_INCLUDED
10 #define OPENVDB_POINTS_RASTERIZE_TRILINEAR_IMPL_HAS_BEEN_INCLUDED
11 
12 namespace openvdb {
14 namespace OPENVDB_VERSION_NAME {
15 namespace points {
16 
17 /// @cond OPENVDB_DOCS_INTERNAL
18 
19 namespace rasterize_trilinear_internal {
20 
21 template <typename TreeType,
22  typename PositionCodecT,
23  typename SourceValueT,
24  typename SourceCodecT,
25  typename FilterT>
26 struct TrilinearTransfer :
27  public VolumeTransfer<TreeType>,
28  public FilteredTransfer<FilterT>
29 {
30  using BaseT = VolumeTransfer<TreeType>;
31  using FilterTransferT = FilteredTransfer<FilterT>;
32  using WeightT = typename TreeType::ValueType;
33  using PositionHandleT = points::AttributeHandle<Vec3f, PositionCodecT>;
34  using SourceHandleT = points::AttributeHandle<SourceValueT, SourceCodecT>;
35 
36  // precision of kernel arithmetic - aliased to the floating point
37  // element type of the source attribute.
38  using SourceElementT = typename ValueTraits<SourceValueT>::ElementType;
39  using RealT = SourceElementT;
40 
41  static_assert(std::is_floating_point<SourceElementT>::value,
42  "Trilinear rasterization only supports floating point values.");
43 
44  static const Index NUM_VALUES = TreeType::LeafNodeType::NUM_VALUES;
45 
46  TrilinearTransfer(const size_t pidx,
47  const size_t sidx,
48  const FilterT& filter,
49  TreeType& tree)
50  : BaseT(tree)
51  , FilterTransferT(filter)
52  , mPIdx(pidx)
53  , mSIdx(sidx)
54  , mPHandle()
55  , mSHandle()
56  , mWeights() {}
57 
58  TrilinearTransfer(const TrilinearTransfer& other)
59  : BaseT(other)
60  , FilterTransferT(other)
61  , mPIdx(other.mPIdx)
62  , mSIdx(other.mSIdx)
63  , mPHandle()
64  , mSHandle()
65  , mWeights() {}
66 
67  //// @note Kernel value evaluator
68  static inline RealT value(const RealT x)
69  {
70  const RealT abs_x = std::fabs(x);
71  if (abs_x < RealT(1.0)) return RealT(1.0) - abs_x;
72  return RealT(0.0);
73  }
74 
75  inline static Int32 range() { return 1; }
76  inline Int32 range(const Coord&, size_t) const { return this->range(); }
77 
78  inline void initialize(const Coord& origin, const size_t idx, const CoordBBox& bounds)
79  {
80  this->BaseT::initialize(origin, idx, bounds);
81  this->FilterTransferT::initialize(origin, idx, bounds);
82  mWeights.fill(openvdb::zeroVal<WeightT>());
83  }
84 
85  inline bool startPointLeaf(const PointDataTree::LeafNodeType& leaf)
86  {
87  this->FilterTransferT::startPointLeaf(leaf);
88  mPHandle.reset(new PositionHandleT(leaf.constAttributeArray(mPIdx)));
89  mSHandle.reset(new SourceHandleT(leaf.constAttributeArray(mSIdx)));
90  return true;
91  }
92 
93  inline bool endPointLeaf(const PointDataTree::LeafNodeType&) { return true; }
94 
95 protected:
96  const size_t mPIdx;
97  const size_t mSIdx;
98  typename PositionHandleT::UniquePtr mPHandle;
99  typename SourceHandleT::UniquePtr mSHandle;
100  std::array<WeightT, NUM_VALUES> mWeights;
101 };
102 
103 template <typename TreeType,
104  typename PositionCodecT,
105  typename SourceValueT,
106  typename SourceCodecT,
107  typename FilterT>
108 struct StaggeredTransfer :
109  public TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>
110 {
111  using BaseT = TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>;
112  using RealT = typename BaseT::RealT;
113  using BaseT::value;
114 
116  "Target Tree must be a vector tree for staggered rasterization");
117 
118  static const Index DIM = TreeType::LeafNodeType::DIM;
119  static const Index LOG2DIM = TreeType::LeafNodeType::LOG2DIM;
120 
121  StaggeredTransfer(const size_t pidx,
122  const size_t sidx,
123  const FilterT& filter,
124  TreeType& tree)
125  : BaseT(pidx, sidx, filter, tree) {}
126 
127  void rasterizePoint(const Coord& ijk,
128  const Index id,
129  const CoordBBox& bounds)
130  {
131  if (!BaseT::filter(id)) return;
132 
133  CoordBBox intersectBox(ijk.offsetBy(-1), ijk.offsetBy(1));
134  intersectBox.intersect(bounds);
135  if (intersectBox.empty()) return;
136 
137  auto* const data = this->buffer();
138  const auto& mask = *(this->mask());
139 
140  const math::Vec3<RealT> P(this->mPHandle->get(id));
141  const SourceValueT s(this->mSHandle->get(id));
142 
143  math::Vec3<RealT> centerw, macw;
144 
145  const Coord& a(intersectBox.min());
146  const Coord& b(intersectBox.max());
147  for (Coord c = a; c.x() <= b.x(); ++c.x()) {
148  // @todo can probably simplify the double call to value() in some way
149  const Index i = ((c.x() & (DIM-1u)) << 2*LOG2DIM); // unsigned bit shift mult
150  const RealT x = static_cast<RealT>(c.x()-ijk.x()); // distance from ijk to c
151  centerw[0] = value(P.x() - x); // center dist
152  macw.x() = value(P.x() - (x-RealT(0.5))); // mac dist
153 
154  for (c.y() = a.y(); c.y() <= b.y(); ++c.y()) {
155  const Index ij = i + ((c.y() & (DIM-1u)) << LOG2DIM);
156  const RealT y = static_cast<RealT>(c.y()-ijk.y());
157  centerw[1] = value(P.y() - y);
158  macw.y() = value(P.y() - (y-RealT(0.5)));
159 
160  for (c.z() = a.z(); c.z() <= b.z(); ++c.z()) {
161  OPENVDB_ASSERT(bounds.isInside(c));
162  const Index offset = ij + /*k*/(c.z() & (DIM-1u));
163  if (!mask.isOn(offset)) continue;
164  const RealT z = static_cast<RealT>(c.z()-ijk.z());
165  centerw[2] = value(P.z() - z);
166  macw.z() = value(P.z() - (z-RealT(0.5)));
167 
168  const math::Vec3<RealT> r {
169  (macw[0] * centerw[1] * centerw[2]),
170  (macw[1] * centerw[0] * centerw[2]),
171  (macw[2] * centerw[0] * centerw[1])
172  };
173 
174  data[offset] += s * r;
175  this->mWeights[offset] += r;
176  }
177  }
178  }
179  }
180 
181  inline bool finalize(const Coord&, const size_t)
182  {
183  auto* const data = this->buffer();
184  const auto& mask = *(this->mask());
185 
186  for (auto iter = mask.beginOn(); iter; ++iter) {
187  const Index offset = iter.pos();
188  const auto& w = this->mWeights[offset];
189  auto& v = data[offset];
190  if (!math::isZero(w[0])) v[0] /= w[0];
191  if (!math::isZero(w[1])) v[1] /= w[1];
192  if (!math::isZero(w[2])) v[2] /= w[2];
193  }
194 
195  return true;
196  }
197 };
198 
199 template <typename TreeType,
200  typename PositionCodecT,
201  typename SourceValueT,
202  typename SourceCodecT,
203  typename FilterT>
204 struct CellCenteredTransfer :
205  public TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>
206 {
207  using BaseT = TrilinearTransfer<TreeType, PositionCodecT, SourceValueT, SourceCodecT, FilterT>;
208  using RealT = typename BaseT::RealT;
209  using BaseT::value;
210 
211  static const Index DIM = TreeType::LeafNodeType::DIM;
212  static const Index LOG2DIM = TreeType::LeafNodeType::LOG2DIM;
213 
214  CellCenteredTransfer(const size_t pidx,
215  const size_t sidx,
216  const FilterT& filter,
217  TreeType& tree)
218  : BaseT(pidx, sidx, filter, tree) {}
219 
220  void rasterizePoint(const Coord& ijk,
221  const Index id,
222  const CoordBBox& bounds)
223  {
224  if (!BaseT::filter(id)) return;
225 
226  const Vec3f P(this->mPHandle->get(id));
227 
228  // build area of influence depending on point position
229  CoordBBox intersectBox(ijk, ijk);
230  if (P.x() < 0.0f) intersectBox.min().x() -= 1;
231  else intersectBox.max().x() += 1;
232  if (P.y() < 0.0f) intersectBox.min().y() -= 1;
233  else intersectBox.max().y() += 1;
234  if (P.z() < 0.0f) intersectBox.min().z() -= 1;
235  else intersectBox.max().z() += 1;
236  OPENVDB_ASSERT(intersectBox.volume() == 8);
237 
238  intersectBox.intersect(bounds);
239  if (intersectBox.empty()) return;
240 
241  auto* const data = this->buffer();
242  const auto& mask = *(this->mask());
243 
244  const SourceValueT s(this->mSHandle->get(id));
245  math::Vec3<RealT> centerw;
246 
247  const Coord& a(intersectBox.min());
248  const Coord& b(intersectBox.max());
249  for (Coord c = a; c.x() <= b.x(); ++c.x()) {
250  const Index i = ((c.x() & (DIM-1u)) << 2*LOG2DIM); // unsigned bit shift mult
251  const RealT x = static_cast<RealT>(c.x()-ijk.x()); // distance from ijk to c
252  centerw[0] = value(P.x() - x); // center dist
253 
254  for (c.y() = a.y(); c.y() <= b.y(); ++c.y()) {
255  const Index ij = i + ((c.y() & (DIM-1u)) << LOG2DIM);
256  const RealT y = static_cast<RealT>(c.y()-ijk.y());
257  centerw[1] = value(P.y() - y);
258 
259  for (c.z() = a.z(); c.z() <= b.z(); ++c.z()) {
260  OPENVDB_ASSERT(bounds.isInside(c));
261  const Index offset = ij + /*k*/(c.z() & (DIM-1u));
262  if (!mask.isOn(offset)) continue;
263  const RealT z = static_cast<RealT>(c.z()-ijk.z());
264  centerw[2] = value(P.z() - z);
265 
266  OPENVDB_ASSERT(centerw[0] >= 0.0f && centerw[0] <= 1.0f);
267  OPENVDB_ASSERT(centerw[1] >= 0.0f && centerw[1] <= 1.0f);
268  OPENVDB_ASSERT(centerw[2] >= 0.0f && centerw[2] <= 1.0f);
269 
270  const RealT weight = centerw.product();
271  data[offset] += s * weight;
272  this->mWeights[offset] += weight;
273  }
274  }
275  }
276  }
277 
278  inline bool finalize(const Coord&, const size_t)
279  {
280  auto* const data = this->buffer();
281  const auto& mask = *(this->mask());
282 
283  for (auto iter = mask.beginOn(); iter; ++iter) {
284  const Index offset = iter.pos();
285  const auto& w = this->mWeights[offset];
286  auto& v = data[offset];
287  if (!math::isZero(w)) v /= w;
288  }
289  return true;
290  }
291 };
292 
293 // @note If building with MSVC we have to use auto to deduce the return type
294 // due to a compiler bug. We can also use that for the public API - but
295 // we explicitly define it in non-msvc builds to ensure the API remains
296 // consistent
297 template <bool Staggered,
298  typename ValueT,
299  typename CodecT,
300  typename PositionCodecT,
301  typename FilterT,
302  typename PointDataTreeT>
303 inline
304 #ifndef _MSC_VER
305 typename TrilinearTraits<ValueT, Staggered>::template TreeT<PointDataTreeT>::Ptr
306 #else
307 auto
308 #endif
309 rasterizeTrilinear(const PointDataTreeT& points,
310  const size_t pidx,
311  const size_t sidx,
312  const FilterT& filter)
313 {
314  using TraitsT = TrilinearTraits<ValueT, Staggered>;
315  using TargetTreeT = typename TraitsT::template TreeT<PointDataTree>;
316  using TransferT = typename std::conditional<Staggered,
317  StaggeredTransfer<TargetTreeT, PositionCodecT, ValueT, CodecT, FilterT>,
318  CellCenteredTransfer<TargetTreeT, PositionCodecT, ValueT, CodecT, FilterT>
319  >::type;
320 
321  typename TargetTreeT::Ptr tree = std::make_shared<TargetTreeT>();
322  if (std::is_same<FilterT, NullFilter>::value) {
323  tree->topologyUnion(points);
324  }
325  else {
326  using MaskTreeT = typename PointDataTreeT::template ValueConverter<ValueMask>::Type;
327  auto mask = convertPointsToMask<PointDataTreeT, MaskTreeT>(points, filter);
328  tree->topologyUnion(*mask);
329  }
330 
331  TransferT transfer(pidx, sidx, filter, *tree);
332  tools::dilateActiveValues(*tree, transfer.range(),
334 
335  rasterize<PointDataTreeT, TransferT>(points, transfer);
336  return tree;
337 }
338 
339 } // namespace rasterize_trilinear_internal
340 
341 /// @endcond
342 
343 ///////////////////////////////////////////////////
344 
345 template <bool Staggered,
346  typename ValueT,
347  typename FilterT,
348  typename PointDataTreeT>
349 inline auto
350 rasterizeTrilinear(const PointDataTreeT& points,
351  const std::string& attribute,
352  const FilterT& filter)
353 {
354  using TraitsT = TrilinearTraits<ValueT, Staggered>;
355  using TargetTreeT = typename TraitsT::template TreeT<PointDataTree>;
356 
357  const auto iter = points.cbeginLeaf();
358  if (!iter) return typename TargetTreeT::Ptr(new TargetTreeT);
359 
360  const AttributeSet::Descriptor& descriptor = iter->attributeSet().descriptor();
361  const size_t pidx = descriptor.find("P");
362  const size_t sidx = descriptor.find(attribute);
363  if (pidx == AttributeSet::INVALID_POS) {
364  OPENVDB_THROW(RuntimeError, "Failed to find position attribute");
365  }
366  if (sidx == AttributeSet::INVALID_POS) {
367  OPENVDB_THROW(RuntimeError, "Failed to find source attribute");
368  }
369 
370  const NamePair& ptype = descriptor.type(pidx);
371  const NamePair& stype = descriptor.type(sidx);
372  if (ptype.second == NullCodec::name()) {
373  if (stype.second == NullCodec::name()) {
375  <Staggered, ValueT, NullCodec, NullCodec>
376  (points, pidx, sidx, filter);
377  }
378  else {
380  <Staggered, ValueT, UnknownCodec, NullCodec>
381  (points, pidx, sidx, filter);
382  }
383  }
384  else {
385  if (stype.second == NullCodec::name()) {
387  <Staggered, ValueT, NullCodec, UnknownCodec>
388  (points, pidx, sidx, filter);
389  }
390  else {
392  <Staggered, ValueT, UnknownCodec, UnknownCodec>
393  (points, pidx, sidx, filter);
394  }
395  }
396 }
397 
398 
399 } // namespace points
400 } // namespace OPENVDB_VERSION_NAME
401 } // namespace openvdb
402 
403 #endif //OPENVDB_POINTS_RASTERIZE_TRILINEAR_IMPL_HAS_BEEN_INCLUDED
int32_t Int32
Definition: Types.h:56
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
OPENVDB_IMPORT void initialize()
Global registration of native Grid, Transform, Metadata and Point attribute types. Also initializes blosc (if enabled).
Index32 Index
Definition: Types.h:54
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
Definition: Exceptions.h:63
math::Vec3< float > Vec3f
Definition: Types.h:74
static const bool IsVec
Definition: Types.h:316
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition: Math.h:337
Definition: Exceptions.h:13
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:40
Definition: PointRasterizeTrilinear.h:36
typename T::ValueType ElementType
Definition: Types.h:373
void dilateActiveValues(TreeOrLeafManagerT &tree, const int iterations=1, const NearestNeighbors nn=NN_FACE, const TilePolicy mode=PRESERVE_TILES, const bool threaded=true)
Topologically dilate all active values (i.e. both voxels and tiles) in a tree using one of three near...
Definition: Morphology.h:1057
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
Definition: Morphology.h:82
auto rasterizeTrilinear(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Perform weighted trilinear rasterization of all points within a voxel. This method takes and returns ...
Definition: PointRasterizeTrilinearImpl.h:350
Definition: AttributeArray.h:436
Definition: AttributeArray.h:433
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218