| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright Contributors to the OpenVDB Project | ||
| 2 | // SPDX-License-Identifier: MPL-2.0 | ||
| 3 | // | ||
| 4 | /// @file ChangeBackground.h | ||
| 5 | /// | ||
| 6 | /// @brief Efficient multi-threaded replacement of the background | ||
| 7 | /// values in tree. | ||
| 8 | /// | ||
| 9 | /// @author Ken Museth | ||
| 10 | |||
| 11 | #ifndef OPENVDB_TOOLS_ChangeBACKGROUND_HAS_BEEN_INCLUDED | ||
| 12 | #define OPENVDB_TOOLS_ChangeBACKGROUND_HAS_BEEN_INCLUDED | ||
| 13 | |||
| 14 | #include <openvdb/math/Math.h> // for isNegative and negative | ||
| 15 | #include <openvdb/Types.h> // for Index typedef | ||
| 16 | #include <openvdb/tree/NodeManager.h> | ||
| 17 | #include <openvdb/openvdb.h> | ||
| 18 | |||
| 19 | |||
| 20 | namespace openvdb { | ||
| 21 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 22 | namespace OPENVDB_VERSION_NAME { | ||
| 23 | namespace tools { | ||
| 24 | |||
| 25 | /// @brief Replace the background value in all the nodes of a tree. | ||
| 26 | /// @details The sign of the background value is preserved, and only | ||
| 27 | /// inactive values equal to the old background value are replaced. | ||
| 28 | /// | ||
| 29 | /// @note If a LeafManager is used the cached leaf nodes are reused, | ||
| 30 | /// resulting in slightly better overall performance. | ||
| 31 | /// | ||
| 32 | /// @param tree Tree (or LeafManager) that will have its background value changed | ||
| 33 | /// @param background the new background value | ||
| 34 | /// @param threaded enable or disable threading (threading is enabled by default) | ||
| 35 | /// @param grainSize used to control the threading granularity (default is 32) | ||
| 36 | template<typename TreeOrLeafManagerT> | ||
| 37 | void | ||
| 38 | changeBackground( | ||
| 39 | TreeOrLeafManagerT& tree, | ||
| 40 | const typename TreeOrLeafManagerT::ValueType& background, | ||
| 41 | bool threaded = true, | ||
| 42 | size_t grainSize = 32); | ||
| 43 | |||
| 44 | |||
| 45 | /// @brief Replace the background value in all the nodes of a floating-point tree | ||
| 46 | /// containing a symmetric narrow-band level set. | ||
| 47 | /// @details All inactive values will be set to +| @a halfWidth | if outside | ||
| 48 | /// and -| @a halfWidth | if inside, where @a halfWidth is half the width | ||
| 49 | /// of the symmetric narrow band. | ||
| 50 | /// | ||
| 51 | /// @note This method is faster than changeBackground since it does not | ||
| 52 | /// perform tests to see if inactive values are equal to the old background value. | ||
| 53 | /// @note If a LeafManager is used the cached leaf nodes are reused, | ||
| 54 | /// resulting in slightly better overall performance. | ||
| 55 | /// | ||
| 56 | /// @param tree Tree (or LeafManager) that will have its background value changed | ||
| 57 | /// @param halfWidth half of the width of the symmetric narrow band | ||
| 58 | /// @param threaded enable or disable threading (threading is enabled by default) | ||
| 59 | /// @param grainSize used to control the threading granularity (default is 32) | ||
| 60 | /// | ||
| 61 | /// @throw ValueError if @a halfWidth is negative (as defined by math::isNegative) | ||
| 62 | template<typename TreeOrLeafManagerT> | ||
| 63 | void | ||
| 64 | changeLevelSetBackground( | ||
| 65 | TreeOrLeafManagerT& tree, | ||
| 66 | const typename TreeOrLeafManagerT::ValueType& halfWidth, | ||
| 67 | bool threaded = true, | ||
| 68 | size_t grainSize = 32); | ||
| 69 | |||
| 70 | |||
| 71 | /// @brief Replace the background values in all the nodes of a floating-point tree | ||
| 72 | /// containing a possibly asymmetric narrow-band level set. | ||
| 73 | /// @details All inactive values will be set to +| @a outsideWidth | if outside | ||
| 74 | /// and -| @a insideWidth | if inside, where @a outsideWidth is the outside | ||
| 75 | /// width of the narrow band and @a insideWidth is its inside width. | ||
| 76 | /// | ||
| 77 | /// @note This method is faster than changeBackground since it does not | ||
| 78 | /// perform tests to see if inactive values are equal to the old background value. | ||
| 79 | /// @note If a LeafManager is used the cached leaf nodes are reused, | ||
| 80 | /// resulting in slightly better overall performance. | ||
| 81 | /// | ||
| 82 | /// @param tree Tree (or LeafManager) that will have its background value changed | ||
| 83 | /// @param outsideWidth The width of the outside of the narrow band | ||
| 84 | /// @param insideWidth The width of the inside of the narrow band | ||
| 85 | /// @param threaded enable or disable threading (threading is enabled by default) | ||
| 86 | /// @param grainSize used to control the threading granularity (default is 32) | ||
| 87 | /// | ||
| 88 | /// @throw ValueError if @a outsideWidth is negative or @a insideWidth is | ||
| 89 | /// not negative (as defined by math::isNegative) | ||
| 90 | template<typename TreeOrLeafManagerT> | ||
| 91 | void | ||
| 92 | changeAsymmetricLevelSetBackground( | ||
| 93 | TreeOrLeafManagerT& tree, | ||
| 94 | const typename TreeOrLeafManagerT::ValueType& outsideWidth, | ||
| 95 | const typename TreeOrLeafManagerT::ValueType& insideWidth, | ||
| 96 | bool threaded = true, | ||
| 97 | size_t grainSize = 32); | ||
| 98 | |||
| 99 | |||
| 100 | ////////////////////////////////////////////////////// | ||
| 101 | |||
| 102 | |||
| 103 | // Replaces the background value in a Tree of any type. | ||
| 104 | template<typename TreeOrLeafManagerT> | ||
| 105 | class ChangeBackgroundOp | ||
| 106 | { | ||
| 107 | public: | ||
| 108 | typedef typename TreeOrLeafManagerT::ValueType ValueT; | ||
| 109 | typedef typename TreeOrLeafManagerT::RootNodeType RootT; | ||
| 110 | typedef typename TreeOrLeafManagerT::LeafNodeType LeafT; | ||
| 111 | |||
| 112 | |||
| 113 | ✗ | ChangeBackgroundOp(const TreeOrLeafManagerT& tree, const ValueT& newValue) | |
| 114 | : mOldValue(tree.root().background()) | ||
| 115 | 74 | , mNewValue(newValue) | |
| 116 | { | ||
| 117 | } | ||
| 118 | 148 | void operator()(RootT& root) const | |
| 119 | { | ||
| 120 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
|
296 | for (typename RootT::ValueOffIter it = root.beginValueOff(); it; ++it) this->set(it); |
| 121 | 148 | root.setBackground(mNewValue, false); | |
| 122 | } | ||
| 123 | 366 | void operator()(LeafT& node) const | |
| 124 | { | ||
| 125 |
2/2✓ Branch 0 taken 56659 times.
✓ Branch 1 taken 183 times.
|
113684 | for (typename LeafT::ValueOffIter it = node.beginValueOff(); it; ++it) this->set(it); |
| 126 | } | ||
| 127 | template<typename NodeT> | ||
| 128 | 4 | void operator()(NodeT& node) const | |
| 129 | { | ||
| 130 | 4 | typename NodeT::NodeMaskType mask = node.getValueOffMask(); | |
| 131 |
2/2✓ Branch 1 taken 36680 times.
✓ Branch 2 taken 2 times.
|
73368 | for (typename NodeT::ValueOnIter it(mask.beginOn(), &node); it; ++it) this->set(it); |
| 132 | } | ||
| 133 | private: | ||
| 134 | |||
| 135 | template<typename IterT> | ||
| 136 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
186678 | inline void set(IterT& iter) const |
| 137 | { | ||
| 138 |
3/3✓ Branch 0 taken 36673 times.
✓ Branch 1 taken 45934 times.
✓ Branch 2 taken 10732 times.
|
186678 | if (math::isApproxEqual(*iter, mOldValue)) { |
| 139 | 91854 | iter.setValue(mNewValue); | |
| 140 |
1/3✓ Branch 0 taken 10739 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
21478 | } else if (math::isApproxEqual(*iter, math::negative(mOldValue))) { |
| 141 | 21464 | iter.setValue(math::negative(mNewValue)); | |
| 142 | } | ||
| 143 | } | ||
| 144 | const ValueT mOldValue, mNewValue; | ||
| 145 | };// ChangeBackgroundOp | ||
| 146 | |||
| 147 | |||
| 148 | // Replaces the background value in a Tree assumed to represent a | ||
| 149 | // level set. It is generally faster than ChangeBackgroundOp. | ||
| 150 | // Note that is follows the sign-convention that outside is positive | ||
| 151 | // and inside is negative! | ||
| 152 | template<typename TreeOrLeafManagerT> | ||
| 153 | class ChangeLevelSetBackgroundOp | ||
| 154 | { | ||
| 155 | public: | ||
| 156 | typedef typename TreeOrLeafManagerT::ValueType ValueT; | ||
| 157 | typedef typename TreeOrLeafManagerT::RootNodeType RootT; | ||
| 158 | typedef typename TreeOrLeafManagerT::LeafNodeType LeafT; | ||
| 159 | |||
| 160 | /// @brief Constructor for asymmetric narrow-bands | ||
| 161 | 28 | ChangeLevelSetBackgroundOp(const ValueT& outside, const ValueT& inside) | |
| 162 | : mOutside(outside) | ||
| 163 | 28 | , mInside(inside) | |
| 164 | { | ||
| 165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
28 | if (math::isNegative(mOutside)) { |
| 166 | ✗ | OPENVDB_THROW(ValueError, | |
| 167 | "ChangeLevelSetBackgroundOp: the outside value cannot be negative!"); | ||
| 168 | } | ||
| 169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
28 | if (!math::isNegative(mInside)) { |
| 170 | ✗ | OPENVDB_THROW(ValueError, | |
| 171 | "ChangeLevelSetBackgroundOp: the inside value must be negative!"); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | 28 | void operator()(RootT& root) const | |
| 175 | { | ||
| 176 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
|
56 | for (typename RootT::ValueOffIter it = root.beginValueOff(); it; ++it) this->set(it); |
| 177 | 28 | root.setBackground(mOutside, false); | |
| 178 | } | ||
| 179 | 52576 | void operator()(LeafT& node) const | |
| 180 | { | ||
| 181 |
2/2✓ Branch 0 taken 6798795 times.
✓ Branch 1 taken 26288 times.
|
13650166 | for(typename LeafT::ValueOffIter it = node.beginValueOff(); it; ++it) this->set(it); |
| 182 | } | ||
| 183 | template<typename NodeT> | ||
| 184 | 392 | void operator()(NodeT& node) const | |
| 185 | { | ||
| 186 | typedef typename NodeT::ValueOffIter IterT; | ||
| 187 |
2/2✓ Branch 1 taken 3586286 times.
✓ Branch 2 taken 196 times.
|
7173356 | for (IterT it(node.getChildMask().beginOff(), &node); it; ++it) this->set(it); |
| 188 | } | ||
| 189 | private: | ||
| 190 | |||
| 191 | template<typename IterT> | ||
| 192 | inline void set(IterT& iter) const | ||
| 193 | { | ||
| 194 | //this is safe since we know ValueType is_floating_point | ||
| 195 | ValueT& v = const_cast<ValueT&>(*iter); | ||
| 196 |
10/32✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 9 taken 214577 times.
✓ Branch 10 taken 312934 times.
✓ Branch 12 taken 1125 times.
✓ Branch 13 taken 34111 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 294903 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 27 taken 2362868 times.
✓ Branch 28 taken 3908416 times.
✓ Branch 30 taken 18689 times.
✓ Branch 31 taken 321195 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 2916263 times.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
|
10385081 | v = v < 0 ? mInside : mOutside; |
| 197 | } | ||
| 198 | const ValueT mOutside, mInside; | ||
| 199 | };// ChangeLevelSetBackgroundOp | ||
| 200 | |||
| 201 | |||
| 202 | template<typename TreeOrLeafManagerT> | ||
| 203 | void | ||
| 204 | 148 | changeBackground( | |
| 205 | TreeOrLeafManagerT& tree, | ||
| 206 | const typename TreeOrLeafManagerT::ValueType& background, | ||
| 207 | bool threaded, | ||
| 208 | size_t grainSize) | ||
| 209 | { | ||
| 210 | 296 | tree::NodeManager<TreeOrLeafManagerT> linearTree(tree); | |
| 211 | ChangeBackgroundOp<TreeOrLeafManagerT> op(tree, background); | ||
| 212 |
1/2✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
|
148 | linearTree.foreachTopDown(op, threaded, grainSize); |
| 213 | } | ||
| 214 | |||
| 215 | |||
| 216 | template<typename TreeOrLeafManagerT> | ||
| 217 | void | ||
| 218 | 28 | changeAsymmetricLevelSetBackground( | |
| 219 | TreeOrLeafManagerT& tree, | ||
| 220 | const typename TreeOrLeafManagerT::ValueType& outsideValue, | ||
| 221 | const typename TreeOrLeafManagerT::ValueType& insideValue, | ||
| 222 | bool threaded, | ||
| 223 | size_t grainSize) | ||
| 224 | { | ||
| 225 | 56 | tree::NodeManager<TreeOrLeafManagerT> linearTree(tree); | |
| 226 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
28 | ChangeLevelSetBackgroundOp<TreeOrLeafManagerT> op(outsideValue, insideValue); |
| 227 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
28 | linearTree.foreachTopDown(op, threaded, grainSize); |
| 228 | } | ||
| 229 | |||
| 230 | |||
| 231 | // If the narrow-band is symmetric only one background value is required | ||
| 232 | template<typename TreeOrLeafManagerT> | ||
| 233 | void | ||
| 234 | 10 | changeLevelSetBackground( | |
| 235 | TreeOrLeafManagerT& tree, | ||
| 236 | const typename TreeOrLeafManagerT::ValueType& background, | ||
| 237 | bool threaded, | ||
| 238 | size_t grainSize) | ||
| 239 | { | ||
| 240 | 10 | changeAsymmetricLevelSetBackground( | |
| 241 | 10 | tree, background, math::negative(background), threaded, grainSize); | |
| 242 | } | ||
| 243 | |||
| 244 | |||
| 245 | //////////////////////////////////////// | ||
| 246 | |||
| 247 | |||
| 248 | // Explicit Template Instantiation | ||
| 249 | |||
| 250 | #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
| 251 | |||
| 252 | #ifdef OPENVDB_INSTANTIATE_CHANGEBACKGROUND | ||
| 253 | #include <openvdb/util/ExplicitInstantiation.h> | ||
| 254 | #endif | ||
| 255 | |||
| 256 | #define _FUNCTION(TreeT) \ | ||
| 257 | void changeBackground(TreeT&, const TreeT::ValueType&, bool, size_t) | ||
| 258 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
| 259 | #undef _FUNCTION | ||
| 260 | |||
| 261 | #define _FUNCTION(TreeT) \ | ||
| 262 | void changeBackground(tree::LeafManager<TreeT>&, const TreeT::ValueType&, bool, size_t) | ||
| 263 | OPENVDB_VOLUME_TREE_INSTANTIATE(_FUNCTION) | ||
| 264 | #undef _FUNCTION | ||
| 265 | |||
| 266 | #define _FUNCTION(TreeT) \ | ||
| 267 | void changeLevelSetBackground(TreeT&, const TreeT::ValueType&, bool, size_t) | ||
| 268 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
| 269 | #undef _FUNCTION | ||
| 270 | |||
| 271 | #define _FUNCTION(TreeT) \ | ||
| 272 | void changeLevelSetBackground(tree::LeafManager<TreeT>&, const TreeT::ValueType&, bool, size_t) | ||
| 273 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
| 274 | #undef _FUNCTION | ||
| 275 | |||
| 276 | #define _FUNCTION(TreeT) \ | ||
| 277 | void changeAsymmetricLevelSetBackground(TreeT&, const TreeT::ValueType&, const TreeT::ValueType&, bool, size_t) | ||
| 278 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
| 279 | #undef _FUNCTION | ||
| 280 | |||
| 281 | #define _FUNCTION(TreeT) \ | ||
| 282 | void changeAsymmetricLevelSetBackground(tree::LeafManager<TreeT>&, const TreeT::ValueType&, const TreeT::ValueType&, bool, size_t) | ||
| 283 | OPENVDB_REAL_TREE_INSTANTIATE(_FUNCTION) | ||
| 284 | #undef _FUNCTION | ||
| 285 | |||
| 286 | #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
| 287 | |||
| 288 | |||
| 289 | } // namespace tools | ||
| 290 | } // namespace OPENVDB_VERSION_NAME | ||
| 291 | } // namespace openvdb | ||
| 292 | |||
| 293 | #endif // OPENVDB_TOOLS_CHANGEBACKGROUND_HAS_BEEN_INCLUDED | ||
| 294 |