OpenVDB 10.0.1
Loading...
Searching...
No Matches
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
27namespace openvdb {
29namespace OPENVDB_VERSION_NAME {
30namespace 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
45template <typename ValueT,
46 typename CodecT = UnknownCodec,
47 typename FilterT = NullFilter,
48 typename PointDataTreeT>
49std::pair<ValueT, ValueT>
50evalMinMax(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
70template <typename ValueT,
71 typename CodecT = UnknownCodec,
72 typename FilterT = NullFilter,
73 typename PointDataTreeT>
74typename ConvertElementType<ValueT, double>::Type
75evalAverage(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
94template <typename ValueT,
95 typename CodecT = UnknownCodec,
96 typename FilterT = NullFilter,
97 typename PointDataTreeT>
98typename PromoteType<ValueT>::Highest
99accumulate(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.
124template <typename ValueT,
125 typename CodecT = UnknownCodec,
126 typename FilterT = NullFilter,
127 typename PointDataTreeT>
128bool 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
166template <typename ValueT,
167 typename CodecT = UnknownCodec,
168 typename FilterT = NullFilter,
169 typename PointDataTreeT,
170 typename ResultTreeT = typename ConvertElementType<ValueT, double>::Type>
171bool evalAverage(const PointDataTreeT& points,
172 const std::string& attribute,
173 typename ConvertElementType<ValueT, double>::Type& average,
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
206template <typename ValueT,
207 typename CodecT = UnknownCodec,
208 typename FilterT = NullFilter,
209 typename PointDataTreeT,
210 typename ResultTreeT = typename PromoteType<ValueT>::Highest>
211bool 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
220namespace 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
225template <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
248template <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
263template <typename VecT>
264struct 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
312template <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
333template <typename ValueT,
334 typename CodecT,
335 typename FilterT,
336 typename ExtentOp,
337 typename PointDataTreeT>
338bool 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{
347 static_assert(std::is_base_of<TreeBase, PointDataTreeT>::value,
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
432template <typename ValueT,
433 typename CodecT,
434 typename FilterT,
435 typename PointDataTreeT,
436 typename std::enable_if<ValueTraits<ValueT>::IsVec, int>::type = 0>
437bool 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
453template <typename ValueT,
454 typename CodecT,
455 typename FilterT,
456 typename PointDataTreeT,
457 typename std::enable_if<!ValueTraits<ValueT>::IsVec, int>::type = 0>
458bool 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
476template <typename ValueT,
477 typename CodecT,
478 typename FilterT,
479 typename PointDataTreeT>
480bool 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
492template <typename ValueT,
493 typename CodecT,
494 typename FilterT,
495 typename PointDataTreeT,
496 typename ResultTreeT>
497bool 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
528 static_assert(std::is_base_of<TreeBase, PointDataTreeT>::value,
529 "PointDataTreeT in instantiation of evalAverage is not an openvdb Tree type");
530 static_assert(std::is_constructible<ResultT, ValueT>::value,
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
603template <typename ValueT,
604 typename CodecT,
605 typename FilterT,
606 typename PointDataTreeT,
607 typename ResultTreeT>
608bool 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
617 static_assert(std::is_base_of<TreeBase, PointDataTreeT>::value,
618 "PointDataTreeT in instantiation of accumulate is not an openvdb Tree type");
619 static_assert(std::is_constructible<ResultT, ValueT>::value,
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
660 if (std::is_integral<ElementT>::value) {
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
692template <typename ValueT,
693 typename CodecT,
694 typename FilterT,
695 typename PointDataTreeT>
696std::pair<ValueT, ValueT>
697evalMinMax(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
709template <typename ValueT,
710 typename CodecT,
711 typename FilterT,
712 typename PointDataTreeT>
714evalAverage(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
724template <typename ValueT,
725 typename CodecT,
726 typename FilterT,
727 typename PointDataTreeT>
729accumulate(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
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:25
Definition AttributeArray.h:836
Index size() const
Definition AttributeArray.h:858
ValueType get(Index n, Index m=0) const
Definition AttributeArray.h:2193
bool isUniform() const
Definition AttributeArray.h:2219
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:85
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition LeafManager.h:318
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
size_t leafCount() const
Return the number of leaf nodes.
Definition LeafManager.h:287
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition LeafManager.h:345
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)
Definition PointStatistics.h:338
PromoteType< ValueT >::Highest accumulate(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Evaluates the total value of a point attribute.
Definition PointStatistics.h:729
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.
Definition PointStatistics.h:697
ConvertElementType< ValueT, double >::Type evalAverage(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Evaluates the average value of a point attribute.
Definition PointStatistics.h:714
Index32 Index
Definition Types.h:54
Definition Exceptions.h:13
SubT Type
Definition Types.h:281
typename TypeT< 64ul >::type Highest
Definition Types.h:332
typename T::ValueType ElementType
Definition Types.h:263
Vector component-wise op to evaluate the min/max of vector components and return the result as a vect...
Definition PointStatistics.h:314
void operator()(const ExtentT &b)
Definition PointStatistics.h:324
ExtentT mMinMax
Definition PointStatistics.h:330
ComponentExtent(const ExtentT &init)
Definition PointStatistics.h:317
ComponentExtent(const VecT &init)
Definition PointStatistics.h:316
void operator()(const VecT &b)
Definition PointStatistics.h:319
const ExtentT & get() const
Definition PointStatistics.h:318
std::pair< VecT, VecT > ExtentT
Definition PointStatistics.h:315
MagnitudeExtent(const ExtentT &init)
Definition PointStatistics.h:273
void operator()(const ExtentT &b)
Definition PointStatistics.h:291
typename ValueTraits< VecT >::ElementType ElementT
Definition PointStatistics.h:266
MagnitudeExtent(const VecT &init)
Definition PointStatistics.h:268
std::pair< ElementT, ElementT > mLengths
Definition PointStatistics.h:305
void operator()(const VecT &b)
Definition PointStatistics.h:279
const ExtentT & get() const
Definition PointStatistics.h:278
std::pair< VecT, VecT > ExtentT
Definition PointStatistics.h:267
Vector squared magnitude op to evaluate the min/max of a vector attribute and return the result as a ...
Definition PointStatistics.h:251
MagnitudeExtent(const ExtentT &init)
Definition PointStatistics.h:256
typename ScalarMinMax< ElementT >::ExtentT ExtentT
Definition PointStatistics.h:253
void operator()(const ExtentT &b)
Definition PointStatistics.h:258
typename ValueTraits< VecT >::ElementType ElementT
Definition PointStatistics.h:252
MagnitudeExtent(const VecT &init)
Definition PointStatistics.h:255
void operator()(const VecT &b)
Definition PointStatistics.h:257
Scalar extent op to evaluate the min/max values of a single integral or floating point attribute type...
Definition PointStatistics.h:227
ScalarMinMax(const ExtentT &init)
Definition PointStatistics.h:230
std::pair< ValueT, ValueT > ExtentT
Definition PointStatistics.h:228
void operator()(const ExtentT &b)
Definition PointStatistics.h:236
void operator()(const ValueT &b)
Definition PointStatistics.h:231
ScalarMinMax(const ValueT &init)
Definition PointStatistics.h:229
ExtentT mMinMax
Definition PointStatistics.h:242
const ExtentT & get() const
Definition PointStatistics.h:241
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:212