9#ifndef OPENVDB_POINTS_STATISTICS_IMPL_HAS_BEEN_INCLUDED
10#define OPENVDB_POINTS_STATISTICS_IMPL_HAS_BEEN_INCLUDED
19namespace statistics_internal
24template <
typename ValueT>
27 using ExtentT = std::pair<ValueT, ValueT>;
28 ScalarMinMax(
const ValueT& init) : mMinMax(init, init) {}
29 ScalarMinMax(
const ExtentT& init) : mMinMax(init) {}
30 inline void operator()(
const ValueT& b)
32 mMinMax.first = std::min(mMinMax.first, b);
33 mMinMax.second = std::max(mMinMax.second, b);
35 inline void operator()(
const ExtentT& b)
37 mMinMax.first = std::min(mMinMax.first, b.first);
38 mMinMax.second = std::max(mMinMax.second, b.second);
40 inline const ExtentT& get()
const {
return mMinMax; }
47template <
typename VecT,
bool MagResult = true>
49 :
public ScalarMinMax<typename ValueTraits<VecT>::ElementType>
51 using ElementT =
typename ValueTraits<VecT>::ElementType;
52 using ExtentT =
typename ScalarMinMax<ElementT>::ExtentT;
53 using BaseT = ScalarMinMax<ElementT>;
54 MagnitudeExtent(
const VecT& init) : BaseT(init.lengthSqr()) {}
55 MagnitudeExtent(
const ExtentT& init) : BaseT(init) {}
56 inline void operator()(
const VecT& b) { this->BaseT::operator()(b.lengthSqr()); }
57 inline void operator()(
const ExtentT& b) { this->BaseT::operator()(b); }
62template <
typename VecT>
63struct MagnitudeExtent<VecT, false>
65 using ElementT =
typename ValueTraits<VecT>::ElementType;
66 using ExtentT = std::pair<VecT, VecT>;
67 MagnitudeExtent(
const VecT& init)
68 : mLengths(), mMinMax(init, init) {
69 mLengths.first = init.lengthSqr();
70 mLengths.second = mLengths.first;
72 MagnitudeExtent(
const ExtentT& init)
73 : mLengths(), mMinMax(init) {
74 mLengths.first = init.first.lengthSqr();
75 mLengths.second = init.second.lengthSqr();
77 inline const ExtentT& get()
const {
return mMinMax; }
78 inline void operator()(
const VecT& b)
80 const ElementT l = b.lengthSqr();
81 if (l < mLengths.first) {
85 else if (l > mLengths.second) {
90 inline void operator()(
const ExtentT& b)
92 ElementT l = b.first.lengthSqr();
93 if (l < mLengths.first) {
95 mMinMax.first = b.first;
97 l = b.second.lengthSqr();
98 if (l > mLengths.second) {
100 mMinMax.second = b.second;
104 std::pair<ElementT, ElementT> mLengths;
111template <
typename VecT>
112struct ComponentExtent
114 using ExtentT = std::pair<VecT, VecT>;
115 ComponentExtent(
const VecT& init) : mMinMax(init, init) {}
116 ComponentExtent(
const ExtentT& init) : mMinMax(init) {}
117 inline const ExtentT& get()
const {
return mMinMax; }
118 inline void operator()(
const VecT& b)
120 mMinMax.first = math::minComponent(mMinMax.first, b);
121 mMinMax.second = math::maxComponent(mMinMax.second, b);
123 inline void operator()(
const ExtentT& b)
125 mMinMax.first = math::minComponent(mMinMax.first, b.first);
126 mMinMax.second = math::maxComponent(mMinMax.second, b.second);
132template <
typename ValueT,
136 typename PointDataTreeT>
137bool evalExtents(
const PointDataTreeT& points,
138 const std::string& attribute,
139 typename ExtentOp::ExtentT& ext,
140 const FilterT& filter,
141 typename PointDataTreeT::template ValueConverter
142 <
typename ExtentOp::ExtentT::first_type>::Type*
const minTree =
nullptr,
143 typename PointDataTreeT::template ValueConverter
144 <
typename ExtentOp::ExtentT::second_type>::Type*
const maxTree =
nullptr)
146 static_assert(std::is_base_of<TreeBase, PointDataTreeT>::value,
147 "PointDataTreeT in instantiation of evalExtents is not an openvdb Tree type");
150 typename ExtentOp::ExtentT ext;
154 tree::LeafManager<const PointDataTreeT> manager(points);
155 if (manager.leafCount() == 0)
return false;
156 const size_t idx = manager.leaf(0).attributeSet().find(attribute);
157 if (idx == AttributeSet::INVALID_POS)
return false;
160 std::vector<std::unique_ptr<typename ExtentOp::ExtentT>> values;
161 if (minTree || maxTree) values.resize(manager.leafCount());
163 const ResultType result = tbb::parallel_reduce(manager.leafRange(),
165 [idx, &filter, &values]
166 (
const auto& range, ResultType in) -> ResultType
168 for (
auto leaf = range.begin(); leaf; ++leaf) {
169 AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx));
170 if (handle.size() == 0)
continue;
171 if (filter.state() == index::ALL) {
172 const size_t size = handle.isUniform() ? 1 : handle.size();
173 ExtentOp
op(handle.get(0));
174 for (
size_t i = 1; i < size; ++i) {
178 if (!values.empty()) {
179 values[leaf.pos()].reset(
new typename ExtentOp::ExtentT(
op.get()));
181 if (in.data)
op(in.ext);
186 auto iter = leaf->beginIndexOn(filter);
188 ExtentOp
op(handle.get(*iter));
190 for (; iter; ++iter)
op(handle.get(*iter));
191 if (!values.empty()) {
192 values[leaf.pos()].reset(
new typename ExtentOp::ExtentT(
op.get()));
194 if (in.data)
op(in.ext);
202 [](
const ResultType& a,
const ResultType& b) -> ResultType {
203 if (!b.data)
return a;
204 if (!a.data)
return b;
205 ExtentOp
op(a.ext);
op(b.ext);
216 if (minTree || maxTree) {
217 manager.foreach([minTree, maxTree, &values]
218 (
const auto& leaf,
const size_t idx) {
219 const auto& v = values[idx];
220 if (v ==
nullptr)
return;
221 const Coord& origin = leaf.origin();
222 if (minTree) minTree->addTile(1, origin, v->first,
true);
223 if (maxTree) maxTree->addTile(1, origin, v->second,
true);
227 if (result.data) ext = result.ext;
231template <
typename ValueT,
234 typename PointDataTreeT,
235 typename std::enable_if<ValueTraits<ValueT>::IsVec,
int>::type = 0>
236bool evalExtents(
const PointDataTreeT& points,
237 const std::string& attribute,
240 const FilterT& filter,
241 typename PointDataTreeT::template ValueConverter<ValueT>::Type* minTree,
242 typename PointDataTreeT::template ValueConverter<ValueT>::Type* maxTree)
244 typename ComponentExtent<ValueT>::ExtentT ext;
245 const bool s = evalExtents<ValueT, CodecT, FilterT,
246 ComponentExtent<ValueT>, PointDataTreeT>
247 (points, attribute, ext, filter, minTree, maxTree);
248 if (s)
min = ext.first,
max = ext.second;
252template <
typename ValueT,
255 typename PointDataTreeT,
256 typename std::enable_if<!ValueTraits<ValueT>::IsVec,
int>::type = 0>
257bool evalExtents(
const PointDataTreeT& points,
258 const std::string& attribute,
261 const FilterT& filter,
262 typename PointDataTreeT::template ValueConverter<ValueT>::Type* minTree,
263 typename PointDataTreeT::template ValueConverter<ValueT>::Type* maxTree)
265 typename ScalarMinMax<ValueT>::ExtentT ext;
266 const bool s = evalExtents<ValueT, CodecT, FilterT,
267 ScalarMinMax<ValueT>, PointDataTreeT>
268 (points, attribute, ext, filter, minTree, maxTree);
269 if (s)
min = ext.first,
max = ext.second;
277template <
typename ValueT,
280 typename PointDataTreeT>
282 const std::string& attribute,
285 const FilterT& filter,
286 typename PointDataTreeT::template ValueConverter<ValueT>::Type* minTree,
287 typename PointDataTreeT::template ValueConverter<ValueT>::Type* maxTree)
289 return statistics_internal::evalExtents<ValueT, CodecT, FilterT, PointDataTreeT>
290 (
points, attribute, min, max, filter, minTree, maxTree);
293template <
typename ValueT,
296 typename PointDataTreeT,
297 typename ResultTreeT>
299 const std::string& attribute,
301 const FilterT& filter,
302 typename PointDataTreeT::template ValueConverter<ResultTreeT>::Type* averageTree)
308 Sample(
const ResultT& _avg,
size_t _size) : avg(_avg), size(_size) {}
310 void add(
const ResultT& val)
313 const ResultT delta = val - avg;
314 avg = avg + (delta /
static_cast<double>(size));
317 void add(
const Sample& other)
320 const double denom = 1.0 /
static_cast<double>(size + other.size);
321 const ResultT delta = other.avg - avg;
322 avg = avg + (denom * delta *
static_cast<double>(other.size));
326 ResultT avg;
size_t size;
329 static_assert(std::is_base_of<TreeBase, PointDataTreeT>::value,
330 "PointDataTreeT in instantiation of evalAverage is not an openvdb Tree type");
331 static_assert(std::is_constructible<ResultT, ValueT>::value,
332 "Target value in points::evalAverage is not constructible from the source value type.");
335 if (manager.
leafCount() == 0)
return false;
336 const size_t idx = manager.
leaf(0).attributeSet().find(attribute);
339 std::vector<std::unique_ptr<Sample>> values;
342 [idx, &filter, &values] (
const auto& range) {
343 for (auto leaf = range.begin(); leaf; ++leaf) {
344 AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx));
345 size_t size = handle.size();
346 if (size == 0) continue;
347 if (filter.state() == index::ALL) {
348 std::unique_ptr<Sample> S(new Sample(ResultT(handle.get(0)), 1));
349 if (handle.isUniform()) {
350 S->avg = S->avg / static_cast<double>(size);
354 for (size_t i = 1; i < size; ++i) {
355 OPENVDB_ASSERT(i < size_t(std::numeric_limits<Index>::max()));
356 S->add(ResultT(handle.get(Index(i))));
359 values[leaf.pos()] = std::move(S);
362 auto iter = leaf->beginIndexOn(filter);
364 std::unique_ptr<Sample> S(new Sample(ResultT(handle.get(*iter)), 1));
366 for (; iter; ++iter, ++size) {
367 S->add(ResultT(handle.get(*iter)));
369 values[leaf.pos()] = std::move(S);
374 auto iter = values.cbegin();
375 while (iter != values.cend() && !(*iter)) ++iter;
376 if (iter == values.cend())
return false;
382 for (; iter != values.cend(); ++iter) {
383 if (*iter) S.add(**iter);
392 manager.foreach([averageTree, &values]
393 (
const auto& leaf,
const size_t idx) {
394 const auto& S = values[idx];
395 if (S ==
nullptr)
return;
396 const Coord& origin = leaf.origin();
397 averageTree->addTile(1, origin, S->avg,
true);
404template <
typename ValueT,
407 typename PointDataTreeT,
408 typename ResultTreeT>
410 const std::string& attribute,
412 const FilterT& filter,
413 typename PointDataTreeT::template ValueConverter<ResultTreeT>::Type* totalTree)
418 static_assert(std::is_base_of<TreeBase, PointDataTreeT>::value,
419 "PointDataTreeT in instantiation of accumulate is not an openvdb Tree type");
420 static_assert(std::is_constructible<ResultT, ValueT>::value,
421 "Target value in points::accumulate is not constructible from the source value type.");
424 if (manager.
leafCount() == 0)
return false;
425 const size_t idx = manager.
leaf(0).attributeSet().find(attribute);
428 std::vector<std::unique_ptr<ResultT>> values;
431 [idx, &filter, &values](
const auto& range) {
432 for (auto leaf = range.begin(); leaf; ++leaf) {
433 AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx));
434 if (handle.size() == 0) continue;
435 if (filter.state() == index::ALL) {
436 const size_t size = handle.isUniform() ? 1 : handle.size();
437 auto total = ResultT(handle.get(0));
438 for (size_t i = 1; i < size; ++i) {
439 OPENVDB_ASSERT(i < size_t(std::numeric_limits<Index>::max()));
440 total += ResultT(handle.get(Index(i)));
442 values[leaf.pos()].reset(new ResultT(total));
445 auto iter = leaf->beginIndexOn(filter);
447 auto total = ResultT(handle.get(*iter));
449 for (; iter; ++iter) total += ResultT(handle.get(*iter));
450 values[leaf.pos()].reset(new ResultT(total));
455 auto iter = values.cbegin();
456 while (iter != values.cend() && !(*iter)) ++iter;
457 if (iter == values.cend())
return false;
459 total = **iter; ++iter;
461 if (std::is_integral<ElementT>::value) {
462 using RangeT = tbb::blocked_range<const std::unique_ptr<ResultT>*>;
464 total = tbb::parallel_reduce(RangeT(&(*iter), (&values.back())+1, 32), total,
465 [](
const RangeT& range, ResultT p) -> ResultT {
466 for (const auto& r : range) if (r) p += *r;
468 }, std::plus<ResultT>());
471 for (; iter != values.cend(); ++iter) {
472 if (*iter) total += (**iter);
481 manager.foreach([totalTree, &values]
482 (
const auto& leaf,
const size_t idx) {
483 const auto& v = values[idx];
484 if (v ==
nullptr)
return;
485 const Coord& origin = leaf.origin();
486 totalTree->addTile(1, origin, *v,
true);
493template <
typename ValueT,
496 typename PointDataTreeT>
497std::pair<ValueT, ValueT>
499 const std::string& attribute,
500 const FilterT& filter)
502 std::pair<ValueT, ValueT> results {
506 (
points, attribute, results.first, results.second, filter);
510template <
typename ValueT,
513 typename PointDataTreeT>
516 const std::string& attribute,
517 const FilterT& filter)
525template <
typename ValueT,
528 typename PointDataTreeT>
531 const std::string& attribute,
532 const FilterT& filter)
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
@ INVALID_POS
Definition AttributeSet.h:42
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
LeafType & leaf(size_t leafIdx) const
Return a pointer to the leaf node at index leafIdx in the array.
Definition LeafManager.h:319
size_t leafCount() const
Return the number of leaf nodes.
Definition LeafManager.h:288
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition LeafManager.h:346
Definition AttributeArray.h:42
PromoteType< ValueT >::Highest accumulate(const PointDataTreeT &points, const std::string &attribute, const FilterT &filter=NullFilter())
Evaluates the total value of a point attribute.
Definition PointStatisticsImpl.h:530
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 PointStatisticsImpl.h:498
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 PointStatisticsImpl.h:515
Index32 Index
Definition Types.h:54
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
Definition Exceptions.h:13
SubT Type
Definition Types.h:320
typename T::ValueType ElementType
Definition Types.h:302
#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:218