OpenVDB: SignedFloodFill.h Source File

OpenVDB 5.1.0

SignedFloodFill.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2018 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 //
37
38 #ifndef OPENVDB_TOOLS_SIGNEDFLOODFILL_HAS_BEEN_INCLUDED
39 #define OPENVDB_TOOLS_SIGNEDFLOODFILL_HAS_BEEN_INCLUDED
40
41 #include <openvdb/version.h>
42 #include <openvdb/Types.h> // for Index typedef
43 #include <openvdb/math/Math.h> // for math::negative
44 #include <openvdb/tree/NodeManager.h>
45 #include <map>
46 #include <type_traits>
47
48
49 namespace openvdb {
50 OPENVDB_USE_VERSION_NAMESPACE
51 namespace OPENVDB_VERSION_NAME {
52 namespace tools {
53
69 template<typename TreeOrLeafManagerT>
70 inline void
71 signedFloodFill(TreeOrLeafManagerT& tree, bool threaded = true,
72 size_t grainSize = 1, Index minLevel = 0);
73
74
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 Index minLevel = 0);
102
103
105
106
107 template<typename TreeOrLeafManagerT>
108 class SignedFloodFillOp
109 {
110 public:
111 using ValueT = typename TreeOrLeafManagerT::ValueType;
112 using RootT = typename TreeOrLeafManagerT::RootNodeType;
113 using LeafT = typename TreeOrLeafManagerT::LeafNodeType;
114 static_assert(std::is_signed<ValueT>::value,
115 "signed flood fill is supported only for signed value grids");
116
117 SignedFloodFillOp(const TreeOrLeafManagerT& tree, Index minLevel = 0)
118 : mOutside(ValueT(math::Abs(tree.background())))
119 , mInside(ValueT(math::negative(mOutside)))
120 , mMinLevel(minLevel)
121 {
122 }
123
124 SignedFloodFillOp(ValueT outsideValue, ValueT insideValue, Index minLevel = 0)
125 : mOutside(ValueT(math::Abs(outsideValue)))
126 , mInside(ValueT(math::negative(math::Abs(insideValue))))
127 , mMinLevel(minLevel)
128 {
129 }
130
131 // Nothing to do at the leaf node level
132 void operator()(LeafT& leaf) const
133 {
134 if (LeafT::LEVEL < mMinLevel) return;
135
136 #if OPENVDB_ABI_VERSION_NUMBER >= 3
137 if (!leaf.allocate()) return; // this assures that the buffer is allocated and in-memory
138 #endif
139 const typename LeafT::NodeMaskType& valueMask = leaf.getValueMask();
140 // WARNING: "Never do what you're about to see at home, we're what you call experts!"
141 typename LeafT::ValueType* buffer =
142 const_cast<typename LeafT::ValueType*>(&(leaf.getFirstValue()));
143
144 const Index first = valueMask.findFirstOn();
145 if (first < LeafT::SIZE) {
146 bool xInside = buffer[first]<0, yInside = xInside, zInside = xInside;
147 for (Index x = 0; x != (1 << LeafT::LOG2DIM); ++x) {
148 const Index x00 = x << (2 * LeafT::LOG2DIM);
149 if (valueMask.isOn(x00)) xInside = buffer[x00] < 0; // element(x, 0, 0)
150 yInside = xInside;
151 for (Index y = 0; y != (1 << LeafT::LOG2DIM); ++y) {
152 const Index xy0 = x00 + (y << LeafT::LOG2DIM);
153 if (valueMask.isOn(xy0)) yInside = buffer[xy0] < 0; // element(x, y, 0)
154 zInside = yInside;
155 for (Index z = 0; z != (1 << LeafT::LOG2DIM); ++z) {
156 const Index xyz = xy0 + z; // element(x, y, z)
157 if (valueMask.isOn(xyz)) {
158 zInside = buffer[xyz] < 0;
159 } else {
160 buffer[xyz] = zInside ? mInside : mOutside;
161 }
162 }
163 }
164 }
165 } else {// if no active voxels exist simply use the sign of the first value
166 leaf.fill(buffer[0] < 0 ? mInside : mOutside);
167 }
168 }
169
170 // Prune the child nodes of the internal nodes
171 template<typename NodeT>
172 void operator()(NodeT& node) const
173 {
174 if (NodeT::LEVEL < mMinLevel) return;
175 // We assume the child nodes have already been flood filled!
176 const typename NodeT::NodeMaskType& childMask = node.getChildMask();
177 // WARNING: "Never do what you're about to see at home, we're what you call experts!"
178 typename NodeT::UnionType* table = const_cast<typename NodeT::UnionType*>(node.getTable());
179
180 const Index first = childMask.findFirstOn();
181 if (first < NodeT::NUM_VALUES) {
182 bool xInside = table[first].getChild()->getFirstValue()<0;
183 bool yInside = xInside, zInside = xInside;
184 for (Index x = 0; x != (1 << NodeT::LOG2DIM); ++x) {
185 const int x00 = x << (2 * NodeT::LOG2DIM); // offset for block(x, 0, 0)
186 if (childMask.isOn(x00)) xInside = table[x00].getChild()->getLastValue()<0;
187 yInside = xInside;
188 for (Index y = 0; y != (1 << NodeT::LOG2DIM); ++y) {
189 const Index xy0 = x00 + (y << NodeT::LOG2DIM); // offset for block(x, y, 0)
190 if (childMask.isOn(xy0)) yInside = table[xy0].getChild()->getLastValue()<0;
191 zInside = yInside;
192 for (Index z = 0; z != (1 << NodeT::LOG2DIM); ++z) {
193 const Index xyz = xy0 + z; // offset for block(x, y, z)
194 if (childMask.isOn(xyz)) {
195 zInside = table[xyz].getChild()->getLastValue()<0;
196 } else {
197 table[xyz].setValue(zInside ? mInside : mOutside);
198 }
199 }
200 }
201 }
202 } else {//no child nodes exist simply use the sign of the first tile value.
203 const ValueT v = table[0].getValue()<0 ? mInside : mOutside;
204 for (Index i = 0; i < NodeT::NUM_VALUES; ++i) table[i].setValue(v);
205 }
206 }
207
208 // Prune the child nodes of the root node
209 void operator()(RootT& root) const
210 {
211 if (RootT::LEVEL < mMinLevel) return;
212 using ChildT = typename RootT::ChildNodeType;
213 // Insert the child nodes into a map sorted according to their origin
214 std::map<Coord, ChildT*> nodeKeys;
215 typename RootT::ChildOnIter it = root.beginChildOn();
216 for (; it; ++it) nodeKeys.insert(std::pair<Coord, ChildT*>(it.getCoord(), &(*it)));
217 static const Index DIM = RootT::ChildNodeType::DIM;
218
219 // We employ a simple z-scanline algorithm that inserts inactive tiles with
220 // the inside value if they are sandwiched between inside child nodes only!
221 typename std::map<Coord, ChildT*>::const_iterator b = nodeKeys.begin(), e = nodeKeys.end();
222 if ( b == e ) return;
223 for (typename std::map<Coord, ChildT*>::const_iterator a = b++; b != e; ++a, ++b) {
224 Coord d = b->first - a->first; // delta of neighboring coordinates
225 if (d[0]!=0 || d[1]!=0 || d[2]==Int32(DIM)) continue;// not same z-scanline or neighbors
226 const ValueT fill[] = { a->second->getLastValue(), b->second->getFirstValue() };
227 if (!(fill[0] < 0) || !(fill[1] < 0)) continue; // scanline isn't inside
228 Coord c = a->first + Coord(0u, 0u, DIM);
229 for (; c[2] != b->first[2]; c[2] += DIM) root.addTile(c, mInside, false);
230 }
231 root.setBackground(mOutside, /*updateChildNodes=*/false);
232 }
233
234 private:
235 const ValueT mOutside, mInside;
236 const Index mMinLevel;
237 };// SignedFloodFillOp
238
239
240 //{
242
243 template<typename TreeOrLeafManagerT>
244 inline
245 typename std::enable_if<std::is_signed<typename TreeOrLeafManagerT::ValueType>::value, void>::type
246 doSignedFloodFill(TreeOrLeafManagerT& tree,
247 typename TreeOrLeafManagerT::ValueType outsideValue,
248 typename TreeOrLeafManagerT::ValueType insideValue,
249 bool threaded,
250 size_t grainSize,
251 Index minLevel)
252 {
253 tree::NodeManager<TreeOrLeafManagerT> nodes(tree);
254 SignedFloodFillOp<TreeOrLeafManagerT> op(outsideValue, insideValue, minLevel);
255 nodes.foreachBottomUp(op, threaded, grainSize);
256 }
257
258 // Dummy (no-op) implementation for unsigned types
259 template <typename TreeOrLeafManagerT>
260 inline
261 typename std::enable_if<!std::is_signed<typename TreeOrLeafManagerT::ValueType>::value, void>::type
262 doSignedFloodFill(TreeOrLeafManagerT&,
263 const typename TreeOrLeafManagerT::ValueType&,
264 const typename TreeOrLeafManagerT::ValueType&,
265 bool,
266 size_t,
267 Index)
268 {
269 OPENVDB_THROW(TypeError,
270 "signedFloodFill is supported only for signed value grids");
271 }
272
274 //}
275
276
277 // If the narrow-band is symmetric and unchanged
278 template <typename TreeOrLeafManagerT>
279 inline void
280 signedFloodFillWithValues(
281 TreeOrLeafManagerT& tree,
282 const typename TreeOrLeafManagerT::ValueType& outsideValue,
283 const typename TreeOrLeafManagerT::ValueType& insideValue,
284 bool threaded,
285 size_t grainSize,
286 Index minLevel)
287 {
288 doSignedFloodFill(tree, outsideValue, insideValue, threaded, grainSize, minLevel);
289 }
290
291
292 template <typename TreeOrLeafManagerT>
293 inline void
294 signedFloodFill(TreeOrLeafManagerT& tree,
295 bool threaded,
296 size_t grainSize,
297 Index minLevel)
298 {
299 const typename TreeOrLeafManagerT::ValueType v = tree.root().background();
300 doSignedFloodFill(tree, v, math::negative(v), threaded, grainSize, minLevel);
301 }
302
303 } // namespace tools
304 } // namespace OPENVDB_VERSION_NAME
305 } // namespace openvdb
306
307 #endif // OPENVDB_TOOLS_RESETBACKGROUND_HAS_BEEN_INCLUDED
308
309 // Copyright (c) 2012-2018 DreamWorks Animation LLC
310 // All rights reserved. This software is distributed under the
311 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v5_1::tools::signedFloodFillWithValues
void signedFloodFillWithValues(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &outsideWidth, const typename TreeOrLeafManagerT::ValueType &insideWidth, bool threaded=true, size_t grainSize=1, Index minLevel=0)
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
Types.h
openvdb::v5_1::math::Abs
Coord Abs(const Coord &xyz)
Definition: Coord.h:513
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
NodeManager.h
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
openvdb::v5_1::tools::SignedFloodFillOp::operator()
void operator()(NodeT &node) const
Definition: SignedFloodFill.h:172
openvdb::v5_1::math::negative
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:108
openvdb::v5_1::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:58
openvdb::v5_1::tools::SignedFloodFillOp::RootT
typename TreeOrLeafManagerT::RootNodeType RootT
Definition: SignedFloodFill.h:112
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
openvdb::v5_1::tools::SignedFloodFillOp::LeafT
typename TreeOrLeafManagerT::LeafNodeType LeafT
Definition: SignedFloodFill.h:113
openvdb::v5_1::Int32
int32_t Int32
Definition: Types.h:63
openvdb
Definition: Exceptions.h:40
openvdb::v5_1::TypeError
Definition: Exceptions.h:91
openvdb::v5_1::tools::SignedFloodFillOp::SignedFloodFillOp
SignedFloodFillOp(const TreeOrLeafManagerT &tree, Index minLevel=0)
Definition: SignedFloodFill.h:117
openvdb::v5_1::tools::SignedFloodFillOp::SignedFloodFillOp
SignedFloodFillOp(ValueT outsideValue, ValueT insideValue, Index minLevel=0)
Definition: SignedFloodFill.h:124
version.h
Library and file format version numbers.
openvdb::v5_1::tools::SignedFloodFillOp::operator()
void operator()(LeafT &leaf) const
Definition: SignedFloodFill.h:132
openvdb::v5_1::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:51
openvdb::v5_1::tools::signedFloodFill
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:294
openvdb::v5_1::tools::SignedFloodFillOp::operator()
void operator()(RootT &root) const
Definition: SignedFloodFill.h:209
openvdb::v5_1::Index
Index32 Index
Definition: Types.h:61
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
openvdb::v5_1::tools::SignedFloodFillOp
Definition: SignedFloodFill.h:108
openvdb::v5_1::tools::SignedFloodFillOp::ValueT
typename TreeOrLeafManagerT::ValueType ValueT
Definition: SignedFloodFill.h:111