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