Line | Branch | Exec | Source |
---|---|---|---|
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> | ||
22 | #include <openvdb/tree/LeafManager.h> | ||
23 | |||
24 | #include <tbb/parallel_reduce.h> | ||
25 | #include <tbb/parallel_for.h> | ||
26 | |||
27 | namespace openvdb { | ||
28 | OPENVDB_USE_VERSION_NAMESPACE | ||
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> | ||
74 | typename ConvertElementType<ValueT, double>::Type | ||
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, | ||
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 | ||
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> | ||
226 | struct ScalarMinMax | ||
227 | { | ||
228 | using ExtentT = std::pair<ValueT, ValueT>; | ||
229 | ScalarMinMax(const ValueT& init) : mMinMax(init, init) {} | ||
230 | 13 | ScalarMinMax(const ExtentT& init) : mMinMax(init) {} | |
231 | inline void operator()(const ValueT& b) | ||
232 | { | ||
233 |
5/10✓ Branch 0 taken 44 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
59 | mMinMax.first = std::min(mMinMax.first, b); |
234 | 59 | mMinMax.second = std::max(mMinMax.second, b); | |
235 | } | ||
236 | inline void operator()(const ExtentT& b) | ||
237 | { | ||
238 |
11/20✓ Branch 0 taken 9 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 5 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
82 | mMinMax.first = std::min(mMinMax.first, b.first); |
239 |
5/10✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
20 | mMinMax.second = std::max(mMinMax.second, b.second); |
240 | 69 | } | |
241 | inline const ExtentT& get() const { return mMinMax; } | ||
242 | ExtentT 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> | ||
249 | struct MagnitudeExtent | ||
250 | : public ScalarMinMax<typename ValueTraits<VecT>::ElementType> | ||
251 | { | ||
252 | using ElementT = typename ValueTraits<VecT>::ElementType; | ||
253 | using ExtentT = typename ScalarMinMax<ElementT>::ExtentT; | ||
254 | using BaseT = ScalarMinMax<ElementT>; | ||
255 | MagnitudeExtent(const VecT& init) : BaseT(init.lengthSqr()) {} | ||
256 | MagnitudeExtent(const ExtentT& init) : BaseT(init) {} | ||
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | 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 | { | ||
266 | using ElementT = typename ValueTraits<VecT>::ElementType; | ||
267 | using ExtentT = std::pair<VecT, VecT>; | ||
268 | MagnitudeExtent(const VecT& init) | ||
269 | : mLengths(), mMinMax(init, init) { | ||
270 | 1 | mLengths.first = init.lengthSqr(); | |
271 | 1 | mLengths.second = mLengths.first; | |
272 | } | ||
273 | ✗ | MagnitudeExtent(const ExtentT& init) | |
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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (l < mLengths.first) { |
283 | ✗ | mLengths.first = l; | |
284 | ✗ | mMinMax.first = b; | |
285 | } | ||
286 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
|
7 | else if (l > mLengths.second) { |
287 | 2 | mLengths.second = l; | |
288 | 2 | 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; | ||
306 | ExtentT mMinMax; | ||
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> | ||
313 | struct ComponentExtent | ||
314 | { | ||
315 | using ExtentT = std::pair<VecT, VecT>; | ||
316 | ComponentExtent(const VecT& init) : mMinMax(init, init) {} | ||
317 | 3 | 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 | 17 | inline void operator()(const ExtentT& b) | |
325 | { | ||
326 | 17 | mMinMax.first = math::minComponent(mMinMax.first, b.first); | |
327 | 17 | mMinMax.second = math::maxComponent(mMinMax.second, b.second); | |
328 | 17 | } | |
329 | |||
330 | ExtentT mMinMax; | ||
331 | }; | ||
332 | |||
333 | template <typename ValueT, | ||
334 | typename CodecT, | ||
335 | typename FilterT, | ||
336 | typename ExtentOp, | ||
337 | typename PointDataTreeT> | ||
338 | 94 | 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 | { | ||
347 | static_assert(std::is_base_of<TreeBase, PointDataTreeT>::value, | ||
348 | "PointDataTreeT in instantiation of evalExtents is not an openvdb Tree type"); | ||
349 | |||
350 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
25 | struct ResultType { |
351 | typename ExtentOp::ExtentT ext; | ||
352 | bool data = false; | ||
353 | }; | ||
354 | |||
355 | 188 | tree::LeafManager<const PointDataTreeT> manager(points); | |
356 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 6 times.
|
94 | if (manager.leafCount() == 0) return false; |
357 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
82 | const size_t idx = manager.leaf(0).attributeSet().find(attribute); |
358 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 1 times.
|
82 | if (idx == AttributeSet::INVALID_POS) return false; |
359 | |||
360 | // track results per leaf for min/max trees | ||
361 | 78 | std::vector<std::unique_ptr<typename ExtentOp::ExtentT>> values; | |
362 |
3/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
|
80 | if (minTree || maxTree) values.resize(manager.leafCount()); |
363 | |||
364 |
2/2✓ Branch 1 taken 39 times.
✓ Branch 2 taken 1 times.
|
90 | const ResultType result = tbb::parallel_reduce(manager.leafRange(), |
365 | ResultType(), | ||
366 | 367 | [idx, &filter, &values] | |
367 | (const auto& range, ResultType in) -> ResultType | ||
368 | { | ||
369 |
14/18✓ Branch 1 taken 62 times.
✓ Branch 2 taken 62 times.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 25 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 13 taken 34 times.
✓ Branch 14 taken 33 times.
✓ Branch 16 taken 16 times.
✓ Branch 17 taken 16 times.
✓ Branch 19 taken 27 times.
✓ Branch 20 taken 27 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 25 taken 8 times.
✓ Branch 26 taken 8 times.
|
345 | for (auto leaf = range.begin(); leaf; ++leaf) { |
370 | 308 | AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx)); | |
371 |
7/18✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 33 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 16 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 27 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 8 times.
|
209 | if (handle.size() == 0) continue; |
372 | if (filter.state() == index::ALL) { | ||
373 |
12/24✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 55 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 21 taken 33 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✓ Branch 24 taken 32 times.
✓ Branch 26 taken 16 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 16 times.
|
113 | const size_t size = handle.isUniform() ? 1 : handle.size(); |
374 |
3/8✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 8 taken 33 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 16 times.
✗ Branch 12 not taken.
|
113 | ExtentOp op(handle.get(0)); |
375 |
9/12✓ Branch 0 taken 49 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 33 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 16 times.
|
183 | for (size_t i = 1; i < size; ++i) { |
376 |
4/12✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
70 | assert(i < size_t(std::numeric_limits<Index>::max())); |
377 |
4/14✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
133 | op(handle.get(Index(i))); |
378 | } | ||
379 |
7/12✓ Branch 0 taken 46 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 24 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 16 times.
|
113 | if (!values.empty()) { |
380 |
4/12✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 13 taken 9 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
57 | values[leaf.pos()].reset(new typename ExtentOp::ExtentT(op.get())); |
381 | } | ||
382 |
8/12✓ Branch 0 taken 37 times.
✓ Branch 1 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✓ Branch 11 taken 10 times.
✓ Branch 12 taken 12 times.
✓ Branch 13 taken 4 times.
|
113 | if (in.data) op(in.ext); |
383 | 113 | in.data = true; | |
384 | in.ext = op.get(); | ||
385 | } | ||
386 | else { | ||
387 | auto iter = leaf->beginIndexOn(filter); | ||
388 |
6/12✓ Branch 0 taken 33 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
59 | if (!iter) continue; |
389 |
2/6✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
22 | ExtentOp op(handle.get(*iter)); |
390 |
2/6✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
|
22 | ++iter; |
391 |
7/22✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 4 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
|
28 | for (; iter; ++iter) op(handle.get(*iter)); |
392 |
3/6✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
22 | if (!values.empty()) { |
393 |
1/6✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
6 | values[leaf.pos()].reset(new typename ExtentOp::ExtentT(op.get())); |
394 | } | ||
395 |
4/6✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
|
22 | if (in.data) op(in.ext); |
396 |
2/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
22 | in.data = true; |
397 | in.ext = op.get(); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | 172 | return in; | |
402 | }, | ||
403 | 18 | [](const ResultType& a, const ResultType& b) -> ResultType { | |
404 |
7/18✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
18 | if (!b.data) return a; |
405 |
5/18✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
16 | if (!a.data) return b; |
406 | 3 | ExtentOp op(a.ext); op(b.ext); | |
407 | 3 | ResultType t; | |
408 | t.ext = op.get(); | ||
409 | 16 | t.data = true; | |
410 | 16 | 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 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 13 times.
|
78 | if (minTree || maxTree) { |
418 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
129 | manager.foreach([minTree, maxTree, &values] |
419 | (const auto& leaf, const size_t idx) { | ||
420 | const auto& v = values[idx]; | ||
421 |
9/18✓ Branch 0 taken 5 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
|
75 | if (v == nullptr) return; |
422 | const Coord& origin = leaf.origin(); | ||
423 |
7/18✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 45 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 1 times.
✗ Branch 25 not taken.
|
63 | if (minTree) minTree->addTile(1, origin, v->first, true); |
424 |
7/18✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 45 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 1 times.
✗ Branch 25 not taken.
|
63 | if (maxTree) maxTree->addTile(1, origin, v->second, true); |
425 | }, false); | ||
426 | } | ||
427 | |||
428 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
|
78 | 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 | 6 | 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 | { | ||
445 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
|
36 | typename ComponentExtent<ValueT>::ExtentT ext; |
446 | const bool s = evalExtents<ValueT, CodecT, FilterT, | ||
447 | ComponentExtent<ValueT>, PointDataTreeT> | ||
448 | 6 | (points, attribute, ext, filter, minTree, maxTree); | |
449 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | if (s) min = ext.first, max = ext.second; |
450 | 6 | 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 | 82 | 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 | 82 | typename ScalarMinMax<ValueT>::ExtentT ext; | |
467 | const bool s = evalExtents<ValueT, CodecT, FilterT, | ||
468 | ScalarMinMax<ValueT>, PointDataTreeT> | ||
469 | 82 | (points, attribute, ext, filter, minTree, maxTree); | |
470 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
|
80 | if (s) min = ext.first, max = ext.second; |
471 | 80 | return s; | |
472 | } | ||
473 | |||
474 | } // namespace statistics_internal | ||
475 | |||
476 | template <typename ValueT, | ||
477 | typename CodecT, | ||
478 | typename FilterT, | ||
479 | typename PointDataTreeT> | ||
480 | 60 | 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 | 60 | (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 | 46 | bool evalAverage(const PointDataTreeT& points, | |
498 | const std::string& attribute, | ||
499 | typename ConvertElementType<ValueT, double>::Type& average, | ||
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 | 40 | Sample(const ResultT& _avg, size_t _size) : avg(_avg), size(_size) {} | |
508 | |||
509 | 11 | void add(const ResultT& val) | |
510 | { | ||
511 | 54 | ++size; | |
512 | 43 | const ResultT delta = val - avg; | |
513 | 54 | avg = avg + (delta / static_cast<double>(size)); | |
514 | } | ||
515 | |||
516 | 24 | void add(const Sample& other) | |
517 | { | ||
518 | 24 | assert(other.size > 0); | |
519 | 24 | const double denom = 1.0 / static_cast<double>(size + other.size); | |
520 | 18 | const ResultT delta = other.avg - avg; | |
521 | 24 | avg = avg + (denom * delta * static_cast<double>(other.size)); | |
522 | 24 | 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 | |||
533 | 92 | tree::LeafManager<const PointDataTreeT> manager(points); | |
534 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
|
46 | if (manager.leafCount() == 0) return false; |
535 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
42 | const size_t idx = manager.leaf(0).attributeSet().find(attribute); |
536 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1 times.
|
42 | if (idx == AttributeSet::INVALID_POS) return false; |
537 | |||
538 | 38 | std::vector<std::unique_ptr<Sample>> values; | |
539 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
40 | values.resize(manager.leafCount()); |
540 |
2/2✓ Branch 1 taken 19 times.
✓ Branch 2 taken 1 times.
|
40 | tbb::parallel_for(manager.leafRange(), |
541 | 149 | [idx, &filter, &values] (const auto& range) { | |
542 |
12/12✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 13 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 6 times.
✓ Branch 10 taken 9 times.
✓ Branch 11 taken 9 times.
✓ Branch 13 taken 6 times.
✓ Branch 14 taken 6 times.
✓ Branch 16 taken 3 times.
✓ Branch 17 taken 3 times.
|
91 | for (auto leaf = range.begin(); leaf; ++leaf) { |
543 | 86 | AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx)); | |
544 | 45 | size_t size = handle.size(); | |
545 |
6/12✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 6 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
|
50 | if (size == 0) continue; |
546 | if (filter.state() == index::ALL) { | ||
547 |
6/12✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 6 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
|
27 | std::unique_ptr<Sample> S(new Sample(ResultT(handle.get(0)), 1)); |
548 |
9/12✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 5 times.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 8 times.
✓ Branch 11 taken 6 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 4 times.
|
27 | if (handle.isUniform()) { |
549 | 2 | S->avg = S->avg / static_cast<double>(size); | |
550 | 10 | S->size = size; | |
551 | } | ||
552 | else { | ||
553 |
6/6✓ Branch 0 taken 17 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 4 times.
|
64 | for (size_t i = 1; i < size; ++i) { |
554 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
|
47 | assert(i < size_t(std::numeric_limits<Index>::max())); |
555 |
3/6✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
|
47 | 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 |
7/12✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
18 | if (!iter) continue; |
563 |
6/14✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
|
13 | std::unique_ptr<Sample> S(new Sample(ResultT(handle.get(*iter)), 1)); |
564 |
3/6✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
|
13 | ++iter; |
565 |
6/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
|
20 | for (; iter; ++iter, ++size) { |
566 |
6/12✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
|
7 | S->add(ResultT(handle.get(*iter))); |
567 | } | ||
568 | values[leaf.pos()] = std::move(S); | ||
569 | } | ||
570 | } | ||
571 | }); | ||
572 | |||
573 | 38 | auto iter = values.cbegin(); | |
574 |
4/4✓ Branch 0 taken 21 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 16 times.
|
48 | while (iter != values.cend() && !(*iter)) ++iter; |
575 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 3 times.
|
38 | if (iter == values.cend()) return false; |
576 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
32 | assert(*iter); |
577 | |||
578 | // serial deterministic reduction of floating point samples | ||
579 | 32 | Sample S = **iter; | |
580 | ++iter; | ||
581 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 16 times.
|
80 | for (; iter != values.cend(); ++iter) { |
582 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
48 | if (*iter) S.add(**iter); |
583 | } | ||
584 | 32 | 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 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
|
32 | if (averageTree) { |
591 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
13 | manager.foreach([averageTree, &values] |
592 | (const auto& leaf, const size_t idx) { | ||
593 | const auto& S = values[idx]; | ||
594 |
3/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
5 | if (S == nullptr) return; |
595 | const Coord& origin = leaf.origin(); | ||
596 | 5 | 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 | 46 | 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 | |||
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 | |||
622 | 92 | tree::LeafManager<const PointDataTreeT> manager(points); | |
623 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
|
46 | if (manager.leafCount() == 0) return false; |
624 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
42 | const size_t idx = manager.leaf(0).attributeSet().find(attribute); |
625 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 2 times.
|
42 | if (idx == AttributeSet::INVALID_POS) return false; |
626 | |||
627 | 36 | std::vector<std::unique_ptr<ResultT>> values; | |
628 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
38 | values.resize(manager.leafCount()); |
629 |
2/2✓ Branch 1 taken 18 times.
✓ Branch 2 taken 1 times.
|
38 | tbb::parallel_for(manager.leafRange(), |
630 | 387 | [idx, &filter, &values](const auto& range) { | |
631 |
12/12✓ Branch 1 taken 17 times.
✓ Branch 2 taken 17 times.
✓ Branch 4 taken 49 times.
✓ Branch 5 taken 48 times.
✓ Branch 7 taken 16 times.
✓ Branch 8 taken 16 times.
✓ Branch 10 taken 24 times.
✓ Branch 11 taken 24 times.
✓ Branch 13 taken 10 times.
✓ Branch 14 taken 10 times.
✓ Branch 16 taken 8 times.
✓ Branch 17 taken 8 times.
|
247 | for (auto leaf = range.begin(); leaf; ++leaf) { |
632 | 222 | AttributeHandle<ValueT, CodecT> handle(leaf->constAttributeArray(idx)); | |
633 |
6/12✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 24 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 10 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 8 times.
|
148 | if (handle.size() == 0) continue; |
634 | if (filter.state() == index::ALL) { | ||
635 |
7/12✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 16 times.
✓ Branch 6 taken 48 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 48 times.
✓ Branch 11 taken 16 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 16 times.
|
81 | const size_t size = handle.isUniform() ? 1 : handle.size(); |
636 |
3/6✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
|
81 | auto total = ResultT(handle.get(0)); |
637 |
4/6✓ Branch 0 taken 7 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
|
88 | for (size_t i = 1; i < size; ++i) { |
638 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
7 | assert(i < size_t(std::numeric_limits<Index>::max())); |
639 |
1/6✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
7 | total += ResultT(handle.get(Index(i))); |
640 | } | ||
641 |
3/6✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
|
81 | values[leaf.pos()].reset(new ResultT(total)); |
642 | } | ||
643 | else { | ||
644 | auto iter = leaf->beginIndexOn(filter); | ||
645 |
9/12✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
42 | if (!iter) continue; |
646 |
3/6✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
17 | auto total = ResultT(handle.get(*iter)); |
647 |
3/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
|
17 | ++iter; |
648 |
6/18✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 5 times.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 4 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
|
20 | for (; iter; ++iter) total += ResultT(handle.get(*iter)); |
649 |
3/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
|
17 | values[leaf.pos()].reset(new ResultT(total)); |
650 | } | ||
651 | } | ||
652 | }); | ||
653 | |||
654 | 36 | auto iter = values.cbegin(); | |
655 |
4/4✓ Branch 0 taken 29 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 16 times.
|
62 | while (iter != values.cend() && !(*iter)) ++iter; |
656 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
|
36 | if (iter == values.cend()) return false; |
657 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
32 | assert(*iter); |
658 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
32 | 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 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | total = tbb::parallel_reduce(RangeT(&(*iter), (&values.back())+1, 32), total, |
664 | [](const RangeT& range, ResultT p) -> ResultT { | ||
665 |
7/16✓ Branch 0 taken 42 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 6 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
62 | for (const auto& r : range) if (r) p += *r; |
666 | return p; | ||
667 | }, std::plus<ResultT>()); | ||
668 | } | ||
669 | else { | ||
670 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 8 times.
|
96 | for (; iter != values.cend(); ++iter) { |
671 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 6 times.
|
80 | 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 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
|
32 | if (totalTree) { |
680 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
18 | manager.foreach([totalTree, &values] |
681 | (const auto& leaf, const size_t idx) { | ||
682 | const auto& v = values[idx]; | ||
683 |
3/12✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
10 | 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 | 10 | evalMinMax(const PointDataTreeT& points, | |
698 | const std::string& attribute, | ||
699 | const FilterT& filter) | ||
700 | { | ||
701 | std::pair<ValueT, ValueT> results { | ||
702 | 2 | zeroVal<ValueT>(), zeroVal<ValueT>() | |
703 | }; | ||
704 | evalMinMax<ValueT, CodecT, FilterT, PointDataTreeT> | ||
705 | 10 | (points, attribute, results.first, results.second, filter); | |
706 | 10 | return results; | |
707 | } | ||
708 | |||
709 | template <typename ValueT, | ||
710 | typename CodecT, | ||
711 | typename FilterT, | ||
712 | typename PointDataTreeT> | ||
713 | typename ConvertElementType<ValueT, double>::Type | ||
714 | 10 | evalAverage(const PointDataTreeT& points, | |
715 | const std::string& attribute, | ||
716 | const FilterT& filter) | ||
717 | { | ||
718 | using ConvertedT = typename ConvertElementType<ValueT, double>::Type; | ||
719 | 8 | ConvertedT result = zeroVal<ConvertedT>(); | |
720 | 10 | evalAverage<ValueT, CodecT, FilterT, PointDataTreeT>(points, attribute, result, filter); | |
721 | 10 | return result; | |
722 | } | ||
723 | |||
724 | template <typename ValueT, | ||
725 | typename CodecT, | ||
726 | typename FilterT, | ||
727 | typename PointDataTreeT> | ||
728 | typename PromoteType<ValueT>::Highest | ||
729 | 5 | accumulate(const PointDataTreeT& points, | |
730 | const std::string& attribute, | ||
731 | const FilterT& filter) | ||
732 | { | ||
733 | using PromotedT = typename PromoteType<ValueT>::Highest; | ||
734 | 4 | PromotedT result = zeroVal<PromotedT>(); | |
735 | 5 | accumulate<ValueT, CodecT, FilterT, PointDataTreeT>(points, attribute, result, filter); | |
736 | 5 | return result; | |
737 | } | ||
738 | |||
739 | } // namespace points | ||
740 | } // namespace OPENVDB_VERSION_NAME | ||
741 | } // namespace openvdb | ||
742 | |||
743 | #endif // OPENVDB_POINTS_STATISTICS_HAS_BEEN_INCLUDED | ||
744 |