| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright Contributors to the OpenVDB Project | ||
| 2 | // SPDX-License-Identifier: MPL-2.0 | ||
| 3 | // | ||
| 4 | /// @file Activate.h | ||
| 5 | /// | ||
| 6 | /// @brief Implementation of topological activation/deactivation | ||
| 7 | /// | ||
| 8 | /// @author Ken Museth | ||
| 9 | /// | ||
| 10 | |||
| 11 | #ifndef OPENVDB_TOOLS_ACTIVATE_HAS_BEEN_INCLUDED | ||
| 12 | #define OPENVDB_TOOLS_ACTIVATE_HAS_BEEN_INCLUDED | ||
| 13 | |||
| 14 | #include <openvdb/Types.h> | ||
| 15 | #include <openvdb/Grid.h> | ||
| 16 | #include <openvdb/math/Math.h> // for isApproxEqual() | ||
| 17 | #include <openvdb/tree/NodeManager.h> | ||
| 18 | #include <openvdb/openvdb.h> | ||
| 19 | #include <openvdb/points/PointDataGrid.h> | ||
| 20 | |||
| 21 | |||
| 22 | namespace openvdb { | ||
| 23 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 24 | namespace OPENVDB_VERSION_NAME { | ||
| 25 | namespace tools { | ||
| 26 | |||
| 27 | /// @brief Mark as active any inactive tiles or voxels in the given grid or tree | ||
| 28 | /// whose values are equal to @a value (optionally to within the given @a tolerance). | ||
| 29 | template<typename GridOrTree> | ||
| 30 | void activate( | ||
| 31 | GridOrTree&, | ||
| 32 | const typename GridOrTree::ValueType& value, | ||
| 33 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
3 | const typename GridOrTree::ValueType& tolerance = zeroVal<typename GridOrTree::ValueType>(), |
| 34 | const bool threaded = true | ||
| 35 | ); | ||
| 36 | |||
| 37 | |||
| 38 | /// @brief Mark as inactive any active tiles or voxels in the given grid or tree | ||
| 39 | /// whose values are equal to @a value (optionally to within the given @a tolerance). | ||
| 40 | template<typename GridOrTree> | ||
| 41 | void deactivate( | ||
| 42 | GridOrTree&, | ||
| 43 | const typename GridOrTree::ValueType& value, | ||
| 44 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | const typename GridOrTree::ValueType& tolerance = zeroVal<typename GridOrTree::ValueType>(), |
| 45 | const bool threaded = true | ||
| 46 | ); | ||
| 47 | |||
| 48 | |||
| 49 | //////////////////////////////////////// | ||
| 50 | |||
| 51 | |||
| 52 | /// @cond OPENVDB_DOCS_INTERNAL | ||
| 53 | |||
| 54 | namespace activate_internal { | ||
| 55 | |||
| 56 | template<typename TreeT, bool IgnoreTolerance = false> | ||
| 57 | struct ActivateOp | ||
| 58 | { | ||
| 59 | public: | ||
| 60 | using RootT = typename TreeT::RootNodeType; | ||
| 61 | using LeafT = typename TreeT::LeafNodeType; | ||
| 62 | using ValueT = typename TreeT::ValueType; | ||
| 63 | |||
| 64 | 21 | explicit ActivateOp(const ValueT& value, | |
| 65 | 3 | const ValueT& tolerance = zeroVal<ValueT>()) | |
| 66 | : mValue(value) | ||
| 67 | 21 | , mTolerance(tolerance) { } | |
| 68 | |||
| 69 | inline bool check(const ValueT& value) const { | ||
| 70 | // math::isApproxEqual is marginally more expensive, | ||
| 71 | // so opt to do direct comparison if tolerance is ignored | ||
| 72 | 335867 | if (IgnoreTolerance) return value == mValue; | |
| 73 | return math::isApproxEqual(value, mValue, mTolerance); | ||
| 74 | } | ||
| 75 | |||
| 76 | 42 | bool operator()(RootT& root, size_t) const | |
| 77 | { | ||
| 78 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 21 times.
|
94 | for (auto it = root.beginValueOff(); it; ++it) { |
| 79 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
8 | if (check(*it)) it.setValueOn(/*on=*/true); |
| 80 | } | ||
| 81 | 42 | return true; | |
| 82 | } | ||
| 83 | |||
| 84 | template<typename NodeT> | ||
| 85 | 118 | bool operator()(NodeT& node, size_t) const | |
| 86 | { | ||
| 87 | // only iterate if there are inactive tiles | ||
| 88 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
118 | if (!node.isValueMaskOn()) { |
| 89 |
2/2✓ Branch 0 taken 729080 times.
✓ Branch 1 taken 59 times.
|
1458278 | for (auto it = node.beginValueOff(); it; ++it) { |
| 90 |
2/2✓ Branch 0 taken 36863 times.
✓ Branch 1 taken 405505 times.
|
995184 | if (check(*it)) it.setValueOn(/*on=*/true); |
| 91 | } | ||
| 92 | } | ||
| 93 | // return false if there are no child nodes below this node | ||
| 94 | 118 | return !node.isChildMaskOff(); | |
| 95 | } | ||
| 96 | |||
| 97 | 19270 | bool operator()(LeafT& leaf, size_t) const | |
| 98 | { | ||
| 99 | // early-exit if there are no inactive values | ||
| 100 |
1/2✓ Branch 0 taken 9635 times.
✗ Branch 1 not taken.
|
19270 | if (leaf.isValueMaskOn()) return true; |
| 101 |
2/2✓ Branch 0 taken 4929207 times.
✓ Branch 1 taken 9635 times.
|
9877684 | for (auto it = leaf.beginValueOff(); it; ++it) { |
| 102 |
2/2✓ Branch 0 taken 516 times.
✓ Branch 1 taken 5108 times.
|
6665130 | if (check(*it)) it.setValueOn(/*on=*/true); |
| 103 | } | ||
| 104 | 19270 | return true; | |
| 105 | } | ||
| 106 | |||
| 107 | private: | ||
| 108 | const ValueT mValue; | ||
| 109 | const ValueT mTolerance; | ||
| 110 | };// ActivateOp | ||
| 111 | |||
| 112 | template<typename TreeT, bool IgnoreTolerance = false> | ||
| 113 | struct DeactivateOp | ||
| 114 | { | ||
| 115 | public: | ||
| 116 | using RootT = typename TreeT::RootNodeType; | ||
| 117 | using LeafT = typename TreeT::LeafNodeType; | ||
| 118 | using ValueT = typename TreeT::ValueType; | ||
| 119 | |||
| 120 | 21 | explicit DeactivateOp(const ValueT& value, | |
| 121 | 2 | const ValueT& tolerance = zeroVal<ValueT>()) | |
| 122 | : mValue(value) | ||
| 123 | 21 | , mTolerance(tolerance) { } | |
| 124 | |||
| 125 | inline bool check(const ValueT& value) const { | ||
| 126 | 15 | if (IgnoreTolerance) return value == mValue; | |
| 127 | return math::isApproxEqual(value, mValue, mTolerance); | ||
| 128 | } | ||
| 129 | |||
| 130 | 42 | bool operator()(RootT& root, size_t) const | |
| 131 | { | ||
| 132 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 21 times.
|
94 | for (auto it = root.beginValueOn(); it; ++it) { |
| 133 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
8 | if (check(*it)) it.setValueOn(/*on=*/false); |
| 134 | } | ||
| 135 | 42 | return true; | |
| 136 | } | ||
| 137 | |||
| 138 | template<typename NodeT> | ||
| 139 | 118 | bool operator()(NodeT& node, size_t) const | |
| 140 | { | ||
| 141 | // only iterate if there are active tiles | ||
| 142 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 30 times.
|
118 | if (!node.isValueMaskOff()) { |
| 143 |
2/2✓ Branch 0 taken 55233 times.
✓ Branch 1 taken 29 times.
|
110524 | for (auto it = node.beginValueOn(); it; ++it) { |
| 144 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
110450 | if (check(*it)) it.setValueOn(/*on=*/false); |
| 145 | } | ||
| 146 | } | ||
| 147 | // return false if there are no child nodes below this node | ||
| 148 | 118 | return !node.isChildMaskOff(); | |
| 149 | } | ||
| 150 | |||
| 151 | 19270 | bool operator()(LeafT& leaf, size_t) const | |
| 152 | { | ||
| 153 | // early-exit if there are no active values | ||
| 154 |
2/2✓ Branch 0 taken 9634 times.
✓ Branch 1 taken 1 times.
|
19270 | if (leaf.isValueMaskOff()) return true; |
| 155 |
2/2✓ Branch 0 taken 3330863 times.
✓ Branch 1 taken 9634 times.
|
6680994 | for (auto it = leaf.beginValueOn(); it; ++it) { |
| 156 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 7 times.
|
6653912 | if (check(*it)) it.setValueOn(/*on=*/false); |
| 157 | } | ||
| 158 | 19268 | return true; | |
| 159 | } | ||
| 160 | |||
| 161 | private: | ||
| 162 | const ValueT mValue; | ||
| 163 | const ValueT mTolerance; | ||
| 164 | };// DeactivateOp | ||
| 165 | |||
| 166 | } // namespace activate_internal | ||
| 167 | |||
| 168 | /// @endcond | ||
| 169 | |||
| 170 | |||
| 171 | //////////////////////////////////////// | ||
| 172 | |||
| 173 | |||
| 174 | template<typename GridOrTree> | ||
| 175 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
|
42 | void activate(GridOrTree& gridOrTree, |
| 176 | const typename GridOrTree::ValueType& value, | ||
| 177 | const typename GridOrTree::ValueType& tolerance, | ||
| 178 | const bool threaded) | ||
| 179 | { | ||
| 180 | using Adapter = TreeAdapter<GridOrTree>; | ||
| 181 | using TreeType = typename Adapter::TreeType; | ||
| 182 | using ValueType = typename TreeType::ValueType; | ||
| 183 | |||
| 184 | TreeType& tree = Adapter::tree(gridOrTree); | ||
| 185 | |||
| 186 | 42 | tree::DynamicNodeManager<TreeType> nodeManager(tree); | |
| 187 | |||
| 188 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 5 times.
|
32 | if (tolerance == zeroVal<ValueType>()) { |
| 189 | 6 | activate_internal::ActivateOp<TreeType, /*IgnoreTolerance=*/true> op(value); | |
| 190 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
28 | nodeManager.foreachTopDown(op, threaded); |
| 191 | } else { | ||
| 192 | activate_internal::ActivateOp<TreeType> op(value, tolerance); | ||
| 193 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
14 | nodeManager.foreachTopDown(op, threaded); |
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | |||
| 198 | template<typename GridOrTree> | ||
| 199 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
|
42 | void deactivate(GridOrTree& gridOrTree, |
| 200 | const typename GridOrTree::ValueType& value, | ||
| 201 | const typename GridOrTree::ValueType& tolerance, | ||
| 202 | const bool threaded) | ||
| 203 | { | ||
| 204 | using Adapter = TreeAdapter<GridOrTree>; | ||
| 205 | using TreeType = typename Adapter::TreeType; | ||
| 206 | using ValueType = typename TreeType::ValueType; | ||
| 207 | |||
| 208 | TreeType& tree = Adapter::tree(gridOrTree); | ||
| 209 | |||
| 210 | 42 | tree::DynamicNodeManager<TreeType> nodeManager(tree); | |
| 211 | |||
| 212 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 5 times.
|
32 | if (tolerance == zeroVal<ValueType>()) { |
| 213 | 4 | activate_internal::DeactivateOp<TreeType, /*IgnoreTolerance=*/true> op(value); | |
| 214 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
26 | nodeManager.foreachTopDown(op, threaded); |
| 215 | } else { | ||
| 216 | activate_internal::DeactivateOp<TreeType> op(value, tolerance); | ||
| 217 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | nodeManager.foreachTopDown(op, threaded); |
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | |||
| 222 | //////////////////////////////////////// | ||
| 223 | |||
| 224 | |||
| 225 | // Explicit Template Instantiation | ||
| 226 | |||
| 227 | #ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
| 228 | |||
| 229 | #ifdef OPENVDB_INSTANTIATE_ACTIVATE | ||
| 230 | #include <openvdb/util/ExplicitInstantiation.h> | ||
| 231 | #endif | ||
| 232 | |||
| 233 | #define _FUNCTION(TreeT) \ | ||
| 234 | void activate(TreeT&, const TreeT::ValueType&, const TreeT::ValueType&, const bool) | ||
| 235 | OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION) | ||
| 236 | #undef _FUNCTION | ||
| 237 | |||
| 238 | #define _FUNCTION(TreeT) \ | ||
| 239 | void activate(Grid<TreeT>&, const TreeT::ValueType&, const TreeT::ValueType&, const bool) | ||
| 240 | OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION) | ||
| 241 | #undef _FUNCTION | ||
| 242 | |||
| 243 | #define _FUNCTION(TreeT) \ | ||
| 244 | void deactivate(TreeT&, const TreeT::ValueType&, const TreeT::ValueType&, const bool) | ||
| 245 | OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION) | ||
| 246 | #undef _FUNCTION | ||
| 247 | |||
| 248 | #define _FUNCTION(TreeT) \ | ||
| 249 | void deactivate(Grid<TreeT>&, const TreeT::ValueType&, const TreeT::ValueType&, const bool) | ||
| 250 | OPENVDB_ALL_TREE_INSTANTIATE(_FUNCTION) | ||
| 251 | #undef _FUNCTION | ||
| 252 | |||
| 253 | #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION | ||
| 254 | |||
| 255 | |||
| 256 | } // namespace tools | ||
| 257 | } // namespace OPENVDB_VERSION_NAME | ||
| 258 | } // namespace openvdb | ||
| 259 | |||
| 260 | #endif // OPENVDB_TOOLS_ACTIVATE_HAS_BEEN_INCLUDED | ||
| 261 |