HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointStatistics.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
4 /// @author Nick Avramoussis
5 ///
6 /// @file PointStatistics.h
7 ///
8 /// @brief Functions to perform multi threaded reductions and analysis of
9 /// arbitrary point attribute types. Each function imposes various
10 /// requirements on the point ValueType (such as expected operators) and
11 /// supports arbitrary point filters.
12 ///
13 
14 #ifndef OPENVDB_POINTS_STATISTICS_HAS_BEEN_INCLUDED
15 #define OPENVDB_POINTS_STATISTICS_HAS_BEEN_INCLUDED
16 
17 #include "PointDataGrid.h"
18 
19 #include <openvdb/openvdb.h>
20 #include <openvdb/Types.h>
21 #include <openvdb/math/Math.h>
23 
24 #include <tbb/parallel_reduce.h>
25 #include <tbb/parallel_for.h>
26 
27 namespace openvdb {
29 namespace OPENVDB_VERSION_NAME {
30 namespace points {
31 
32 /// @brief Evaluates the minimum and maximum values of a point attribute.
33 /// @details Performs parallel reduction by comparing values using their less
34 /// than and greater than operators. If the PointDataGrid is empty or the
35 /// filter evalutes to empty, zeroVal<ValueT>() is returned for both values.
36 /// @note The ValueT of the attribute must be copy constructible. This method
37 /// will throw if the templated ValueT does not match the given attribute.
38 /// For vectors and matrices, this results in per component comparisons.
39 /// See evalExtents for magnitudes or more custom control.
40 /// @warning if "P" is provided, the result is undefined.
41 /// @param points the point tree
42 /// @param attribute the attribute to reduce
43 /// @param filter a filter to apply to points
44 /// @return min,max value pair
45 template <typename ValueT,
46  typename CodecT = UnknownCodec,
47  typename FilterT = NullFilter,
48  typename PointDataTreeT>
49 std::pair<ValueT, ValueT>
50 evalMinMax(const PointDataTreeT& points,
51  const std::string& attribute,
52  const FilterT& filter = NullFilter());
53 
54 /// @brief Evaluates the average value of a point attribute.
55 /// @details Performs parallel reduction by cumulative moving average. The
56 /// reduction arithmetic and return value precision evaluates to:
57 /// ConvertElementType<ValueT, double>::Type
58 /// which, for POD and VDB math types, is ValueT at double precision. If the
59 /// PointDataGrid is empty or the filter evalutes to empty, zeroVal<ValueT>()
60 /// is returned.
61 /// @note The ConvertElementType of the attribute must be copy constructible,
62 /// support the same type + - * operators and * / operators from a double.
63 /// This method will throw if ValueT does not match the given attribute. The
64 /// function is deterministic.
65 /// @warning if "P" is provided, the result is undefined.
66 /// @param points the point tree
67 /// @param attribute the attribute to reduce
68 /// @param filter a filter to apply to points
69 /// @return the average value
70 template <typename ValueT,
71  typename CodecT = UnknownCodec,
72  typename FilterT = NullFilter,
73  typename PointDataTreeT>
75 evalAverage(const PointDataTreeT& points,
76  const std::string& attribute,
77  const FilterT& filter = NullFilter());
78 
79 /// @brief Evaluates the total value of a point attribute.
80 /// @details Performs parallel reduction by summing all values. The reduction
81 /// arithmetic and return value precision evaluates to:
82 /// PromoteType<ValueT>::Highest
83 /// which, for POD and VDB math types, is ValueT at its highest bit precision.
84 /// If the PointDataGrid is empty or the filter evalutes to empty,
85 /// zeroVal<ValueT>() is returned.
86 /// @note The PromoteType of the attribute must be copy constructible, support
87 /// the same type + operator. This method will throw if ValueT does not match
88 /// the given attribute. The function is deterministic.
89 /// @warning if "P" is provided, the result is undefined.
90 /// @param points the point tree
91 /// @param attribute the attribute to reduce
92 /// @param filter a filter to apply to points
93 /// @return the total value
94 template <typename ValueT,
95  typename CodecT = UnknownCodec,
96  typename FilterT = NullFilter,
97  typename PointDataTreeT>
98 typename PromoteType<ValueT>::Highest
99 accumulate(const PointDataTreeT& points,
100  const std::string& attribute,
101  const FilterT& filter = NullFilter());
102 
103 /// @brief Evaluates the minimum and maximum values of a point attribute and
104 /// returns whether the values are valid. Optionally constructs localised
105 /// min and max value trees.
106 /// @details Performs parallel reduction by comparing values using their less
107 /// than and greater than operators. This method will return true if min and
108 /// max have been set, false otherwise (when no points existed or a filter
109 /// evaluated to empty).
110 /// @note The ValueT of the attribute must also be copy constructible. This
111 /// method will throw if the templated ValueT does not match the given
112 /// attribute. For vectors and matrices, this results in per component
113 /// comparisons. See evalExtents for magnitudes or more custom control.
114 /// @warning if "P" is provided, the result is undefined.
115 /// @param points the point tree
116 /// @param attribute the attribute to reduce
117 /// @param min the computed min value
118 /// @param max the computed max value
119 /// @param filter a filter to apply to points
120 /// @param minTree if provided, builds a tiled tree of localised min results
121 /// @param maxTree if provided, builds a tiled tree of localised max results
122 /// @return true if min and max have been set, false otherwise. Can be false if
123 /// no points were processed or if the tree was empty.
124 template <typename ValueT,
125  typename CodecT = UnknownCodec,
126  typename FilterT = NullFilter,
127  typename PointDataTreeT>
128 bool evalMinMax(const PointDataTreeT& points,
129  const std::string& attribute,
130  ValueT& min,
131  ValueT& max,
132  const FilterT& filter = NullFilter(),
133  typename PointDataTreeT::template ValueConverter<ValueT>::Type* minTree = nullptr,
134  typename PointDataTreeT::template ValueConverter<ValueT>::Type* maxTree = nullptr);
135 
136 /// @brief Evaluates the average value of a point attribute and returns whether
137 /// the value is valid. Optionally constructs localised average value trees.
138 /// @details Performs parallel reduction by cumulative moving average. The
139 /// reduction arithmetic and return value precision evaluates to:
140 /// ConvertElementType<ValueT, double>::Type
141 /// which, for POD and VDB math types, is ValueT at double precision. This
142 /// method will return true average has been set, false otherwise (when no
143 /// points existed or a filter evaluated to empty).
144 /// @note The ConvertElementType of the attribute must be copy constructible,
145 /// support the same type + - * operators and * / operators from a double.
146 /// This method will throw if ValueT does not match the given attribute. The
147 /// function is deterministic.
148 /// @warning if "P" is provided, the result is undefined.
149 /// @param points the point tree
150 /// @param attribute the attribute to reduce
151 /// @param average the computed averaged value at double precision
152 /// @param filter a filter to apply to points
153 /// @param averageTree if provided, builds a tiled tree of localised avg results.
154 /// @return true if average has been set, false otherwise. Can be false if
155 /// no points were processed or if the tree was empty.
156 /// @par Example:
157 /// @code
158 /// using namespace openvdb;
159 /// using namespace openvdb::points
160 ///
161 /// // average and store per leaf values in a new tree
162 /// ConvertElementType<uint8_t, double>::Type avg; // evaluates to double
163 /// PointDataTree::ValueConverter<decltype(avg)>::Type avgTree; // double tree of averages
164 /// bool success = evalAverage<uint8_t>(tree, "attrib", avg, NullFilter(), &avgTree);
165 /// @endcode
166 template <typename ValueT,
167  typename CodecT = UnknownCodec,
168  typename FilterT = NullFilter,
169  typename PointDataTreeT,
170  typename ResultTreeT = typename ConvertElementType<ValueT, double>::Type>
171 bool evalAverage(const PointDataTreeT& points,
172  const std::string& attribute,
174  const FilterT& filter = NullFilter(),
175  typename PointDataTreeT::template ValueConverter<ResultTreeT>::Type* averageTree = nullptr);
176 
177 /// @brief Evaluates the total value of a point attribute and returns whether
178 /// the value is valid. Optionally constructs localised total value trees.
179 /// @details Performs parallel reduction by summing all values. The reduction
180 /// arithmetic and return value precision evaluates to:
181 /// PromoteType<ValueT>::Highest
182 /// which, for POD and VDB math types, is ValueT at its highest bit precision.
183 /// This method will return true total has been set, false otherwise (when no
184 /// points existed or a filter evaluated to empty).
185 /// @note The PromoteType of the attribute must be copy constructible, support
186 /// the same type + operator. This method will throw if ValueT does not match
187 /// the given attribute. The function is deterministic.
188 /// @warning if "P" is provided, the result is undefined.
189 /// @param points the point tree
190 /// @param attribute the attribute to reduce
191 /// @param total the computed total value
192 /// @param filter a filter to apply to points
193 /// @param totalTree if provided, builds a tiled tree of localised total results.
194 /// @return true if total has been set, false otherwise. Can be false if
195 /// no points were processed or if the tree was empty.
196 /// @par Example:
197 /// @code
198 /// using namespace openvdb;
199 /// using namespace openvdb::points;
200 ///
201 /// // accumulate and store per leaf values in a new tree
202 /// PromoteType<uint8_t>::Highest total; // evaluates to uint64_t
203 /// PointDataTree::ValueConverter<decltype(total)>::Type totalTree; // uint64_t tree of totals
204 /// bool success = accumulate<uint8_t>(tree, "attrib", total, NullFilter(), &totalTree);
205 /// @endcode
206 template <typename ValueT,
207  typename CodecT = UnknownCodec,
208  typename FilterT = NullFilter,
209  typename PointDataTreeT,
210  typename ResultTreeT = typename PromoteType<ValueT>::Highest>
211 bool accumulate(const PointDataTreeT& points,
212  const std::string& attribute,
213  typename PromoteType<ValueT>::Highest& total,
214  const FilterT& filter = NullFilter(),
215  typename PointDataTreeT::template ValueConverter<ResultTreeT>::Type* totalTree = nullptr);
216 
217 ///////////////////////////////////////////////////
218 ///////////////////////////////////////////////////
219 
220 namespace statistics_internal
221 {
222 
223 /// @brief Scalar extent op to evaluate the min/max values of a
224 /// single integral or floating point attribute type
225 template <typename ValueT>
227 {
228  using ExtentT = std::pair<ValueT, ValueT>;
229  ScalarMinMax(const ValueT& init) : mMinMax(init, init) {}
230  ScalarMinMax(const ExtentT& init) : mMinMax(init) {}
231  inline void operator()(const ValueT& b)
232  {
233  mMinMax.first = std::min(mMinMax.first, b);
234  mMinMax.second = std::max(mMinMax.second, b);
235  }
236  inline void operator()(const ExtentT& b)
237  {
238  mMinMax.first = std::min(mMinMax.first, b.first);
239  mMinMax.second = std::max(mMinMax.second, b.second);
240  }
241  inline const ExtentT& get() const { return mMinMax; }
243 };
244 
245 /// @brief Vector squared magnitude op to evaluate the min/max of a
246 /// vector attribute and return the result as a scalar of the
247 /// appropriate precision
248 template <typename VecT, bool MagResult = true>
250  : public ScalarMinMax<typename ValueTraits<VecT>::ElementType>
251 {
255  MagnitudeExtent(const VecT& init) : BaseT(init.lengthSqr()) {}
256  MagnitudeExtent(const ExtentT& init) : BaseT(init) {}
257  inline void operator()(const VecT& b) { this->BaseT::operator()(b.lengthSqr()); }
258  inline void operator()(const ExtentT& b) { this->BaseT::operator()(b); }
259 };
260 
261 /// @brief Vector squared magnitude op to evaluate the min/max of a
262 /// vector attribute and return the result as the original vector
263 template <typename VecT>
264 struct MagnitudeExtent<VecT, false>
265 {
267  using ExtentT = std::pair<VecT, VecT>;
268  MagnitudeExtent(const VecT& init)
269  : mLengths(), mMinMax(init, init) {
270  mLengths.first = init.lengthSqr();
271  mLengths.second = mLengths.first;
272  }
274  : mLengths(), mMinMax(init) {
275  mLengths.first = init.first.lengthSqr();
276  mLengths.second = init.second.lengthSqr();
277  }
278  inline const ExtentT& get() const { return mMinMax; }
279  inline void operator()(const VecT& b)
280  {
281  const ElementT l = b.lengthSqr();
282  if (l < mLengths.first) {
283  mLengths.first = l;
284  mMinMax.first = b;
285  }
286  else if (l > mLengths.second) {
287  mLengths.second = l;
288  mMinMax.second = b;
289  }
290  }
291  inline void operator()(const ExtentT& b)
292  {
293  ElementT l = b.first.lengthSqr();
294  if (l < mLengths.first) {
295  mLengths.first = l;
296  mMinMax.first = b.first;
297  }
298  l = b.second.lengthSqr();
299  if (l > mLengths.second) {
300  mLengths.second = l;
301  mMinMax.second = b.second;
302  }
303  }
304 
305  std::pair<ElementT, ElementT> mLengths;
307 };
308 
309 /// @brief Vector component-wise op to evaluate the min/max of
310 /// vector components and return the result as a vector of
311 /// equal size and precision
312 template <typename VecT>
314 {
315  using ExtentT = std::pair<VecT, VecT>;
316  ComponentExtent(const VecT& init) : mMinMax(init, init) {}
317  ComponentExtent(const ExtentT& init) : mMinMax(init) {}
318  inline const ExtentT& get() const { return mMinMax; }
319  inline void operator()(const VecT& b)
320  {
321  mMinMax.first = math::minComponent(mMinMax.first, b);
322  mMinMax.second = math::maxComponent(mMinMax.second, b);
323  }
324  inline void operator()(const ExtentT& b)
325  {
326  mMinMax.first = math::minComponent(mMinMax.first, b.first);
327  mMinMax.second = math::maxComponent(mMinMax.second, b.second);
328  }
329 
331 };
332 
333 template <typename ValueT,
334  typename CodecT,
335  typename FilterT,
336  typename ExtentOp,
337  typename PointDataTreeT>
338 bool evalExtents(const PointDataTreeT& points,
339  const std::string& attribute,
340  typename ExtentOp::ExtentT& ext,
341  const FilterT& filter,
342  typename PointDataTreeT::template ValueConverter
343  <typename ExtentOp::ExtentT::first_type>::Type* const minTree = nullptr,
344  typename PointDataTreeT::template ValueConverter
345  <typename ExtentOp::ExtentT::second_type>::Type* const maxTree = nullptr)
346 {
348  "PointDataTreeT in instantiation of evalExtents is not an openvdb Tree type");
349 
350  struct ResultType {
351  typename ExtentOp::ExtentT ext;
352  bool data = false;
353  };
354 
356  if (manager.leafCount() == 0) return false;
357  const size_t idx = manager.leaf(0).attributeSet().find(attribute);
358  if (idx == AttributeSet::INVALID_POS) return false;
359 
360  // track results per leaf for min/max trees
361  std::vector<std::unique_ptr<typename ExtentOp::ExtentT>> values;
362  if (minTree || maxTree) values.resize(manager.leafCount());
363 
364  const ResultType result = tbb::parallel_reduce(manager.leafRange(),
365  ResultType(),
366  [idx, &filter, &values]
367  (const auto& range, ResultType in) -> ResultType
368  {
369  for (auto leaf = range.begin(); leaf; ++leaf) {
370  AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx));
371  if (handle.size() == 0) continue;
372  if (filter.state() == index::ALL) {
373  const size_t size = handle.isUniform() ? 1 : handle.size();
374  ExtentOp op(handle.get(0));
375  for (size_t i = 1; i < size; ++i) {
376  assert(i < size_t(std::numeric_limits<Index>::max()));
377  op(handle.get(Index(i)));
378  }
379  if (!values.empty()) {
380  values[leaf.pos()].reset(new typename ExtentOp::ExtentT(op.get()));
381  }
382  if (in.data) op(in.ext);
383  in.data = true;
384  in.ext = op.get();
385  }
386  else {
387  auto iter = leaf->beginIndexOn(filter);
388  if (!iter) continue;
389  ExtentOp op(handle.get(*iter));
390  ++iter;
391  for (; iter; ++iter) op(handle.get(*iter));
392  if (!values.empty()) {
393  values[leaf.pos()].reset(new typename ExtentOp::ExtentT(op.get()));
394  }
395  if (in.data) op(in.ext);
396  in.data = true;
397  in.ext = op.get();
398  }
399  }
400 
401  return in;
402  },
403  [](const ResultType& a, const ResultType& b) -> ResultType {
404  if (!b.data) return a;
405  if (!a.data) return b;
406  ExtentOp op(a.ext); op(b.ext);
407  ResultType t;
408  t.ext = op.get();
409  t.data = true;
410  return t;
411  });
412 
413  // set minmax trees only if a new value was set - if the value
414  // hasn't changed, leave it as inactive background (this is
415  // only possible if a point leaf exists with no points or if a
416  // filter is provided but is not hit for a given leaf)
417  if (minTree || maxTree) {
418  manager.foreach([minTree, maxTree, &values]
419  (const auto& leaf, const size_t idx) {
420  const auto& v = values[idx];
421  if (v == nullptr) return;
422  const Coord& origin = leaf.origin();
423  if (minTree) minTree->addTile(1, origin, v->first, true);
424  if (maxTree) maxTree->addTile(1, origin, v->second, true);
425  }, false);
426  }
427 
428  if (result.data) ext = result.ext;
429  return result.data;
430 }
431 
432 template <typename ValueT,
433  typename CodecT,
434  typename FilterT,
435  typename PointDataTreeT,
436  typename std::enable_if<ValueTraits<ValueT>::IsVec, int>::type = 0>
437 bool evalExtents(const PointDataTreeT& points,
438  const std::string& attribute,
439  ValueT& min,
440  ValueT& max,
441  const FilterT& filter,
442  typename PointDataTreeT::template ValueConverter<ValueT>::Type* minTree,
443  typename PointDataTreeT::template ValueConverter<ValueT>::Type* maxTree)
444 {
446  const bool s = evalExtents<ValueT, CodecT, FilterT,
447  ComponentExtent<ValueT>, PointDataTreeT>
448  (points, attribute, ext, filter, minTree, maxTree);
449  if (s) min = ext.first, max = ext.second;
450  return s;
451 }
452 
453 template <typename ValueT,
454  typename CodecT,
455  typename FilterT,
456  typename PointDataTreeT,
457  typename std::enable_if<!ValueTraits<ValueT>::IsVec, int>::type = 0>
458 bool evalExtents(const PointDataTreeT& points,
459  const std::string& attribute,
460  ValueT& min,
461  ValueT& max,
462  const FilterT& filter,
463  typename PointDataTreeT::template ValueConverter<ValueT>::Type* minTree,
464  typename PointDataTreeT::template ValueConverter<ValueT>::Type* maxTree)
465 {
466  typename ScalarMinMax<ValueT>::ExtentT ext;
467  const bool s = evalExtents<ValueT, CodecT, FilterT,
468  ScalarMinMax<ValueT>, PointDataTreeT>
469  (points, attribute, ext, filter, minTree, maxTree);
470  if (s) min = ext.first, max = ext.second;
471  return s;
472 }
473 
474 } // namespace statistics_internal
475 
476 template <typename ValueT,
477  typename CodecT,
478  typename FilterT,
479  typename PointDataTreeT>
480 bool evalMinMax(const PointDataTreeT& points,
481  const std::string& attribute,
482  ValueT& min,
483  ValueT& max,
484  const FilterT& filter,
485  typename PointDataTreeT::template ValueConverter<ValueT>::Type* minTree,
486  typename PointDataTreeT::template ValueConverter<ValueT>::Type* maxTree)
487 {
488  return statistics_internal::evalExtents<ValueT, CodecT, FilterT, PointDataTreeT>
489  (points, attribute, min, max, filter, minTree, maxTree);
490 }
491 
492 template <typename ValueT,
493  typename CodecT,
494  typename FilterT,
495  typename PointDataTreeT,
496  typename ResultTreeT>
497 bool evalAverage(const PointDataTreeT& points,
498  const std::string& attribute,
500  const FilterT& filter,
501  typename PointDataTreeT::template ValueConverter<ResultTreeT>::Type* averageTree)
502 {
503  using ResultT = typename ConvertElementType<ValueT, double>::Type;
504 
505  struct Sample
506  {
507  Sample(const ResultT& _avg, size_t _size) : avg(_avg), size(_size) {}
508 
509  void add(const ResultT& val)
510  {
511  ++size;
512  const ResultT delta = val - avg;
513  avg = avg + (delta / static_cast<double>(size));
514  }
515 
516  void add(const Sample& other)
517  {
518  assert(other.size > 0);
519  const double denom = 1.0 / static_cast<double>(size + other.size);
520  const ResultT delta = other.avg - avg;
521  avg = avg + (denom * delta * static_cast<double>(other.size));
522  size += other.size;
523  }
524 
525  ResultT avg; size_t size;
526  };
527 
529  "PointDataTreeT in instantiation of evalAverage is not an openvdb Tree type");
531  "Target value in points::evalAverage is not constructible from the source value type.");
532 
534  if (manager.leafCount() == 0) return false;
535  const size_t idx = manager.leaf(0).attributeSet().find(attribute);
536  if (idx == AttributeSet::INVALID_POS) return false;
537 
538  std::vector<std::unique_ptr<Sample>> values;
539  values.resize(manager.leafCount());
540  tbb::parallel_for(manager.leafRange(),
541  [idx, &filter, &values] (const auto& range) {
542  for (auto leaf = range.begin(); leaf; ++leaf) {
543  AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx));
544  size_t size = handle.size();
545  if (size == 0) continue;
546  if (filter.state() == index::ALL) {
547  std::unique_ptr<Sample> S(new Sample(ResultT(handle.get(0)), 1));
548  if (handle.isUniform()) {
549  S->avg = S->avg / static_cast<double>(size);
550  S->size = size;
551  }
552  else {
553  for (size_t i = 1; i < size; ++i) {
554  assert(i < size_t(std::numeric_limits<Index>::max()));
555  S->add(ResultT(handle.get(Index(i))));
556  }
557  }
558  values[leaf.pos()] = std::move(S);
559  }
560  else {
561  auto iter = leaf->beginIndexOn(filter);
562  if (!iter) continue;
563  std::unique_ptr<Sample> S(new Sample(ResultT(handle.get(*iter)), 1));
564  ++iter;
565  for (; iter; ++iter, ++size) {
566  S->add(ResultT(handle.get(*iter)));
567  }
568  values[leaf.pos()] = std::move(S);
569  }
570  }
571  });
572 
573  auto iter = values.cbegin();
574  while (iter != values.cend() && !(*iter)) ++iter;
575  if (iter == values.cend()) return false;
576  assert(*iter);
577 
578  // serial deterministic reduction of floating point samples
579  Sample S = **iter;
580  ++iter;
581  for (; iter != values.cend(); ++iter) {
582  if (*iter) S.add(**iter);
583  }
584  average = S.avg;
585 
586  // set average tree only if a new value was set - if the value
587  // hasn't changed, leave it as inactive background (this is
588  // only possible if a point leaf exists with no points or if a
589  // filter is provided but is not hit for a given leaf)
590  if (averageTree) {
591  manager.foreach([averageTree, &values]
592  (const auto& leaf, const size_t idx) {
593  const auto& S = values[idx];
594  if (S == nullptr) return;
595  const Coord& origin = leaf.origin();
596  averageTree->addTile(1, origin, S->avg, true);
597  }, false);
598  }
599 
600  return true;
601 }
602 
603 template <typename ValueT,
604  typename CodecT,
605  typename FilterT,
606  typename PointDataTreeT,
607  typename ResultTreeT>
608 bool accumulate(const PointDataTreeT& points,
609  const std::string& attribute,
610  typename PromoteType<ValueT>::Highest& total,
611  const FilterT& filter,
612  typename PointDataTreeT::template ValueConverter<ResultTreeT>::Type* totalTree)
613 {
614  using ResultT = typename PromoteType<ValueT>::Highest;
615  using ElementT = typename ValueTraits<ResultT>::ElementType;
616 
618  "PointDataTreeT in instantiation of accumulate is not an openvdb Tree type");
620  "Target value in points::accumulate is not constructible from the source value type.");
621 
623  if (manager.leafCount() == 0) return false;
624  const size_t idx = manager.leaf(0).attributeSet().find(attribute);
625  if (idx == AttributeSet::INVALID_POS) return false;
626 
627  std::vector<std::unique_ptr<ResultT>> values;
628  values.resize(manager.leafCount());
629  tbb::parallel_for(manager.leafRange(),
630  [idx, &filter, &values](const auto& range) {
631  for (auto leaf = range.begin(); leaf; ++leaf) {
632  AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx));
633  if (handle.size() == 0) continue;
634  if (filter.state() == index::ALL) {
635  const size_t size = handle.isUniform() ? 1 : handle.size();
636  auto total = ResultT(handle.get(0));
637  for (size_t i = 1; i < size; ++i) {
638  assert(i < size_t(std::numeric_limits<Index>::max()));
639  total += ResultT(handle.get(Index(i)));
640  }
641  values[leaf.pos()].reset(new ResultT(total));
642  }
643  else {
644  auto iter = leaf->beginIndexOn(filter);
645  if (!iter) continue;
646  auto total = ResultT(handle.get(*iter));
647  ++iter;
648  for (; iter; ++iter) total += ResultT(handle.get(*iter));
649  values[leaf.pos()].reset(new ResultT(total));
650  }
651  }
652  });
653 
654  auto iter = values.cbegin();
655  while (iter != values.cend() && !(*iter)) ++iter;
656  if (iter == values.cend()) return false;
657  assert(*iter);
658  total = **iter; ++iter;
659 
661  using RangeT = tbb::blocked_range<const std::unique_ptr<ResultT>*>;
662  // reasonable grain size for accumulation of single to matrix types
663  total = tbb::parallel_reduce(RangeT(&(*iter), (&values.back())+1, 32), total,
664  [](const RangeT& range, ResultT p) -> ResultT {
665  for (const auto& r : range) if (r) p += *r;
666  return p;
667  }, std::plus<ResultT>());
668  }
669  else {
670  for (; iter != values.cend(); ++iter) {
671  if (*iter) total += (**iter);
672  }
673  }
674 
675  // set total tree only if a new value was set - if the value
676  // hasn't changed, leave it as inactive background (this is
677  // only possible if a point leaf exists with no points or if a
678  // filter is provided but is not hit for a given leaf)
679  if (totalTree) {
680  manager.foreach([totalTree, &values]
681  (const auto& leaf, const size_t idx) {
682  const auto& v = values[idx];
683  if (v == nullptr) return;
684  const Coord& origin = leaf.origin();
685  totalTree->addTile(1, origin, *v, true);
686  }, false);
687  }
688 
689  return true;
690 }
691 
692 template <typename ValueT,
693  typename CodecT,
694  typename FilterT,
695  typename PointDataTreeT>
696 std::pair<ValueT, ValueT>
697 evalMinMax(const PointDataTreeT& points,
698  const std::string& attribute,
699  const FilterT& filter)
700 {
701  std::pair<ValueT, ValueT> results {
702  zeroVal<ValueT>(), zeroVal<ValueT>()
703  };
704  evalMinMax<ValueT, CodecT, FilterT, PointDataTreeT>
705  (points, attribute, results.first, results.second, filter);
706  return results;
707 }
708 
709 template <typename ValueT,
710  typename CodecT,
711  typename FilterT,
712  typename PointDataTreeT>
714 evalAverage(const PointDataTreeT& points,
715  const std::string& attribute,
716  const FilterT& filter)
717 {
718  using ConvertedT = typename ConvertElementType<ValueT, double>::Type;
719  ConvertedT result = zeroVal<ConvertedT>();
720  evalAverage<ValueT, CodecT, FilterT, PointDataTreeT>(points, attribute, result, filter);
721  return result;
722 }
723 
724 template <typename ValueT,
725  typename CodecT,
726  typename FilterT,
727  typename PointDataTreeT>
729 accumulate(const PointDataTreeT& points,
730  const std::string& attribute,
731  const FilterT& filter)
732 {
733  using PromotedT = typename PromoteType<ValueT>::Highest;
734  PromotedT result = zeroVal<PromotedT>();
735  accumulate<ValueT, CodecT, FilterT, PointDataTreeT>(points, attribute, result, filter);
736  return result;
737 }
738 
739 } // namespace points
740 } // namespace OPENVDB_VERSION_NAME
741 } // namespace openvdb
742 
743 #endif // OPENVDB_POINTS_STATISTICS_HAS_BEEN_INCLUDED
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:508
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
Definition: parallel.h:127
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
typename T::ValueType ElementType
Definition: Types.h:263
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:345
Vector squared magnitude op to evaluate the min/max of a vector attribute and return the result as a ...
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:207
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Scalar extent op to evaluate the min/max values of a single integral or floating point attribute type...
GLdouble GLdouble t
Definition: glew.h:1403
GLuint in
Definition: glew.h:11552
GLdouble l
Definition: glew.h:9164
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1602
GLsizeiptr size
Definition: glcorearb.h:664
size_t leafCount() const
Return the number of leaf nodes.
Definition: LeafManager.h:287
GLuint64EXT * result
Definition: glew.h:14311
PromoteType< ValueT >::Highest accumulate(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Evaluates the total value of a point attribute.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
const GLdouble * v
Definition: glcorearb.h:837
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
std::pair< ValueTraits< VecT >::ElementType, ValueTraits< VecT >::ElementType > ExtentT
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
GLfloat GLfloat p
Definition: glew.h:16656
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1297
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
ConvertElementType< ValueT, double >::Type evalAverage(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Evaluates the average value of a point attribute.
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3460
GLuint GLfloat * val
Definition: glcorearb.h:1608
Vector component-wise op to evaluate the min/max of vector components and return the result as a vect...
typename TypeT< 64ul >::type Highest
Definition: Types.h:332
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:517
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool evalExtents(const PointDataTreeT &points, const std::string &attribute, typename ExtentOp::ExtentT &ext, const FilterT &filter, typename PointDataTreeT::template ValueConverter< typename ExtentOp::ExtentT::first_type >::Type *const minTree=nullptr, typename PointDataTreeT::template ValueConverter< typename ExtentOp::ExtentT::second_type >::Type *const maxTree=nullptr)
OIIO_API bool attribute(string_view name, TypeDesc type, const void *val)
GLenum GLint * range
Definition: glcorearb.h:1925
std::pair< ValueT, ValueT > evalMinMax(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Evaluates the minimum and maximum values of a point attribute.
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
ImageBuf OIIO_API add(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition: LeafManager.h:318
type
Definition: core.h:1059
GLboolean r
Definition: glcorearb.h:1222
GLdouble s
Definition: glew.h:1395
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Definition: format.h:895