OpenVDB: SignedFloodFill.h Source File

OpenVDB 3.1.0

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

SignedFloodFill.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2015 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
38
39 #ifndef OPENVDB_TOOLS_SIGNEDFLOODFILL_HAS_BEEN_INCLUDED
40 #define OPENVDB_TOOLS_SIGNEDFLOODFILL_HAS_BEEN_INCLUDED
41
42 #include <boost/utility/enable_if.hpp>
43 #include <openvdb/math/Math.h> // for math::negative
44 #include <openvdb/Types.h> // for Index typedef
45 #include <boost/static_assert.hpp>
46 #include <boost/type_traits/is_floating_point.hpp>
47 #include <boost/type_traits/is_signed.hpp>
48
49 #include <openvdb/tree/NodeManager.h>
50
51
52 namespace openvdb {
53 OPENVDB_USE_VERSION_NAMESPACE
54 namespace OPENVDB_VERSION_NAME {
55 namespace tools {
56
71 template<typename TreeOrLeafManagerT>
72 inline void
73 signedFloodFill(TreeOrLeafManagerT& tree, bool threaded = true, size_t grainSize = 1);
74
75
93 template<typename TreeOrLeafManagerT>
94 inline void
95 signedFloodFillWithValues(
96 TreeOrLeafManagerT& tree,
97 const typename TreeOrLeafManagerT::ValueType& outsideWidth,
98 const typename TreeOrLeafManagerT::ValueType& insideWidth,
99 bool threaded = true,
100 size_t grainSize = 1);
101
102
104
105
106 template<typename TreeOrLeafManagerT>
107 class SignedFloodFillOp
108 {
109 public:
110 typedef typename TreeOrLeafManagerT::ValueType ValueT;
111 typedef typename TreeOrLeafManagerT::RootNodeType RootT;
112 typedef typename TreeOrLeafManagerT::LeafNodeType LeafT;
113 BOOST_STATIC_ASSERT(boost::is_floating_point<ValueT>::value || boost::is_signed<ValueT>::value);
114
115 SignedFloodFillOp(const TreeOrLeafManagerT& tree)
116 : mOutside(ValueT(math::Abs(tree.background())))
117 , mInside(ValueT(math::negative(mOutside)))
118 {
119 }
120
121 SignedFloodFillOp(ValueT outsideValue, ValueT insideValue)
122 : mOutside(ValueT(math::Abs(outsideValue)))
123 , mInside(ValueT(math::negative(math::Abs(insideValue))))
124 {
125 }
126
127 // Nothing to do at the leaf node level
128 void operator()(LeafT& leaf) const
129 {
130 #ifndef OPENVDB_2_ABI_COMPATIBLE
131 if (!leaf.allocate()) return;//this assures that the buffer is allocated and in-memory
132 #endif
133 const typename LeafT::NodeMaskType& valueMask = leaf.getValueMask();
134 // WARNING: "Never do what you're about to see at home, we're what you call experts!"
135 typename LeafT::ValueType* buffer =
136 const_cast<typename LeafT::ValueType*>(&(leaf.getFirstValue()));
137
138 const Index first = valueMask.findFirstOn();
139 if (first < LeafT::SIZE) {
140 bool xInside = buffer[first]<0, yInside = xInside, zInside = xInside;
141 for (Index x = 0; x != (1 << LeafT::LOG2DIM); ++x) {
142 const Index x00 = x << (2 * LeafT::LOG2DIM);
143 if (valueMask.isOn(x00)) xInside = buffer[x00] < 0; // element(x, 0, 0)
144 yInside = xInside;
145 for (Index y = 0; y != (1 << LeafT::LOG2DIM); ++y) {
146 const Index xy0 = x00 + (y << LeafT::LOG2DIM);
147 if (valueMask.isOn(xy0)) yInside = buffer[xy0] < 0; // element(x, y, 0)
148 zInside = yInside;
149 for (Index z = 0; z != (1 << LeafT::LOG2DIM); ++z) {
150 const Index xyz = xy0 + z; // element(x, y, z)
151 if (valueMask.isOn(xyz)) {
152 zInside = buffer[xyz] < 0;
153 } else {
154 buffer[xyz] = zInside ? mInside : mOutside;
155 }
156 }
157 }
158 }
159 } else {// if no active voxels exist simply use the sign of the first value
160 leaf.fill(buffer[0] < 0 ? mInside : mOutside);
161 }
162 }
163
164 // Prune the child nodes of the internal nodes
165 template<typename NodeT>
166 void operator()(NodeT& node) const
167 {
168 // We assume the child nodes have already been flood filled!
169 const typename NodeT::NodeMaskType& childMask = node.getChildMask();
170 // WARNING: "Never do what you're about to see at home, we're what you call experts!"
171 typename NodeT::UnionType* table = const_cast<typename NodeT::UnionType*>(node.getTable());
172
173 const Index first = childMask.findFirstOn();
174 if (first < NodeT::NUM_VALUES) {
175 bool xInside = table[first].getChild()->getFirstValue()<0;
176 bool yInside = xInside, zInside = xInside;
177 for (Index x = 0; x != (1 << NodeT::LOG2DIM); ++x) {
178 const int x00 = x << (2 * NodeT::LOG2DIM); // offset for block(x, 0, 0)
179 if (childMask.isOn(x00)) xInside = table[x00].getChild()->getLastValue()<0;
180 yInside = xInside;
181 for (Index y = 0; y != (1 << NodeT::LOG2DIM); ++y) {
182 const Index xy0 = x00 + (y << NodeT::LOG2DIM); // offset for block(x, y, 0)
183 if (childMask.isOn(xy0)) yInside = table[xy0].getChild()->getLastValue()<0;
184 zInside = yInside;
185 for (Index z = 0; z != (1 << NodeT::LOG2DIM); ++z) {
186 const Index xyz = xy0 + z; // offset for block(x, y, z)
187 if (childMask.isOn(xyz)) {
188 zInside = table[xyz].getChild()->getLastValue()<0;
189 } else {
190 table[xyz].setValue(zInside ? mInside : mOutside);
191 }
192 }
193 }
194 }
195 } else {//no child nodes exist simply use the sign of the first tile value.
196 const ValueT v = table[0].getValue()<0 ? mInside : mOutside;
197 for (Index i = 0; i < NodeT::NUM_VALUES; ++i) table[i].setValue(v);
198 }
199 }
200
201 // Prune the child nodes of the root node
202 void operator()(RootT& root) const
203 {
204 typedef typename RootT::ChildNodeType ChildT;
205 // Insert the child nodes into a map sorted according to their origin
206 std::map<Coord, ChildT*> nodeKeys;
207 typename RootT::ChildOnIter it = root.beginChildOn();
208 for (; it; ++it) nodeKeys.insert(std::pair<Coord, ChildT*>(it.getCoord(), &(*it)));
209 static const Index DIM = RootT::ChildNodeType::DIM;
210
211 // We employ a simple z-scanline algorithm that inserts inactive tiles with
212 // the inside value if they are sandwiched between inside child nodes only!
213 typename std::map<Coord, ChildT*>::const_iterator b = nodeKeys.begin(), e = nodeKeys.end();
214 if ( b == e ) return;
215 for (typename std::map<Coord, ChildT*>::const_iterator a = b++; b != e; ++a, ++b) {
216 Coord d = b->first - a->first; // delta of neighboring coordinates
217 if (d[0]!=0 || d[1]!=0 || d[2]==Int32(DIM)) continue;// not same z-scanline or neighbors
218 const ValueT fill[] = { a->second->getLastValue(), b->second->getFirstValue() };
219 if (!(fill[0] < 0) || !(fill[1] < 0)) continue; // scanline isn't inside
220 Coord c = a->first + Coord(0u, 0u, DIM);
221 for (; c[2] != b->first[2]; c[2] += DIM) root.addTile(c, mInside, false);
222 }
223 root.setBackground(mOutside, /*updateChildNodes=*/false);
224 }
225
226 private:
227 const ValueT mOutside, mInside;
228 };// SignedFloodFillOp
229
230
231 template<typename TreeOrLeafManagerT>
232 inline
233 typename boost::enable_if_c<
234 boost::is_floating_point<typename TreeOrLeafManagerT::ValueType>::value ||
235 boost::is_signed<typename TreeOrLeafManagerT::ValueType>::value, void>::type
236 doSignedFloodFill(TreeOrLeafManagerT& tree,
237 typename TreeOrLeafManagerT::ValueType outsideValue,
238 typename TreeOrLeafManagerT::ValueType insideValue,
239 bool threaded,
240 size_t grainSize)
241 {
242 tree::NodeManager<TreeOrLeafManagerT> nodes(tree);
243 SignedFloodFillOp<TreeOrLeafManagerT> op(outsideValue, insideValue);
244 nodes.processBottomUp(op, threaded, grainSize);
245 }
246
247 // Dummy (no-op) implementation for non-float types
248 template <typename TreeOrLeafManagerT>
249 inline
250 typename boost::disable_if_c<
251 boost::is_floating_point<typename TreeOrLeafManagerT::ValueType>::value ||
252 boost::is_signed<typename TreeOrLeafManagerT::ValueType>::value, void>::type
253 doSignedFloodFill(TreeOrLeafManagerT&,
254 const typename TreeOrLeafManagerT::ValueType&,
255 const typename TreeOrLeafManagerT::ValueType&,
256 bool,
257 size_t)
258 {
259 OPENVDB_THROW(TypeError,
260 "signedFloodFill is supported only for signed value grids");
261 }
262
263
264 // If the narrow-band is symmetric and unchanged
265 template <typename TreeOrLeafManagerT>
266 inline void
267 signedFloodFillWithValues(
268 TreeOrLeafManagerT& tree,
269 const typename TreeOrLeafManagerT::ValueType& outsideValue,
270 const typename TreeOrLeafManagerT::ValueType& insideValue,
271 bool threaded,
272 size_t grainSize)
273 {
274 doSignedFloodFill(tree, outsideValue, insideValue, threaded, grainSize);
275 }
276
277
278 template <typename TreeOrLeafManagerT>
279 inline void
280 signedFloodFill(TreeOrLeafManagerT& tree,
281 bool threaded,
282 size_t grainSize)
283 {
284 const typename TreeOrLeafManagerT::ValueType v = tree.root().background();
285 doSignedFloodFill(tree, v, math::negative(v), threaded, grainSize);
286 }
287
288 } // namespace tools
289 } // namespace OPENVDB_VERSION_NAME
290 } // namespace openvdb
291
292 #endif // OPENVDB_TOOLS_RESETBACKGROUND_HAS_BEEN_INCLUDED
293
294 // Copyright (c) 2012-2015 DreamWorks Animation LLC
295 // All rights reserved. This software is distributed under the
296 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v3_1_0::math::negative
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:116
openvdb::v3_1_0::Index
Index32 Index
Definition: Types.h:58
Types.h
openvdb::v3_1_0::tools::SignedFloodFillOp::operator()
void operator()(LeafT &leaf) const
Definition: SignedFloodFill.h:128
openvdb::v3_1_0::tools::SignedFloodFillOp
Definition: SignedFloodFill.h:107
openvdb::v3_1_0::tools::doSignedFloodFill
boost::disable_if_c< boost::is_floating_point< typename TreeOrLeafManagerT::ValueType >::value||boost::is_signed< typename TreeOrLeafManagerT::ValueType >::value, void >::type doSignedFloodFill(TreeOrLeafManagerT &, const typename TreeOrLeafManagerT::ValueType &, const typename TreeOrLeafManagerT::ValueType &, bool, size_t)
Definition: SignedFloodFill.h:253
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
openvdb::v3_1_0::math::Abs
int32_t Abs(int32_t i)
Return the absolute value of the given quantity.
Definition: Math.h:293
openvdb::v3_1_0::tree::NodeManager::processBottomUp
void processBottomUp(const NodeOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to all the nodes in the tree.
Definition: NodeManager.h:401
openvdb::v3_1_0::tools::SignedFloodFillOp::RootT
TreeOrLeafManagerT::RootNodeType RootT
Definition: SignedFloodFill.h:111
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
NodeManager.h
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
openvdb::v3_1_0::tools::signedFloodFillWithValues
void signedFloodFillWithValues(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &outsideWidth, const typename TreeOrLeafManagerT::ValueType &insideWidth, bool threaded=true, size_t grainSize=1)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:267
openvdb::v3_1_0::tools::SignedFloodFillOp::operator()
void operator()(NodeT &node) const
Definition: SignedFloodFill.h:166
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
Definition: version.h:43
openvdb::v3_1_0::tools::SignedFloodFillOp::SignedFloodFillOp
SignedFloodFillOp(const TreeOrLeafManagerT &tree)
Definition: SignedFloodFill.h:115
openvdb::v3_1_0::tools::SignedFloodFillOp::operator()
void operator()(RootT &root) const
Definition: SignedFloodFill.h:202
openvdb
Definition: Exceptions.h:39
openvdb::v3_1_0::tools::SignedFloodFillOp::LeafT
TreeOrLeafManagerT::LeafNodeType LeafT
Definition: SignedFloodFill.h:112
openvdb::v3_1_0::tools::signedFloodFill
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:280
openvdb::v3_1_0::tree::NodeManager
To facilitate threading over the nodes of a tree, cache node pointers in linear arrays, one for each level of the tree.
Definition: NodeManager.h:56
openvdb::v3_1_0::Int32
int32_t Int32
Definition: Types.h:60
openvdb::v3_1_0::tools::SignedFloodFillOp::ValueT
TreeOrLeafManagerT::ValueType ValueT
Definition: SignedFloodFill.h:110
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
openvdb::v3_1_0::TypeError
Definition: Exceptions.h:87
openvdb::v3_1_0::tools::SignedFloodFillOp::SignedFloodFillOp
SignedFloodFillOp(ValueT outsideValue, ValueT insideValue)
Definition: SignedFloodFill.h:121