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     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     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     explicit ActivateOp(const ValueT& value,
65                         const ValueT& tolerance = zeroVal<ValueT>())
mValueActivateOp66         : mValue(value)
67         , mTolerance(tolerance) { }
68 
checkActivateOp69     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         if (IgnoreTolerance)    return value == mValue;
73         return math::isApproxEqual(value, mValue, mTolerance);
74     }
75 
operatorActivateOp76     bool operator()(RootT& root, size_t) const
77     {
78         for (auto it = root.beginValueOff(); it; ++it) {
79             if (check(*it))     it.setValueOn(/*on=*/true);
80         }
81         return true;
82     }
83 
84     template<typename NodeT>
operatorActivateOp85     bool operator()(NodeT& node, size_t) const
86     {
87         // only iterate if there are inactive tiles
88         if (!node.isValueMaskOn()) {
89             for (auto it = node.beginValueOff(); it; ++it) {
90                 if (check(*it))     it.setValueOn(/*on=*/true);
91             }
92         }
93         // return false if there are no child nodes below this node
94         return !node.isChildMaskOff();
95     }
96 
operatorActivateOp97     bool operator()(LeafT& leaf, size_t) const
98     {
99         // early-exit if there are no inactive values
100         if (leaf.isValueMaskOn())  return true;
101         for (auto it = leaf.beginValueOff(); it; ++it) {
102             if (check(*it))     it.setValueOn(/*on=*/true);
103         }
104         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     explicit DeactivateOp(const ValueT& value,
121                         const ValueT& tolerance = zeroVal<ValueT>())
mValueDeactivateOp122         : mValue(value)
123         , mTolerance(tolerance) { }
124 
checkDeactivateOp125     inline bool check(const ValueT& value) const {
126         if (IgnoreTolerance)    return value == mValue;
127         return math::isApproxEqual(value, mValue, mTolerance);
128     }
129 
operatorDeactivateOp130     bool operator()(RootT& root, size_t) const
131     {
132         for (auto it = root.beginValueOn(); it; ++it) {
133             if (check(*it))     it.setValueOn(/*on=*/false);
134         }
135         return true;
136     }
137 
138     template<typename NodeT>
operatorDeactivateOp139     bool operator()(NodeT& node, size_t) const
140     {
141         // only iterate if there are active tiles
142         if (!node.isValueMaskOff()) {
143             for (auto it = node.beginValueOn(); it; ++it) {
144                 if (check(*it))     it.setValueOn(/*on=*/false);
145             }
146         }
147         // return false if there are no child nodes below this node
148         return !node.isChildMaskOff();
149     }
150 
operatorDeactivateOp151     bool operator()(LeafT& leaf, size_t) const
152     {
153         // early-exit if there are no active values
154         if (leaf.isValueMaskOff())  return true;
155         for (auto it = leaf.beginValueOn(); it; ++it) {
156             if (check(*it))     it.setValueOn(/*on=*/false);
157         }
158         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>
activate(GridOrTree & gridOrTree,const typename GridOrTree::ValueType & value,const typename GridOrTree::ValueType & tolerance,const bool threaded)175 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     tree::DynamicNodeManager<TreeType> nodeManager(tree);
187 
188     if (tolerance == zeroVal<ValueType>()) {
189         activate_internal::ActivateOp<TreeType, /*IgnoreTolerance=*/true> op(value);
190         nodeManager.foreachTopDown(op, threaded);
191     } else {
192         activate_internal::ActivateOp<TreeType> op(value, tolerance);
193         nodeManager.foreachTopDown(op, threaded);
194     }
195 }
196 
197 
198 template<typename GridOrTree>
deactivate(GridOrTree & gridOrTree,const typename GridOrTree::ValueType & value,const typename GridOrTree::ValueType & tolerance,const bool threaded)199 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     tree::DynamicNodeManager<TreeType> nodeManager(tree);
211 
212     if (tolerance == zeroVal<ValueType>()) {
213         activate_internal::DeactivateOp<TreeType, /*IgnoreTolerance=*/true> op(value);
214         nodeManager.foreachTopDown(op, threaded);
215     } else {
216         activate_internal::DeactivateOp<TreeType> op(value, tolerance);
217         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