| 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 |