OpenVDB 3.2.0

RootNode.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2016 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 //
34
35 #ifndef OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
36 #define OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
37
38 #include <map>
39 #include <set>
40 #include <sstream>
41 #include <deque>
42 #include <boost/type_traits/remove_const.hpp>
43 #include <boost/type_traits/remove_pointer.hpp>
44 #include <boost/type_traits/is_pointer.hpp>
45 #include <boost/type_traits/is_const.hpp>
46 #include <boost/mpl/contains.hpp>
47 #include <boost/mpl/if.hpp>
48 #include <boost/mpl/vector.hpp>//for boost::mpl::vector
49 #include <boost/mpl/at.hpp>
50 #include <boost/mpl/push_back.hpp>
51 #include <boost/mpl/size.hpp>
52 #include <tbb/parallel_for.h>
53 #include <openvdb/Exceptions.h>
54 #include <openvdb/Types.h>
55 #include <openvdb/io/Compression.h> // for truncateRealToHalf()
56 #include <openvdb/math/Math.h> // for isZero(), isExactlyEqual(), etc.
57 #include <openvdb/math/BBox.h>
58 #include <openvdb/util/NodeMasks.h> // for backward compatibility only (see readTopology())
59 #include <openvdb/version.h>
60
61
62 namespace openvdb {
63 OPENVDB_USE_VERSION_NAMESPACE
64 namespace OPENVDB_VERSION_NAME {
65 namespace tree {
66
67 // Forward declarations
68 template<typename HeadType, int HeadLevel> struct NodeChain;
69 template<typename, typename> struct SameRootConfig;
70 template<typename, typename, bool> struct RootNodeCopyHelper;
71 template<typename, typename, typename, bool> struct RootNodeCombineHelper;
72
73
74 template<typename ChildType>
75 class RootNode
76 {
77 public:
78 typedef ChildType ChildNodeType;
79 typedef typename ChildType::LeafNodeType LeafNodeType;
80 typedef typename ChildType::ValueType ValueType;
81 typedef typename ChildType::BuildType BuildType;
82
83 static const Index LEVEL = 1 + ChildType::LEVEL; // level 0 = leaf
84
86 typedef typename NodeChain<RootNode, LEVEL>::Type NodeChainType;
87 BOOST_STATIC_ASSERT(boost::mpl::size<NodeChainType>::value == LEVEL + 1);
88
91 template<typename OtherValueType>
92 struct ValueConverter {
93 typedef RootNode<typename ChildType::template ValueConverter<OtherValueType>::Type> Type;
94 };
95
99 template<typename OtherNodeType>
100 struct SameConfiguration {
101 static const bool value = SameRootConfig<ChildNodeType, OtherNodeType>::value;
102 };
103
104
106 RootNode();
107
109 explicit RootNode(const ValueType& background);
110
111 RootNode(const RootNode& other) { *this = other; }
112
119 template<typename OtherChildType>
120 explicit RootNode(const RootNode<OtherChildType>& other) { *this = other; }
121
130 template<typename OtherChildType>
131 RootNode(const RootNode<OtherChildType>& other,
132 const ValueType& background, const ValueType& foreground, TopologyCopy);
133
144 template<typename OtherChildType>
145 RootNode(const RootNode<OtherChildType>& other, const ValueType& background, TopologyCopy);
146
148 RootNode& operator=(const RootNode& other);
156 template<typename OtherChildType>
157 RootNode& operator=(const RootNode<OtherChildType>& other);
158
159 ~RootNode() { this->clear(); }
160
161 private:
162 struct Tile {
163 Tile(): value(zeroVal<ValueType>()), active(false) {}
164 Tile(const ValueType& v, bool b): value(v), active(b) {}
165 ValueType value;
166 bool active;
167 };
168
169 // This lightweight struct pairs child pointers and tiles.
170 struct NodeStruct {
171 ChildType* child;
172 Tile tile;
173
174 NodeStruct(): child(NULL) {}
175 NodeStruct(ChildType& c): child(&c) {}
176 NodeStruct(const Tile& t): child(NULL), tile(t) {}
177 ~NodeStruct() {}
178
179 bool isChild() const { return child != NULL; }
180 bool isTile() const { return child == NULL; }
181 bool isTileOff() const { return isTile() && !tile.active; }
182 bool isTileOn() const { return isTile() && tile.active; }
183
184 void set(ChildType& c) { delete child; child = &c; }
185 void set(const Tile& t) { delete child; child = NULL; tile = t; }
186 ChildType& steal(const Tile& t) { ChildType* c = child; child = NULL; tile = t; return *c; }
187 };
188
189 typedef std::map<Coord, NodeStruct> MapType;
190 typedef typename MapType::iterator MapIter;
191 typedef typename MapType::const_iterator MapCIter;
192
193 typedef std::set<Coord> CoordSet;
194 typedef typename CoordSet::iterator CoordSetIter;
195 typedef typename CoordSet::const_iterator CoordSetCIter;
196
197 static void setTile(const MapIter& i, const Tile& t) { i->second.set(t); }
198 static void setChild(const MapIter& i, ChildType& c) { i->second.set(c); }
199 static Tile& getTile(const MapIter& i) { return i->second.tile; }
200 static const Tile& getTile(const MapCIter& i) { return i->second.tile; }
201 static ChildType& getChild(const MapIter& i) { return *(i->second.child); }
202 static const ChildType& getChild(const MapCIter& i) { return *(i->second.child); }
203 static ChildType& stealChild(const MapIter& i, const Tile& t) {return i->second.steal(t);}
204 static const ChildType& stealChild(const MapCIter& i,const Tile& t) {return i->second.steal(t);}
205
206 static bool isChild(const MapCIter& i) { return i->second.isChild(); }
207 static bool isChild(const MapIter& i) { return i->second.isChild(); }
208 static bool isTile(const MapCIter& i) { return i->second.isTile(); }
209 static bool isTile(const MapIter& i) { return i->second.isTile(); }
210 static bool isTileOff(const MapCIter& i) { return i->second.isTileOff(); }
211 static bool isTileOff(const MapIter& i) { return i->second.isTileOff(); }
212 static bool isTileOn(const MapCIter& i) { return i->second.isTileOn(); }
213 static bool isTileOn(const MapIter& i) { return i->second.isTileOn(); }
214
215 struct NullPred {
216 static inline bool test(const MapIter&) { return true; }
217 static inline bool test(const MapCIter&) { return true; }
218 };
219 struct ValueOnPred {
220 static inline bool test(const MapIter& i) { return isTileOn(i); }
221 static inline bool test(const MapCIter& i) { return isTileOn(i); }
222 };
223 struct ValueOffPred {
224 static inline bool test(const MapIter& i) { return isTileOff(i); }
225 static inline bool test(const MapCIter& i) { return isTileOff(i); }
226 };
227 struct ValueAllPred {
228 static inline bool test(const MapIter& i) { return isTile(i); }
229 static inline bool test(const MapCIter& i) { return isTile(i); }
230 };
231 struct ChildOnPred {
232 static inline bool test(const MapIter& i) { return isChild(i); }
233 static inline bool test(const MapCIter& i) { return isChild(i); }
234 };
235 struct ChildOffPred {
236 static inline bool test(const MapIter& i) { return isTile(i); }
237 static inline bool test(const MapCIter& i) { return isTile(i); }
238 };
239
240 template<typename _RootNodeT, typename _MapIterT, typename FilterPredT>
241 class BaseIter
242 {
243 public:
244 typedef _RootNodeT RootNodeT;
245 typedef _MapIterT MapIterT; // either MapIter or MapCIter
246
247 bool operator==(const BaseIter& other) const
248 {
249 return (mParentNode == other.mParentNode) && (mIter == other.mIter);
250 }
251 bool operator!=(const BaseIter& other) const { return !(*this == other); }
252
253 RootNodeT* getParentNode() const { return mParentNode; }
255 RootNodeT& parent() const
256 {
257 if (!mParentNode) OPENVDB_THROW(ValueError, "iterator references a null parent node");
258 return *mParentNode;
259 }
260
261 bool test() const { assert(mParentNode); return mIter != mParentNode->mTable.end(); }
262 operator bool() const { return this->test(); }
263
264 void increment() { ++mIter; this->skip(); }
265 bool next() { this->increment(); return this->test(); }
266 void increment(Index n) { for (int i = 0; i < n && this->next(); ++i) {} }
267
270 Index pos() const
271 {
272 return !mParentNode ? 0U : Index(std::distance(mParentNode->mTable.begin(), mIter));
273 }
274
275 bool isValueOn() const { return RootNodeT::isTileOn(mIter); }
276 bool isValueOff() const { return RootNodeT::isTileOff(mIter); }
277 void setValueOn(bool on = true) const { mIter->second.tile.active = on; }
278 void setValueOff() const { mIter->second.tile.active = false; }
279
281 Coord getCoord() const { return mIter->first; }
283 void getCoord(Coord& xyz) const { xyz = this->getCoord(); }
284
285 protected:
286 BaseIter(): mParentNode(NULL) {}
287 BaseIter(RootNodeT& parent, const MapIterT& iter): mParentNode(&parent), mIter(iter) {}
288
289 void skip() { while (this->test() && !FilterPredT::test(mIter)) ++mIter; }
290
291 RootNodeT* mParentNode;
292 MapIterT mIter;
293 }; // BaseIter
294
295 template<typename RootNodeT, typename MapIterT, typename FilterPredT, typename ChildNodeT>
296 class ChildIter: public BaseIter<RootNodeT, MapIterT, FilterPredT>
297 {
298 public:
299 typedef BaseIter<RootNodeT, MapIterT, FilterPredT> BaseT;
300 typedef RootNodeT NodeType;
301 typedef NodeType ValueType;
302 typedef ChildNodeT ChildNodeType;
303 typedef typename boost::remove_const<NodeType>::type NonConstNodeType;
304 typedef typename boost::remove_const<ValueType>::type NonConstValueType;
305 typedef typename boost::remove_const<ChildNodeType>::type NonConstChildNodeType;
306 using BaseT::mIter;
307
308 ChildIter() {}
309 ChildIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) { BaseT::skip(); }
310
311 ChildIter& operator++() { BaseT::increment(); return *this; }
312
313 ChildNodeT& getValue() const { return getChild(mIter); }
314 ChildNodeT& operator*() const { return this->getValue(); }
315 ChildNodeT* operator->() const { return &this->getValue(); }
316 }; // ChildIter
317
318 template<typename RootNodeT, typename MapIterT, typename FilterPredT, typename ValueT>
319 class ValueIter: public BaseIter<RootNodeT, MapIterT, FilterPredT>
320 {
321 public:
322 typedef BaseIter<RootNodeT, MapIterT, FilterPredT> BaseT;
323 typedef RootNodeT NodeType;
324 typedef ValueT ValueType;
325 typedef typename boost::remove_const<NodeType>::type NonConstNodeType;
326 typedef typename boost::remove_const<ValueT>::type NonConstValueType;
327 using BaseT::mIter;
328
329 ValueIter() {}
330 ValueIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) { BaseT::skip(); }
331
332 ValueIter& operator++() { BaseT::increment(); return *this; }
333
334 ValueT& getValue() const { return getTile(mIter).value; }
335 ValueT& operator*() const { return this->getValue(); }
336 ValueT* operator->() const { return &(this->getValue()); }
337
338 void setValue(const ValueT& v) const { assert(isTile(mIter)); getTile(mIter).value = v; }
339
340 template<typename ModifyOp>
341 void modifyValue(const ModifyOp& op) const
342 {
343 assert(isTile(mIter));
344 op(getTile(mIter).value);
345 }
346 }; // ValueIter
347
348 template<typename RootNodeT, typename MapIterT, typename ChildNodeT, typename ValueT>
349 class DenseIter: public BaseIter<RootNodeT, MapIterT, NullPred>
350 {
351 public:
352 typedef BaseIter<RootNodeT, MapIterT, NullPred> BaseT;
353 typedef RootNodeT NodeType;
354 typedef ValueT ValueType;
355 typedef ChildNodeT ChildNodeType;
356 typedef typename boost::remove_const<NodeType>::type NonConstNodeType;
357 typedef typename boost::remove_const<ValueT>::type NonConstValueType;
358 typedef typename boost::remove_const<ChildNodeT>::type NonConstChildNodeType;
359 using BaseT::mIter;
360
361 DenseIter() {}
362 DenseIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) {}
363
364 DenseIter& operator++() { BaseT::increment(); return *this; }
365
366 bool isChildNode() const { return isChild(mIter); }
367
368 ChildNodeT* probeChild(NonConstValueType& value) const
369 {
370 if (isChild(mIter)) return &getChild(mIter);
371 value = getTile(mIter).value;
372 return NULL;
373 }
374 bool probeChild(ChildNodeT*& child, NonConstValueType& value) const
375 {
376 child = this->probeChild(value);
377 return child != NULL;
378 }
379 bool probeValue(NonConstValueType& value) const { return !this->probeChild(value); }
380
381 void setChild(ChildNodeT& c) const { RootNodeT::setChild(mIter, c); }
382 void setChild(ChildNodeT* c) const { assert(c != NULL); RootNodeT::setChild(mIter, *c); }
383 void setValue(const ValueT& v) const
384 {
385 if (isTile(mIter)) getTile(mIter).value = v;
389 else stealChild(mIter, Tile(v, /*active=*/true));
390 }
391 }; // DenseIter
392
393 public:
394 typedef ChildIter<RootNode, MapIter, ChildOnPred, ChildType> ChildOnIter;
395 typedef ChildIter<const RootNode, MapCIter, ChildOnPred, const ChildType> ChildOnCIter;
396 typedef ValueIter<RootNode, MapIter, ChildOffPred, const ValueType> ChildOffIter;
397 typedef ValueIter<const RootNode, MapCIter, ChildOffPred, ValueType> ChildOffCIter;
398 typedef DenseIter<RootNode, MapIter, ChildType, ValueType> ChildAllIter;
399 typedef DenseIter<const RootNode, MapCIter, const ChildType, const ValueType> ChildAllCIter;
400
401 typedef ValueIter<RootNode, MapIter, ValueOnPred, ValueType> ValueOnIter;
402 typedef ValueIter<const RootNode, MapCIter, ValueOnPred, const ValueType> ValueOnCIter;
403 typedef ValueIter<RootNode, MapIter, ValueOffPred, ValueType> ValueOffIter;
404 typedef ValueIter<const RootNode, MapCIter, ValueOffPred, const ValueType> ValueOffCIter;
405 typedef ValueIter<RootNode, MapIter, ValueAllPred, ValueType> ValueAllIter;
406 typedef ValueIter<const RootNode, MapCIter, ValueAllPred, const ValueType> ValueAllCIter;
407
408
409 ChildOnCIter cbeginChildOn() const { return ChildOnCIter(*this, mTable.begin()); }
410 ChildOffCIter cbeginChildOff() const { return ChildOffCIter(*this, mTable.begin()); }
411 ChildAllCIter cbeginChildAll() const { return ChildAllCIter(*this, mTable.begin()); }
412 ChildOnCIter beginChildOn() const { return cbeginChildOn(); }
413 ChildOffCIter beginChildOff() const { return cbeginChildOff(); }
414 ChildAllCIter beginChildAll() const { return cbeginChildAll(); }
415 ChildOnIter beginChildOn() { return ChildOnIter(*this, mTable.begin()); }
416 ChildOffIter beginChildOff() { return ChildOffIter(*this, mTable.begin()); }
417 ChildAllIter beginChildAll() { return ChildAllIter(*this, mTable.begin()); }
418
419 ValueOnCIter cbeginValueOn() const { return ValueOnCIter(*this, mTable.begin()); }
420 ValueOffCIter cbeginValueOff() const { return ValueOffCIter(*this, mTable.begin()); }
421 ValueAllCIter cbeginValueAll() const { return ValueAllCIter(*this, mTable.begin()); }
422 ValueOnCIter beginValueOn() const { return cbeginValueOn(); }
423 ValueOffCIter beginValueOff() const { return cbeginValueOff(); }
424 ValueAllCIter beginValueAll() const { return cbeginValueAll(); }
425 ValueOnIter beginValueOn() { return ValueOnIter(*this, mTable.begin()); }
426 ValueOffIter beginValueOff() { return ValueOffIter(*this, mTable.begin()); }
427 ValueAllIter beginValueAll() { return ValueAllIter(*this, mTable.begin()); }
428
430 Index64 memUsage() const;
431
437 void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
438
440 static CoordBBox getNodeBoundingBox() { return CoordBBox::inf(); }
441
454 void setBackground(const ValueType& value, bool updateChildNodes);
455
457 const ValueType& background() const { return mBackground; }
458
460 bool isBackgroundTile(const Tile&) const;
462 bool isBackgroundTile(const MapIter&) const;
464 bool isBackgroundTile(const MapCIter&) const;
466
468 size_t numBackgroundTiles() const;
471 size_t eraseBackgroundTiles();
472 inline void clear();
473
475 bool empty() const { return mTable.size() == numBackgroundTiles(); }
476
480 bool expand(const Coord& xyz);
481
482 static Index getLevel() { return LEVEL; }
483 static void getNodeLog2Dims(std::vector<Index>& dims);
484 static Index getChildDim() { return ChildType::DIM; }
485
487 Index getTableSize() const { return static_cast<Index>(mTable.size()); }
488
489 Index getWidth() const { return this->getMaxIndex()[0] - this->getMinIndex()[0]; }
490 Index getHeight() const { return this->getMaxIndex()[1] - this->getMinIndex()[1]; }
491 Index getDepth() const { return this->getMaxIndex()[2] - this->getMinIndex()[2]; }
492
494 Coord getMinIndex() const;
496 Coord getMaxIndex() const;
498 void getIndexRange(CoordBBox& bbox) const;
499
502 template<typename OtherChildType>
503 bool hasSameTopology(const RootNode<OtherChildType>& other) const;
504
506 template<typename OtherChildType>
507 static bool hasSameConfiguration(const RootNode<OtherChildType>& other);
508
511 template<typename OtherChildType>
512 static bool hasCompatibleValueType(const RootNode<OtherChildType>& other);
513
514 Index32 leafCount() const;
515 Index32 nonLeafCount() const;
516 Index64 onVoxelCount() const;
517 Index64 offVoxelCount() const;
518 Index64 onLeafVoxelCount() const;
519 Index64 offLeafVoxelCount() const;
520 Index64 onTileCount() const;
521
522 bool isValueOn(const Coord& xyz) const;
523
524 bool hasActiveTiles() const;
525
526 const ValueType& getValue(const Coord& xyz) const;
527 bool probeValue(const Coord& xyz, ValueType& value) const;
528
532 int getValueDepth(const Coord& xyz) const;
533
535 void setActiveState(const Coord& xyz, bool on);
537 void setValueOnly(const Coord& xyz, const ValueType& value);
539 void setValueOn(const Coord& xyz, const ValueType& value);
541 void setValueOff(const Coord& xyz);
543 void setValueOff(const Coord& xyz, const ValueType& value);
544
547 template<typename ModifyOp>
548 void modifyValue(const Coord& xyz, const ModifyOp& op);
550 template<typename ModifyOp>
551 void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op);
552
554 void fill(const CoordBBox& bbox, const ValueType& value, bool active = true);
563 void sparseFill(const CoordBBox& bbox, const ValueType& value, bool active = true)
564 {
565 this->fill(bbox, value, active);
566 }
568
578 void denseFill(const CoordBBox& bbox, const ValueType& value, bool active = true);
579
585 template<typename DenseT>
586 void copyToDense(const CoordBBox& bbox, DenseT& dense) const;
587
588
589 //
590 // I/O
591 //
592 bool writeTopology(std::ostream&, bool toHalf = false) const;
593 bool readTopology(std::istream&, bool fromHalf = false);
594
595 void writeBuffers(std::ostream&, bool toHalf = false) const;
596 void readBuffers(std::istream&, bool fromHalf = false);
597 void readBuffers(std::istream&, const CoordBBox&, bool fromHalf = false);
598
599
600 //
601 // Voxel access
602 //
607 template<typename AccessorT>
608 const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const;
613 template<typename AccessorT>
614 bool isValueOnAndCache(const Coord& xyz, AccessorT&) const;
615
620 template<typename AccessorT>
621 void setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
622
627 template<typename AccessorT>
628 void setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
629
635 template<typename ModifyOp, typename AccessorT>
636 void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
637
642 template<typename ModifyOp, typename AccessorT>
643 void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&);
644
649 template<typename AccessorT>
650 void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&);
651
656 template<typename AccessorT>
657 void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&);
658
664 template<typename AccessorT>
665 bool probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT&) const;
666
672 template<typename AccessorT>
673 int getValueDepthAndCache(const Coord& xyz, AccessorT&) const;
674
676 void clip(const CoordBBox&);
677
683 void prune(const ValueType& tolerance = zeroVal<ValueType>());
684
687 void addLeaf(LeafNodeType* leaf);
688
691 template<typename AccessorT>
692 void addLeafAndCache(LeafNodeType* leaf, AccessorT&);
693
702 template<typename NodeT>
703 NodeT* stealNode(const Coord& xyz, const ValueType& value, bool state);
704
707 void addTile(const Coord& xyz, const ValueType& value, bool state);
708
712 void addTile(Index level, const Coord& xyz, const ValueType& value, bool state);
713
716 template<typename AccessorT>
717 void addTileAndCache(Index level, const Coord& xyz, const ValueType&, bool state, AccessorT&);
718
724 LeafNodeType* touchLeaf(const Coord& xyz);
725
728 template<typename AccessorT>
729 LeafNodeType* touchLeafAndCache(const Coord& xyz, AccessorT& acc);
730
732 template <typename NodeT>
735 NodeT* probeNode(const Coord& xyz);
736 template <typename NodeT>
737 const NodeT* probeConstNode(const Coord& xyz) const;
739
741 template<typename NodeT, typename AccessorT>
744 NodeT* probeNodeAndCache(const Coord& xyz, AccessorT& acc);
745 template<typename NodeT, typename AccessorT>
746 const NodeT* probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const;
748
750 LeafNodeType* probeLeaf(const Coord& xyz);
753 const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
754 const LeafNodeType* probeLeaf(const Coord& xyz) const;
756
758 template<typename AccessorT>
761 LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc);
762 template<typename AccessorT>
763 const LeafNodeType* probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const;
764 template<typename AccessorT>
765 const LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc) const;
767
768
769 //
770 // Aux methods
771 //
772
774 template<typename ArrayT> void getNodes(ArrayT& array);
797 template<typename ArrayT> void getNodes(ArrayT& array) const;
799
801 template<typename ArrayT>
825 void stealNodes(ArrayT& array, const ValueType& value, bool state);
826 template<typename ArrayT>
827 void stealNodes(ArrayT& array) { this->stealNodes(array, mBackground, false); }
829
836 void voxelizeActiveTiles(bool threaded = true);
837
845 template<MergePolicy Policy> void merge(RootNode& other);
846
860 template<typename OtherChildType>
861 void topologyUnion(const RootNode<OtherChildType>& other);
862
876 template<typename OtherChildType>
877 void topologyIntersection(const RootNode<OtherChildType>& other);
878
889 template<typename OtherChildType>
890 void topologyDifference(const RootNode<OtherChildType>& other);
891
892 template<typename CombineOp>
893 void combine(RootNode& other, CombineOp&, bool prune = false);
894
895 template<typename CombineOp, typename OtherRootNode /*= RootNode*/>
896 void combine2(const RootNode& other0, const OtherRootNode& other1,
897 CombineOp& op, bool prune = false);
898
904 template<typename BBoxOp> void visitActiveBBox(BBoxOp&) const;
905
906 template<typename VisitorOp> void visit(VisitorOp&);
907 template<typename VisitorOp> void visit(VisitorOp&) const;
908
909 template<typename OtherRootNodeType, typename VisitorOp>
910 void visit2(OtherRootNodeType& other, VisitorOp&);
911 template<typename OtherRootNodeType, typename VisitorOp>
912 void visit2(OtherRootNodeType& other, VisitorOp&) const;
913
914 private:
917 template<typename> friend class RootNode;
918
919 template<typename, typename, bool> friend struct RootNodeCopyHelper;
920 template<typename, typename, typename, bool> friend struct RootNodeCombineHelper;
921
923 void initTable() {}
925 void resetTable(MapType& table) { mTable.swap(table); table.clear(); }
927 void resetTable(const MapType&) const {}
929
930 Index getChildCount() const;
931 Index getTileCount() const;
932 Index getActiveTileCount() const;
933 Index getInactiveTileCount() const;
934
936 static Coord coordToKey(const Coord& xyz) { return xyz & ~(ChildType::DIM - 1); }
937
939 void insertKeys(CoordSet&) const;
940
942 bool hasKey(const Coord& key) const { return mTable.find(key) != mTable.end(); }
944 MapIter findKey(const Coord& key) { return mTable.find(key); }
947 MapCIter findKey(const Coord& key) const { return mTable.find(key); }
949
950 MapIter findCoord(const Coord& xyz) { return mTable.find(coordToKey(xyz)); }
953 MapCIter findCoord(const Coord& xyz) const { return mTable.find(coordToKey(xyz)); }
955 MapIter findOrAddCoord(const Coord& xyz);
959
964 template<typename OtherChildType>
965 static void enforceSameConfiguration(const RootNode<OtherChildType>& other);
966
972 template<typename OtherChildType>
973 static void enforceCompatibleValueTypes(const RootNode<OtherChildType>& other);
974
975 template<typename CombineOp, typename OtherRootNode /*= RootNode*/>
976 void doCombine2(const RootNode&, const OtherRootNode&, CombineOp&, bool prune);
977
978 template<typename RootNodeT, typename VisitorOp, typename ChildAllIterT>
979 static inline void doVisit(RootNodeT&, VisitorOp&);
980
981 template<typename RootNodeT, typename OtherRootNodeT, typename VisitorOp,
982 typename ChildAllIterT, typename OtherChildAllIterT>
983 static inline void doVisit2(RootNodeT&, OtherRootNodeT&, VisitorOp&);
984
985
986 MapType mTable;
987 ValueType mBackground;
988 }; // end of RootNode class
989
990
992
993
1014 template<typename HeadT, int HeadLevel>
1015 struct NodeChain {
1016 typedef typename NodeChain<typename HeadT::ChildNodeType, HeadLevel-1>::Type SubtreeT;
1017 typedef typename boost::mpl::push_back<SubtreeT, HeadT>::type Type;
1018 };
1019
1021 template<typename HeadT>
1022 struct NodeChain<HeadT, /*HeadLevel=*/1> {
1023 typedef typename boost::mpl::vector<typename HeadT::ChildNodeType, HeadT>::type Type;
1024 };
1025
1026
1028
1029
1031 template<typename ChildT1, typename NodeT2>
1034 struct SameRootConfig {
1035 static const bool value = false;
1036 };
1037
1038 template<typename ChildT1, typename ChildT2>
1039 struct SameRootConfig<ChildT1, RootNode<ChildT2> > {
1040 static const bool value = ChildT1::template SameConfiguration<ChildT2>::value;
1041 };
1043
1044
1046
1047
1048 template<typename ChildT>
1049 inline
1050 RootNode<ChildT>::RootNode(): mBackground(zeroVal<ValueType>())
1051 {
1052 this->initTable();
1053 }
1054
1055
1056 template<typename ChildT>
1057 inline
1058 RootNode<ChildT>::RootNode(const ValueType& background): mBackground(background)
1059 {
1060 this->initTable();
1061 }
1062
1063
1064 template<typename ChildT>
1065 template<typename OtherChildType>
1066 inline
1067 RootNode<ChildT>::RootNode(const RootNode<OtherChildType>& other,
1068 const ValueType& backgd, const ValueType& foregd, TopologyCopy):
1069 mBackground(backgd)
1070 {
1071 typedef RootNode<OtherChildType> OtherRootT;
1072
1073 enforceSameConfiguration(other);
1074
1075 const Tile bgTile(backgd, /*active=*/false), fgTile(foregd, true);
1076 this->initTable();
1077
1078 for (typename OtherRootT::MapCIter i=other.mTable.begin(), e=other.mTable.end(); i != e; ++i) {
1079 mTable[i->first] = OtherRootT::isTile(i)
1080 ? NodeStruct(OtherRootT::isTileOn(i) ? fgTile : bgTile)
1081 : NodeStruct(*(new ChildT(OtherRootT::getChild(i), backgd, foregd, TopologyCopy())));
1082 }
1083 }
1084
1085
1086 template<typename ChildT>
1087 template<typename OtherChildType>
1088 inline
1089 RootNode<ChildT>::RootNode(const RootNode<OtherChildType>& other,
1090 const ValueType& backgd, TopologyCopy):
1091 mBackground(backgd)
1092 {
1093 typedef RootNode<OtherChildType> OtherRootT;
1094
1095 enforceSameConfiguration(other);
1096
1097 const Tile bgTile(backgd, /*active=*/false), fgTile(backgd, true);
1098 this->initTable();
1099 for (typename OtherRootT::MapCIter i=other.mTable.begin(), e=other.mTable.end(); i != e; ++i) {
1100 mTable[i->first] = OtherRootT::isTile(i)
1101 ? NodeStruct(OtherRootT::isTileOn(i) ? fgTile : bgTile)
1102 : NodeStruct(*(new ChildT(OtherRootT::getChild(i), backgd, TopologyCopy())));
1103 }
1104 }
1105
1106
1108
1109
1110 // This helper class is a friend of RootNode and is needed so that assignment
1111 // with value conversion can be specialized for compatible and incompatible
1112 // pairs of RootNode types.
1113 template<typename RootT, typename OtherRootT, bool Compatible = false>
1114 struct RootNodeCopyHelper
1115 {
1116 static inline void copyWithValueConversion(RootT& self, const OtherRootT& other)
1117 {
1118 // If the two root nodes have different configurations or incompatible ValueTypes,
1119 // throw an exception.
1120 self.enforceSameConfiguration(other);
1121 self.enforceCompatibleValueTypes(other);
1122 // One of the above two tests should throw, so we should never get here:
1123 std::ostringstream ostr;
1124 ostr << "cannot convert a " << typeid(OtherRootT).name()
1125 << " to a " << typeid(RootT).name();
1126 OPENVDB_THROW(TypeError, ostr.str());
1127 }
1128 };
1129
1130 // Specialization for root nodes of compatible types
1131 template<typename RootT, typename OtherRootT>
1132 struct RootNodeCopyHelper<RootT, OtherRootT, /*Compatible=*/true>
1133 {
1134 static inline void copyWithValueConversion(RootT& self, const OtherRootT& other)
1135 {
1136 typedef typename RootT::ValueType ValueT;
1137 typedef typename RootT::ChildNodeType ChildT;
1138 typedef typename RootT::NodeStruct NodeStruct;
1139 typedef typename RootT::Tile Tile;
1140 typedef typename OtherRootT::ValueType OtherValueT;
1141 typedef typename OtherRootT::MapCIter OtherMapCIter;
1142 typedef typename OtherRootT::Tile OtherTile;
1143
1144 struct Local {
1146 static inline ValueT convertValue(const OtherValueT& val) { return ValueT(val); }
1147 };
1148
1149 self.mBackground = Local::convertValue(other.mBackground);
1150
1151 self.clear();
1152 self.initTable();
1153
1154 for (OtherMapCIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
1155 if (other.isTile(i)) {
1156 // Copy the other node's tile, but convert its value to this node's ValueType.
1157 const OtherTile& otherTile = other.getTile(i);
1158 self.mTable[i->first] = NodeStruct(
1159 Tile(Local::convertValue(otherTile.value), otherTile.active));
1160 } else {
1161 // Copy the other node's child, but convert its values to this node's ValueType.
1162 self.mTable[i->first] = NodeStruct(*(new ChildT(other.getChild(i))));
1163 }
1164 }
1165 }
1166 };
1167
1168
1169 // Overload for root nodes of the same type as this node
1170 template<typename ChildT>
1171 inline RootNode<ChildT>&
1172 RootNode<ChildT>::operator=(const RootNode& other)
1173 {
1174 if (&other != this) {
1175 mBackground = other.mBackground;
1176
1177 this->clear();
1178 this->initTable();
1179
1180 for (MapCIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
1181 mTable[i->first] =
1182 isTile(i) ? NodeStruct(getTile(i)) : NodeStruct(*(new ChildT(getChild(i))));
1183 }
1184 }
1185 return *this;
1186 }
1187
1188 // Overload for root nodes of different types
1189 template<typename ChildT>
1190 template<typename OtherChildType>
1191 inline RootNode<ChildT>&
1192 RootNode<ChildT>::operator=(const RootNode<OtherChildType>& other)
1193 {
1194 typedef RootNode<OtherChildType> OtherRootT;
1195 typedef typename OtherRootT::ValueType OtherValueT;
1196 static const bool compatible = (SameConfiguration<OtherRootT>::value
1197 && CanConvertType</*from=*/OtherValueT, /*to=*/ValueType>::value);
1198 RootNodeCopyHelper<RootNode, OtherRootT, compatible>::copyWithValueConversion(*this, other);
1199 return *this;
1200 }
1201
1202
1204
1205 template<typename ChildT>
1206 inline void
1207 RootNode<ChildT>::setBackground(const ValueType& background, bool updateChildNodes)
1208 {
1209 if (math::isExactlyEqual(background, mBackground)) return;
1210
1211 if (updateChildNodes) {
1212 // Traverse the tree, replacing occurrences of mBackground with background
1213 // and -mBackground with -background.
1214 for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
1215 ChildT *child = iter->second.child;
1216 if (child) {
1217 child->resetBackground(/*old=*/mBackground, /*new=*/background);
1218 } else {
1219 Tile& tile = getTile(iter);
1220 if (tile.active) continue;//only change inactive tiles
1221 if (math::isApproxEqual(tile.value, mBackground)) {
1222 tile.value = background;
1223 } else if (math::isApproxEqual(tile.value, math::negative(mBackground))) {
1224 tile.value = math::negative(background);
1225 }
1226 }
1227 }
1228 }
1229 mBackground = background;
1230 }
1231
1232 template<typename ChildT>
1233 inline bool
1234 RootNode<ChildT>::isBackgroundTile(const Tile& tile) const
1235 {
1236 return !tile.active && math::isApproxEqual(tile.value, mBackground);
1237 }
1238
1239 template<typename ChildT>
1240 inline bool
1241 RootNode<ChildT>::isBackgroundTile(const MapIter& iter) const
1242 {
1243 return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground);
1244 }
1245
1246 template<typename ChildT>
1247 inline bool
1248 RootNode<ChildT>::isBackgroundTile(const MapCIter& iter) const
1249 {
1250 return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground);
1251 }
1252
1253
1254 template<typename ChildT>
1255 inline size_t
1256 RootNode<ChildT>::numBackgroundTiles() const
1257 {
1258 size_t count = 0;
1259 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1260 if (this->isBackgroundTile(i)) ++count;
1261 }
1262 return count;
1263 }
1264
1265
1266 template<typename ChildT>
1267 inline size_t
1268 RootNode<ChildT>::eraseBackgroundTiles()
1269 {
1270 std::set<Coord> keysToErase;
1271 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1272 if (this->isBackgroundTile(i)) keysToErase.insert(i->first);
1273 }
1274 for (std::set<Coord>::iterator i = keysToErase.begin(), e = keysToErase.end(); i != e; ++i) {
1275 mTable.erase(*i);
1276 }
1277 return keysToErase.size();
1278 }
1279
1280
1282
1283
1284 template<typename ChildT>
1285 inline void
1286 RootNode<ChildT>::insertKeys(CoordSet& keys) const
1287 {
1288 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1289 keys.insert(i->first);
1290 }
1291 }
1292
1293
1294 template<typename ChildT>
1295 inline typename RootNode<ChildT>::MapIter
1296 RootNode<ChildT>::findOrAddCoord(const Coord& xyz)
1297 {
1298 const Coord key = coordToKey(xyz);
1299 std::pair<MapIter, bool> result = mTable.insert(
1300 typename MapType::value_type(key, NodeStruct(Tile(mBackground, /*active=*/false))));
1301 return result.first;
1302 }
1303
1304
1305 template<typename ChildT>
1306 inline bool
1307 RootNode<ChildT>::expand(const Coord& xyz)
1308 {
1309 const Coord key = coordToKey(xyz);
1310 std::pair<MapIter, bool> result = mTable.insert(
1311 typename MapType::value_type(key, NodeStruct(Tile(mBackground, /*active=*/false))));
1312 return result.second; // return true if the key did not already exist
1313 }
1314
1315
1317
1318
1319 template<typename ChildT>
1320 inline void
1321 RootNode<ChildT>::getNodeLog2Dims(std::vector<Index>& dims)
1322 {
1323 dims.push_back(0); // magic number; RootNode has no Log2Dim
1324 ChildT::getNodeLog2Dims(dims);
1325 }
1326
1327
1328 template<typename ChildT>
1329 inline Coord
1330 RootNode<ChildT>::getMinIndex() const
1331 {
1332 return mTable.empty() ? Coord(0) : mTable.begin()->first;
1333 }
1334
1335 template<typename ChildT>
1336 inline Coord
1337 RootNode<ChildT>::getMaxIndex() const
1338 {
1339 return mTable.empty() ? Coord(0) : mTable.rbegin()->first + Coord(ChildT::DIM - 1);
1340 }
1341
1342
1343 template<typename ChildT>
1344 inline void
1345 RootNode<ChildT>::getIndexRange(CoordBBox& bbox) const
1346 {
1347 bbox.min() = this->getMinIndex();
1348 bbox.max() = this->getMaxIndex();
1349 }
1350
1351
1353
1354
1355 template<typename ChildT>
1356 template<typename OtherChildType>
1357 inline bool
1358 RootNode<ChildT>::hasSameTopology(const RootNode<OtherChildType>& other) const
1359 {
1360 typedef RootNode<OtherChildType> OtherRootT;
1361 typedef typename OtherRootT::MapType OtherMapT;
1362 typedef typename OtherRootT::MapIter OtherIterT;
1363 typedef typename OtherRootT::MapCIter OtherCIterT;
1364
1365 if (!hasSameConfiguration(other)) return false;
1366
1367 // Create a local copy of the other node's table.
1368 OtherMapT copyOfOtherTable = other.mTable;
1369
1370 // For each entry in this node's table...
1371 for (MapCIter thisIter = mTable.begin(); thisIter != mTable.end(); ++thisIter) {
1372 if (this->isBackgroundTile(thisIter)) continue; // ignore background tiles
1373
1374 // Fail if there is no corresponding entry in the other node's table.
1375 OtherCIterT otherIter = other.findKey(thisIter->first);
1376 if (otherIter == other.mTable.end()) return false;
1377
1378 // Fail if this entry is a tile and the other is a child or vice-versa.
1379 if (isChild(thisIter)) {//thisIter points to a child
1380 if (OtherRootT::isTile(otherIter)) return false;
1381 // Fail if both entries are children, but the children have different topology.
1382 if (!getChild(thisIter).hasSameTopology(&OtherRootT::getChild(otherIter))) return false;
1383 } else {//thisIter points to a tile
1384 if (OtherRootT::isChild(otherIter)) return false;
1385 if (getTile(thisIter).active != OtherRootT::getTile(otherIter).active) return false;
1386 }
1387
1388 // Remove tiles and child nodes with matching topology from
1389 // the copy of the other node's table. This is required since
1390 // the two root tables can include an arbitrary number of
1391 // background tiles and still have the same topology!
1392 copyOfOtherTable.erase(otherIter->first);
1393 }
1394 // Fail if the remaining entries in copyOfOtherTable are not all background tiles.
1395 for (OtherIterT i = copyOfOtherTable.begin(), e = copyOfOtherTable.end(); i != e; ++i) {
1396 if (!other.isBackgroundTile(i)) return false;
1397 }
1398 return true;
1399 }
1400
1401
1402 template<typename ChildT>
1403 template<typename OtherChildType>
1404 inline bool
1405 RootNode<ChildT>::hasSameConfiguration(const RootNode<OtherChildType>&)
1406 {
1407 std::vector<Index> thisDims, otherDims;
1408 RootNode::getNodeLog2Dims(thisDims);
1409 RootNode<OtherChildType>::getNodeLog2Dims(otherDims);
1410 return (thisDims == otherDims);
1411 }
1412
1413
1414 template<typename ChildT>
1415 template<typename OtherChildType>
1416 inline void
1417 RootNode<ChildT>::enforceSameConfiguration(const RootNode<OtherChildType>&)
1418 {
1419 std::vector<Index> thisDims, otherDims;
1420 RootNode::getNodeLog2Dims(thisDims);
1421 RootNode<OtherChildType>::getNodeLog2Dims(otherDims);
1422 if (thisDims != otherDims) {
1423 std::ostringstream ostr;
1424 ostr << "grids have incompatible configurations (" << thisDims[0];
1425 for (size_t i = 1, N = thisDims.size(); i < N; ++i) ostr << " x " << thisDims[i];
1426 ostr << " vs. " << otherDims[0];
1427 for (size_t i = 1, N = otherDims.size(); i < N; ++i) ostr << " x " << otherDims[i];
1428 ostr << ")";
1429 OPENVDB_THROW(TypeError, ostr.str());
1430 }
1431 }
1432
1433
1434 template<typename ChildT>
1435 template<typename OtherChildType>
1436 inline bool
1437 RootNode<ChildT>::hasCompatibleValueType(const RootNode<OtherChildType>&)
1438 {
1439 typedef typename OtherChildType::ValueType OtherValueType;
1440 return CanConvertType</*from=*/OtherValueType, /*to=*/ValueType>::value;
1441 }
1442
1443
1444 template<typename ChildT>
1445 template<typename OtherChildType>
1446 inline void
1447 RootNode<ChildT>::enforceCompatibleValueTypes(const RootNode<OtherChildType>&)
1448 {
1449 typedef typename OtherChildType::ValueType OtherValueType;
1450 if (!CanConvertType</*from=*/OtherValueType, /*to=*/ValueType>::value) {
1451 std::ostringstream ostr;
1452 ostr << "values of type " << typeNameAsString<OtherValueType>()
1453 << " cannot be converted to type " << typeNameAsString<ValueType>();
1454 OPENVDB_THROW(TypeError, ostr.str());
1455 }
1456 }
1457
1458
1460
1461
1462 template<typename ChildT>
1463 inline Index64
1464 RootNode<ChildT>::memUsage() const
1465 {
1466 Index64 sum = sizeof(*this);
1467 for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
1468 if (const ChildT *child = iter->second.child) {
1469 sum += child->memUsage();
1470 }
1471 }
1472 return sum;
1473 }
1474
1475
1476 template<typename ChildT>
1477 inline void
1478 RootNode<ChildT>::clear()
1479 {
1480 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1481 delete i->second.child;
1482 }
1483 mTable.clear();
1484 }
1485
1486
1487 template<typename ChildT>
1488 inline void
1489 RootNode<ChildT>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1490 {
1491 for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
1492 if (const ChildT *child = iter->second.child) {
1493 child->evalActiveBoundingBox(bbox, visitVoxels);
1494 } else if (isTileOn(iter)) {
1495 bbox.expand(iter->first, ChildT::DIM);
1496 }
1497 }
1498 }
1499
1500
1501 template<typename ChildT>
1502 inline Index
1503 RootNode<ChildT>::getChildCount() const {
1504 Index sum = 0;
1505 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1506 if (isChild(i)) ++sum;
1507 }
1508 return sum;
1509 }
1510
1511
1512 template<typename ChildT>
1513 inline Index
1514 RootNode<ChildT>::getTileCount() const
1515 {
1516 Index sum = 0;
1517 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1518 if (isTile(i)) ++sum;
1519 }
1520 return sum;
1521 }
1522
1523
1524 template<typename ChildT>
1525 inline Index
1526 RootNode<ChildT>::getActiveTileCount() const
1527 {
1528 Index sum = 0;
1529 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1530 if (isTileOn(i)) ++sum;
1531 }
1532 return sum;
1533 }
1534
1535
1536 template<typename ChildT>
1537 inline Index
1538 RootNode<ChildT>::getInactiveTileCount() const
1539 {
1540 Index sum = 0;
1541 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1542 if (isTileOff(i)) ++sum;
1543 }
1544 return sum;
1545 }
1546
1547
1548 template<typename ChildT>
1549 inline Index32
1550 RootNode<ChildT>::leafCount() const
1551 {
1552 Index32 sum = 0;
1553 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1554 if (isChild(i)) sum += getChild(i).leafCount();
1555 }
1556 return sum;
1557 }
1558
1559
1560 template<typename ChildT>
1561 inline Index32
1562 RootNode<ChildT>::nonLeafCount() const
1563 {
1564 Index32 sum = 1;
1565 if (ChildT::LEVEL != 0) {
1566 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1567 if (isChild(i)) sum += getChild(i).nonLeafCount();
1568 }
1569 }
1570 return sum;
1571 }
1572
1573
1574 template<typename ChildT>
1575 inline Index64
1576 RootNode<ChildT>::onVoxelCount() const
1577 {
1578 Index64 sum = 0;
1579 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1580 if (isChild(i)) {
1581 sum += getChild(i).onVoxelCount();
1582 } else if (isTileOn(i)) {
1583 sum += ChildT::NUM_VOXELS;
1584 }
1585 }
1586 return sum;
1587 }
1588
1589
1590 template<typename ChildT>
1591 inline Index64
1592 RootNode<ChildT>::offVoxelCount() const
1593 {
1594 Index64 sum = 0;
1595 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1596 if (isChild(i)) {
1597 sum += getChild(i).offVoxelCount();
1598 } else if (isTileOff(i) && !this->isBackgroundTile(i)) {
1599 sum += ChildT::NUM_VOXELS;
1600 }
1601 }
1602 return sum;
1603 }
1604
1605
1606 template<typename ChildT>
1607 inline Index64
1608 RootNode<ChildT>::onLeafVoxelCount() const
1609 {
1610 Index64 sum = 0;
1611 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1612 if (isChild(i)) sum += getChild(i).onLeafVoxelCount();
1613 }
1614 return sum;
1615 }
1616
1617
1618 template<typename ChildT>
1619 inline Index64
1620 RootNode<ChildT>::offLeafVoxelCount() const
1621 {
1622 Index64 sum = 0;
1623 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1624 if (isChild(i)) sum += getChild(i).offLeafVoxelCount();
1625 }
1626 return sum;
1627 }
1628
1629 template<typename ChildT>
1630 inline Index64
1631 RootNode<ChildT>::onTileCount() const
1632 {
1633 Index64 sum = 0;
1634 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1635 if (isChild(i)) {
1636 sum += getChild(i).onTileCount();
1637 } else if (isTileOn(i)) {
1638 sum += 1;
1639 }
1640 }
1641 return sum;
1642 }
1643
1645
1646
1647 template<typename ChildT>
1648 inline bool
1649 RootNode<ChildT>::isValueOn(const Coord& xyz) const
1650 {
1651 MapCIter iter = this->findCoord(xyz);
1652 if (iter == mTable.end() || isTileOff(iter)) return false;
1653 return isTileOn(iter) ? true : getChild(iter).isValueOn(xyz);
1654 }
1655
1656 template<typename ChildT>
1657 inline bool
1658 RootNode<ChildT>::hasActiveTiles() const
1659 {
1660 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
1661 if (isChild(i) ? getChild(i).hasActiveTiles() : getTile(i).active) return true;
1662 }
1663 return false;
1664 }
1665
1666 template<typename ChildT>
1667 template<typename AccessorT>
1668 inline bool
1669 RootNode<ChildT>::isValueOnAndCache(const Coord& xyz, AccessorT& acc) const
1670 {
1671 MapCIter iter = this->findCoord(xyz);
1672 if (iter == mTable.end() || isTileOff(iter)) return false;
1673 if (isTileOn(iter)) return true;
1674 acc.insert(xyz, &getChild(iter));
1675 return getChild(iter).isValueOnAndCache(xyz, acc);
1676 }
1677
1678
1679 template<typename ChildT>
1680 inline const typename ChildT::ValueType&
1681 RootNode<ChildT>::getValue(const Coord& xyz) const
1682 {
1683 MapCIter iter = this->findCoord(xyz);
1684 return iter == mTable.end() ? mBackground
1685 : (isTile(iter) ? getTile(iter).value : getChild(iter).getValue(xyz));
1686 }
1687
1688 template<typename ChildT>
1689 template<typename AccessorT>
1690 inline const typename ChildT::ValueType&
1691 RootNode<ChildT>::getValueAndCache(const Coord& xyz, AccessorT& acc) const
1692 {
1693 MapCIter iter = this->findCoord(xyz);
1694 if (iter == mTable.end()) return mBackground;
1695 if (isChild(iter)) {
1696 acc.insert(xyz, &getChild(iter));
1697 return getChild(iter).getValueAndCache(xyz, acc);
1698 }
1699 return getTile(iter).value;
1700 }
1701
1702
1703 template<typename ChildT>
1704 inline int
1705 RootNode<ChildT>::getValueDepth(const Coord& xyz) const
1706 {
1707 MapCIter iter = this->findCoord(xyz);
1708 return iter == mTable.end() ? -1
1709 : (isTile(iter) ? 0 : int(LEVEL) - int(getChild(iter).getValueLevel(xyz)));
1710 }
1711
1712 template<typename ChildT>
1713 template<typename AccessorT>
1714 inline int
1715 RootNode<ChildT>::getValueDepthAndCache(const Coord& xyz, AccessorT& acc) const
1716 {
1717 MapCIter iter = this->findCoord(xyz);
1718 if (iter == mTable.end()) return -1;
1719 if (isTile(iter)) return 0;
1720 acc.insert(xyz, &getChild(iter));
1721 return int(LEVEL) - int(getChild(iter).getValueLevelAndCache(xyz, acc));
1722 }
1723
1724
1725 template<typename ChildT>
1726 inline void
1727 RootNode<ChildT>::setValueOff(const Coord& xyz)
1728 {
1729 MapIter iter = this->findCoord(xyz);
1730 if (iter != mTable.end() && !isTileOff(iter)) {
1731 if (isTileOn(iter)) {
1732 setChild(iter, *new ChildT(xyz, getTile(iter).value, /*active=*/true));
1733 }
1734 getChild(iter).setValueOff(xyz);
1735 }
1736 }
1737
1738
1739 template<typename ChildT>
1740 inline void
1741 RootNode<ChildT>::setActiveState(const Coord& xyz, bool on)
1742 {
1743 ChildT* child = NULL;
1744 MapIter iter = this->findCoord(xyz);
1745 if (iter == mTable.end()) {
1746 if (on) {
1747 child = new ChildT(xyz, mBackground);
1748 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1749 } else {
1750 // Nothing to do; (x, y, z) is background and therefore already inactive.
1751 }
1752 } else if (isChild(iter)) {
1753 child = &getChild(iter);
1754 } else if (on != getTile(iter).active) {
1755 child = new ChildT(xyz, getTile(iter).value, !on);
1756 setChild(iter, *child);
1757 }
1758 if (child) child->setActiveState(xyz, on);
1759 }
1760
1761 template<typename ChildT>
1762 template<typename AccessorT>
1763 inline void
1764 RootNode<ChildT>::setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& acc)
1765 {
1766 ChildT* child = NULL;
1767 MapIter iter = this->findCoord(xyz);
1768 if (iter == mTable.end()) {
1769 if (on) {
1770 child = new ChildT(xyz, mBackground);
1771 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1772 } else {
1773 // Nothing to do; (x, y, z) is background and therefore already inactive.
1774 }
1775 } else if (isChild(iter)) {
1776 child = &getChild(iter);
1777 } else if (on != getTile(iter).active) {
1778 child = new ChildT(xyz, getTile(iter).value, !on);
1779 setChild(iter, *child);
1780 }
1781 if (child) {
1782 acc.insert(xyz, child);
1783 child->setActiveStateAndCache(xyz, on, acc);
1784 }
1785 }
1786
1787
1788 template<typename ChildT>
1789 inline void
1790 RootNode<ChildT>::setValueOff(const Coord& xyz, const ValueType& value)
1791 {
1792 ChildT* child = NULL;
1793 MapIter iter = this->findCoord(xyz);
1794 if (iter == mTable.end()) {
1795 if (!math::isExactlyEqual(mBackground, value)) {
1796 child = new ChildT(xyz, mBackground);
1797 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1798 }
1799 } else if (isChild(iter)) {
1800 child = &getChild(iter);
1801 } else if (isTileOn(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1802 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1803 setChild(iter, *child);
1804 }
1805 if (child) child->setValueOff(xyz, value);
1806 }
1807
1808 template<typename ChildT>
1809 template<typename AccessorT>
1810 inline void
1811 RootNode<ChildT>::setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc)
1812 {
1813 ChildT* child = NULL;
1814 MapIter iter = this->findCoord(xyz);
1815 if (iter == mTable.end()) {
1816 if (!math::isExactlyEqual(mBackground, value)) {
1817 child = new ChildT(xyz, mBackground);
1818 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1819 }
1820 } else if (isChild(iter)) {
1821 child = &getChild(iter);
1822 } else if (isTileOn(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1823 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1824 setChild(iter, *child);
1825 }
1826 if (child) {
1827 acc.insert(xyz, child);
1828 child->setValueOffAndCache(xyz, value, acc);
1829 }
1830 }
1831
1832
1833 template<typename ChildT>
1834 inline void
1835 RootNode<ChildT>::setValueOn(const Coord& xyz, const ValueType& value)
1836 {
1837 ChildT* child = NULL;
1838 MapIter iter = this->findCoord(xyz);
1839 if (iter == mTable.end()) {
1840 child = new ChildT(xyz, mBackground);
1841 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1842 } else if (isChild(iter)) {
1843 child = &getChild(iter);
1844 } else if (isTileOff(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1845 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1846 setChild(iter, *child);
1847 }
1848 if (child) child->setValueOn(xyz, value);
1849 }
1850
1851 template<typename ChildT>
1852 template<typename AccessorT>
1853 inline void
1854 RootNode<ChildT>::setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc)
1855 {
1856 ChildT* child = NULL;
1857 MapIter iter = this->findCoord(xyz);
1858 if (iter == mTable.end()) {
1859 child = new ChildT(xyz, mBackground);
1860 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1861 } else if (isChild(iter)) {
1862 child = &getChild(iter);
1863 } else if (isTileOff(iter) || !math::isExactlyEqual(getTile(iter).value, value)) {
1864 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1865 setChild(iter, *child);
1866 }
1867 if (child) {
1868 acc.insert(xyz, child);
1869 child->setValueAndCache(xyz, value, acc);
1870 }
1871 }
1872
1873
1874 template<typename ChildT>
1875 inline void
1876 RootNode<ChildT>::setValueOnly(const Coord& xyz, const ValueType& value)
1877 {
1878 ChildT* child = NULL;
1879 MapIter iter = this->findCoord(xyz);
1880 if (iter == mTable.end()) {
1881 child = new ChildT(xyz, mBackground);
1882 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1883 } else if (isChild(iter)) {
1884 child = &getChild(iter);
1885 } else if (!math::isExactlyEqual(getTile(iter).value, value)) {
1886 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1887 setChild(iter, *child);
1888 }
1889 if (child) child->setValueOnly(xyz, value);
1890 }
1891
1892 template<typename ChildT>
1893 template<typename AccessorT>
1894 inline void
1895 RootNode<ChildT>::setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc)
1896 {
1897 ChildT* child = NULL;
1898 MapIter iter = this->findCoord(xyz);
1899 if (iter == mTable.end()) {
1900 child = new ChildT(xyz, mBackground);
1901 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1902 } else if (isChild(iter)) {
1903 child = &getChild(iter);
1904 } else if (!math::isExactlyEqual(getTile(iter).value, value)) {
1905 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1906 setChild(iter, *child);
1907 }
1908 if (child) {
1909 acc.insert(xyz, child);
1910 child->setValueOnlyAndCache(xyz, value, acc);
1911 }
1912 }
1913
1914
1915 template<typename ChildT>
1916 template<typename ModifyOp>
1917 inline void
1918 RootNode<ChildT>::modifyValue(const Coord& xyz, const ModifyOp& op)
1919 {
1920 ChildT* child = NULL;
1921 MapIter iter = this->findCoord(xyz);
1922 if (iter == mTable.end()) {
1923 child = new ChildT(xyz, mBackground);
1924 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1925 } else if (isChild(iter)) {
1926 child = &getChild(iter);
1927 } else {
1928 // Need to create a child if the tile is inactive,
1929 // in order to activate voxel (x, y, z).
1930 bool createChild = isTileOff(iter);
1931 if (!createChild) {
1932 // Need to create a child if applying the functor
1933 // to the tile value produces a different value.
1934 const ValueType& tileVal = getTile(iter).value;
1935 ValueType modifiedVal = tileVal;
1936 op(modifiedVal);
1937 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
1938 }
1939 if (createChild) {
1940 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1941 setChild(iter, *child);
1942 }
1943 }
1944 if (child) child->modifyValue(xyz, op);
1945 }
1946
1947 template<typename ChildT>
1948 template<typename ModifyOp, typename AccessorT>
1949 inline void
1950 RootNode<ChildT>::modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT& acc)
1951 {
1952 ChildT* child = NULL;
1953 MapIter iter = this->findCoord(xyz);
1954 if (iter == mTable.end()) {
1955 child = new ChildT(xyz, mBackground);
1956 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1957 } else if (isChild(iter)) {
1958 child = &getChild(iter);
1959 } else {
1960 // Need to create a child if the tile is inactive,
1961 // in order to activate voxel (x, y, z).
1962 bool createChild = isTileOff(iter);
1963 if (!createChild) {
1964 // Need to create a child if applying the functor
1965 // to the tile value produces a different value.
1966 const ValueType& tileVal = getTile(iter).value;
1967 ValueType modifiedVal = tileVal;
1968 op(modifiedVal);
1969 createChild = !math::isExactlyEqual(tileVal, modifiedVal);
1970 }
1971 if (createChild) {
1972 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
1973 setChild(iter, *child);
1974 }
1975 }
1976 if (child) {
1977 acc.insert(xyz, child);
1978 child->modifyValueAndCache(xyz, op, acc);
1979 }
1980 }
1981
1982
1983 template<typename ChildT>
1984 template<typename ModifyOp>
1985 inline void
1986 RootNode<ChildT>::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op)
1987 {
1988 ChildT* child = NULL;
1989 MapIter iter = this->findCoord(xyz);
1990 if (iter == mTable.end()) {
1991 child = new ChildT(xyz, mBackground);
1992 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
1993 } else if (isChild(iter)) {
1994 child = &getChild(iter);
1995 } else {
1996 const Tile& tile = getTile(iter);
1997 bool modifiedState = tile.active;
1998 ValueType modifiedVal = tile.value;
1999 op(modifiedVal, modifiedState);
2000 // Need to create a child if applying the functor to the tile
2001 // produces a different value or active state.
2002 if (modifiedState != tile.active || !math::isExactlyEqual(modifiedVal, tile.value)) {
2003 child = new ChildT(xyz, tile.value, tile.active);
2004 setChild(iter, *child);
2005 }
2006 }
2007 if (child) child->modifyValueAndActiveState(xyz, op);
2008 }
2009
2010 template<typename ChildT>
2011 template<typename ModifyOp, typename AccessorT>
2012 inline void
2013 RootNode<ChildT>::modifyValueAndActiveStateAndCache(
2014 const Coord& xyz, const ModifyOp& op, AccessorT& acc)
2015 {
2016 ChildT* child = NULL;
2017 MapIter iter = this->findCoord(xyz);
2018 if (iter == mTable.end()) {
2019 child = new ChildT(xyz, mBackground);
2020 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
2021 } else if (isChild(iter)) {
2022 child = &getChild(iter);
2023 } else {
2024 const Tile& tile = getTile(iter);
2025 bool modifiedState = tile.active;
2026 ValueType modifiedVal = tile.value;
2027 op(modifiedVal, modifiedState);
2028 // Need to create a child if applying the functor to the tile
2029 // produces a different value or active state.
2030 if (modifiedState != tile.active || !math::isExactlyEqual(modifiedVal, tile.value)) {
2031 child = new ChildT(xyz, tile.value, tile.active);
2032 setChild(iter, *child);
2033 }
2034 }
2035 if (child) {
2036 acc.insert(xyz, child);
2037 child->modifyValueAndActiveStateAndCache(xyz, op, acc);
2038 }
2039 }
2040
2041
2042 template<typename ChildT>
2043 inline bool
2044 RootNode<ChildT>::probeValue(const Coord& xyz, ValueType& value) const
2045 {
2046 MapCIter iter = this->findCoord(xyz);
2047 if (iter == mTable.end()) {
2048 value = mBackground;
2049 return false;
2050 } else if (isChild(iter)) {
2051 return getChild(iter).probeValue(xyz, value);
2052 }
2053 value = getTile(iter).value;
2054 return isTileOn(iter);
2055 }
2056
2057 template<typename ChildT>
2058 template<typename AccessorT>
2059 inline bool
2060 RootNode<ChildT>::probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT& acc) const
2061 {
2062 MapCIter iter = this->findCoord(xyz);
2063 if (iter == mTable.end()) {
2064 value = mBackground;
2065 return false;
2066 } else if (isChild(iter)) {
2067 acc.insert(xyz, &getChild(iter));
2068 return getChild(iter).probeValueAndCache(xyz, value, acc);
2069 }
2070 value = getTile(iter).value;
2071 return isTileOn(iter);
2072 }
2073
2074
2076
2077 template<typename ChildT>
2078 inline void
2079 RootNode<ChildT>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
2080 {
2081 if (bbox.empty()) return;
2082
2083 Coord xyz, tileMax;
2084 for (int x = bbox.min().x(); x <= bbox.max().x(); x = tileMax.x() + 1) {
2085 xyz.setX(x);
2086 for (int y = bbox.min().y(); y <= bbox.max().y(); y = tileMax.y() + 1) {
2087 xyz.setY(y);
2088 for (int z = bbox.min().z(); z <= bbox.max().z(); z = tileMax.z() + 1) {
2089 xyz.setZ(z);
2090
2091 // Get the bounds of the tile that contains voxel (x, y, z).
2092 Coord tileMin = coordToKey(xyz);
2093 tileMax = tileMin.offsetBy(ChildT::DIM - 1);
2094
2095 if (xyz != tileMin || Coord::lessThan(bbox.max(), tileMax)) {
2096 // If the box defined by (xyz, bbox.max()) doesn't completely enclose
2097 // the tile to which xyz belongs, create a child node (or retrieve
2098 // the existing one).
2099 ChildT* child = NULL;
2100 MapIter iter = this->findKey(tileMin);
2101 if (iter == mTable.end()) {
2102 // No child or tile exists. Create a child and initialize it
2103 // with the background value.
2104 child = new ChildT(xyz, mBackground);
2105 mTable[tileMin] = NodeStruct(*child);
2106 } else if (isTile(iter)) {
2107 // Replace the tile with a newly-created child that is initialized
2108 // with the tile's value and active state.
2109 const Tile& tile = getTile(iter);
2110 child = new ChildT(xyz, tile.value, tile.active);
2111 mTable[tileMin] = NodeStruct(*child);
2112 } else if (isChild(iter)) {
2113 child = &getChild(iter);
2114 }
2115 // Forward the fill request to the child.
2116 if (child) {
2117 const Coord tmp = Coord::minComponent(bbox.max(), tileMax);
2118 child->fill(CoordBBox(xyz, tmp), value, active);
2119 }
2120 } else {
2121 // If the box given by (xyz, bbox.max()) completely encloses
2122 // the tile to which xyz belongs, create the tile (if it
2123 // doesn't already exist) and give it the fill value.
2124 MapIter iter = this->findOrAddCoord(tileMin);
2125 setTile(iter, Tile(value, active));
2126 }
2127 }
2128 }
2129 }
2130 }
2131
2132 template<typename ChildT>
2133 inline void
2134 RootNode<ChildT>::denseFill(const CoordBBox& bbox, const ValueType& value, bool active)
2135 {
2136 this->sparseFill(bbox, value, active);
2137 this->voxelizeActiveTiles(true);//multi-threaded
2138 }
2139
2140 template<typename ChildT>
2141 template<typename DenseT>
2142 inline void
2143 RootNode<ChildT>::copyToDense(const CoordBBox& bbox, DenseT& dense) const
2144 {
2145 typedef typename DenseT::ValueType DenseValueType;
2146
2147 const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride();
2148 const Coord& min = dense.bbox().min();
2149 CoordBBox nodeBBox;
2150 for (Coord xyz = bbox.min(); xyz[0] <= bbox.max()[0]; xyz[0] = nodeBBox.max()[0] + 1) {
2151 for (xyz[1] = bbox.min()[1]; xyz[1] <= bbox.max()[1]; xyz[1] = nodeBBox.max()[1] + 1) {
2152 for (xyz[2] = bbox.min()[2]; xyz[2] <= bbox.max()[2]; xyz[2] = nodeBBox.max()[2] + 1) {
2153
2154 // Get the coordinate bbox of the child node that contains voxel xyz.
2155 nodeBBox = CoordBBox::createCube(coordToKey(xyz), ChildT::DIM);
2156
2157 // Get the coordinate bbox of the interection of inBBox and nodeBBox
2158 CoordBBox sub(xyz, Coord::minComponent(bbox.max(), nodeBBox.max()));
2159
2160 MapCIter iter = this->findKey(nodeBBox.min());
2161 if (iter != mTable.end() && isChild(iter)) {//is a child
2162 getChild(iter).copyToDense(sub, dense);
2163 } else {//is background or a tile value
2164 const ValueType value = iter==mTable.end() ? mBackground : getTile(iter).value;
2165 sub.translate(-min);
2166 DenseValueType* a0 = dense.data() + zStride*sub.min()[2];
2167 for (Int32 x=sub.min()[0], ex=sub.max()[0]+1; x<ex; ++x) {
2168 DenseValueType* a1 = a0 + x*xStride;
2169 for (Int32 y=sub.min()[1], ey=sub.max()[1]+1; y<ey; ++y) {
2170 DenseValueType* a2 = a1 + y*yStride;
2171 for (Int32 z=sub.min()[2], ez=sub.max()[2]+1; z<ez; ++z, a2 += zStride) {
2172 *a2 = DenseValueType(value);
2173 }
2174 }
2175 }
2176 }
2177 }
2178 }
2179 }
2180 }
2181
2183
2184
2185 template<typename ChildT>
2186 inline bool
2187 RootNode<ChildT>::writeTopology(std::ostream& os, bool toHalf) const
2188 {
2189 if (!toHalf) {
2190 os.write(reinterpret_cast<const char*>(&mBackground), sizeof(ValueType));
2191 } else {
2192 ValueType truncatedVal = io::truncateRealToHalf(mBackground);
2193 os.write(reinterpret_cast<const char*>(&truncatedVal), sizeof(ValueType));
2194 }
2195 io::setGridBackgroundValuePtr(os, &mBackground);
2196
2197 const Index numTiles = this->getTileCount(), numChildren = this->getChildCount();
2198 os.write(reinterpret_cast<const char*>(&numTiles), sizeof(Index));
2199 os.write(reinterpret_cast<const char*>(&numChildren), sizeof(Index));
2200
2201 if (numTiles == 0 && numChildren == 0) return false;
2202
2203 // Write tiles.
2204 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2205 if (isChild(i)) continue;
2206 os.write(reinterpret_cast<const char*>(i->first.asPointer()), 3 * sizeof(Int32));
2207 os.write(reinterpret_cast<const char*>(&getTile(i).value), sizeof(ValueType));
2208 os.write(reinterpret_cast<const char*>(&getTile(i).active), sizeof(bool));
2209 }
2210 // Write child nodes.
2211 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2212 if (isTile(i)) continue;
2213 os.write(reinterpret_cast<const char*>(i->first.asPointer()), 3 * sizeof(Int32));
2214 getChild(i).writeTopology(os, toHalf);
2215 }
2216
2217 return true; // not empty
2218 }
2219
2220
2221 template<typename ChildT>
2222 inline bool
2223 RootNode<ChildT>::readTopology(std::istream& is, bool fromHalf)
2224 {
2225 // Delete the existing tree.
2226 this->clear();
2227
2228 if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_ROOTNODE_MAP) {
2229 // Read and convert an older-format RootNode.
2230
2231 // For backward compatibility with older file formats, read both
2232 // outside and inside background values.
2233 is.read(reinterpret_cast<char*>(&mBackground), sizeof(ValueType));
2234 ValueType inside;
2235 is.read(reinterpret_cast<char*>(&inside), sizeof(ValueType));
2236
2237 io::setGridBackgroundValuePtr(is, &mBackground);
2238
2239 // Read the index range.
2240 Coord rangeMin, rangeMax;
2241 is.read(reinterpret_cast<char*>(rangeMin.asPointer()), 3 * sizeof(Int32));
2242 is.read(reinterpret_cast<char*>(rangeMax.asPointer()), 3 * sizeof(Int32));
2243
2244 this->initTable();
2245 Index tableSize = 0, log2Dim[4] = { 0, 0, 0, 0 };
2246 Int32 offset[3];
2247 for (int i = 0; i < 3; ++i) {
2248 offset[i] = rangeMin[i] >> ChildT::TOTAL;
2249 rangeMin[i] = offset[i] << ChildT::TOTAL;
2250 log2Dim[i] = 1 + util::FindHighestOn((rangeMax[i] >> ChildT::TOTAL) - offset[i]);
2251 tableSize += log2Dim[i];
2252 rangeMax[i] = (((1 << log2Dim[i]) + offset[i]) << ChildT::TOTAL) - 1;
2253 }
2254 log2Dim[3] = log2Dim[1] + log2Dim[2];
2255 tableSize = 1U << tableSize;
2256
2257 // Read masks.
2258 util::RootNodeMask childMask(tableSize), valueMask(tableSize);
2259 childMask.load(is);
2260 valueMask.load(is);
2261
2262 // Read child nodes/values.
2263 for (Index i = 0; i < tableSize; ++i) {
2264 // Compute origin = offset2coord(i).
2265 Index n = i;
2266 Coord origin;
2267 origin[0] = (n >> log2Dim[3]) + offset[0];
2268 n &= (1U << log2Dim[3]) - 1;
2269 origin[1] = (n >> log2Dim[2]) + offset[1];
2270 origin[2] = (n & ((1U << log2Dim[2]) - 1)) + offset[1];
2271 origin <<= ChildT::TOTAL;
2272
2273 if (childMask.isOn(i)) {
2274 // Read in and insert a child node.
2275 #ifdef OPENVDB_2_ABI_COMPATIBLE
2276 ChildT* child = new ChildT(origin, mBackground);
2277 #else
2278 ChildT* child = new ChildT(PartialCreate(), origin, mBackground);
2279 #endif
2280 child->readTopology(is);
2281 mTable[origin] = NodeStruct(*child);
2282 } else {
2283 // Read in a tile value and insert a tile, but only if the value
2284 // is either active or non-background.
2285 ValueType value;
2286 is.read(reinterpret_cast<char*>(&value), sizeof(ValueType));
2287 if (valueMask.isOn(i) || (!math::isApproxEqual(value, mBackground))) {
2288 mTable[origin] = NodeStruct(Tile(value, valueMask.isOn(i)));
2289 }
2290 }
2291 }
2292 return true;
2293 }
2294
2295 // Read a RootNode that was stored in the current format.
2296
2297 is.read(reinterpret_cast<char*>(&mBackground), sizeof(ValueType));
2298 io::setGridBackgroundValuePtr(is, &mBackground);
2299
2300 Index numTiles = 0, numChildren = 0;
2301 is.read(reinterpret_cast<char*>(&numTiles), sizeof(Index));
2302 is.read(reinterpret_cast<char*>(&numChildren), sizeof(Index));
2303
2304 if (numTiles == 0 && numChildren == 0) return false;
2305
2306 Int32 vec[3];
2307 ValueType value;
2308 bool active;
2309
2310 // Read tiles.
2311 for (Index n = 0; n < numTiles; ++n) {
2312 is.read(reinterpret_cast<char*>(vec), 3 * sizeof(Int32));
2313 is.read(reinterpret_cast<char*>(&value), sizeof(ValueType));
2314 is.read(reinterpret_cast<char*>(&active), sizeof(bool));
2315 mTable[Coord(vec)] = NodeStruct(Tile(value, active));
2316 }
2317
2318 // Read child nodes.
2319 for (Index n = 0; n < numChildren; ++n) {
2320 is.read(reinterpret_cast<char*>(vec), 3 * sizeof(Int32));
2321 Coord origin(vec);
2322 #ifdef OPENVDB_2_ABI_COMPATIBLE
2323 ChildT* child = new ChildT(origin, mBackground);
2324 #else
2325 ChildT* child = new ChildT(PartialCreate(), origin, mBackground);
2326 #endif
2327 child->readTopology(is, fromHalf);
2328 mTable[Coord(vec)] = NodeStruct(*child);
2329 }
2330
2331 return true; // not empty
2332 }
2333
2334
2335 template<typename ChildT>
2336 inline void
2337 RootNode<ChildT>::writeBuffers(std::ostream& os, bool toHalf) const
2338 {
2339 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2340 if (isChild(i)) getChild(i).writeBuffers(os, toHalf);
2341 }
2342 }
2343
2344
2345 template<typename ChildT>
2346 inline void
2347 RootNode<ChildT>::readBuffers(std::istream& is, bool fromHalf)
2348 {
2349 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2350 if (isChild(i)) getChild(i).readBuffers(is, fromHalf);
2351 }
2352 }
2353
2354
2355 template<typename ChildT>
2356 inline void
2357 RootNode<ChildT>::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf)
2358 {
2359 const Tile bgTile(mBackground, /*active=*/false);
2360
2361 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2362 if (isChild(i)) {
2363 // Stream in and clip the branch rooted at this child.
2364 // (We can't skip over children that lie outside the clipping region,
2365 // because buffers are serialized in depth-first order and need to be
2366 // unserialized in the same order.)
2367 ChildT& child = getChild(i);
2368 child.readBuffers(is, clipBBox, fromHalf);
2369 }
2370 }
2371 // Clip root-level tiles and prune children that were clipped.
2372 this->clip(clipBBox);
2373 }
2374
2375
2377
2378
2379 template<typename ChildT>
2380 inline void
2381 RootNode<ChildT>::clip(const CoordBBox& clipBBox)
2382 {
2383 const Tile bgTile(mBackground, /*active=*/false);
2384
2385 // Iterate over a copy of this node's table so that we can modify the original.
2386 // (Copying the table copies child node pointers, not the nodes themselves.)
2387 MapType copyOfTable(mTable);
2388 for (MapIter i = copyOfTable.begin(), e = copyOfTable.end(); i != e; ++i) {
2389 const Coord& xyz = i->first; // tile or child origin
2390 CoordBBox tileBBox(xyz, xyz.offsetBy(ChildT::DIM - 1)); // tile or child bounds
2391 if (!clipBBox.hasOverlap(tileBBox)) {
2392 // This table entry lies completely outside the clipping region. Delete it.
2393 setTile(this->findCoord(xyz), bgTile); // delete any existing child node first
2394 mTable.erase(xyz);
2395 } else if (!clipBBox.isInside(tileBBox)) {
2396 // This table entry does not lie completely inside the clipping region
2397 // and must be clipped.
2398 if (isChild(i)) {
2399 getChild(i).clip(clipBBox, mBackground);
2400 } else {
2401 // Replace this tile with a background tile, then fill the clip region
2402 // with the tile's original value. (This might create a child branch.)
2403 tileBBox.intersect(clipBBox);
2404 const Tile& origTile = getTile(i);
2405 setTile(this->findCoord(xyz), bgTile);
2406 this->sparseFill(tileBBox, origTile.value, origTile.active);
2407 }
2408 } else {
2409 // This table entry lies completely inside the clipping region. Leave it intact.
2410 }
2411 }
2412 this->prune(); // also erases root-level background tiles
2413 }
2414
2415
2417
2418
2419 template<typename ChildT>
2420 inline void
2421 RootNode<ChildT>::prune(const ValueType& tolerance)
2422 {
2423 bool state = false;
2424 ValueType value = zeroVal<ValueType>();
2425 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2426 if (this->isTile(i)) continue;
2427 this->getChild(i).prune(tolerance);
2428 if (this->getChild(i).isConstant(value, state, tolerance)) {
2429 this->setTile(i, Tile(value, state));
2430 }
2431 }
2432 this->eraseBackgroundTiles();
2433 }
2434
2435
2437
2438
2439 template<typename ChildT>
2440 template<typename NodeT>
2441 inline NodeT*
2442 RootNode<ChildT>::stealNode(const Coord& xyz, const ValueType& value, bool state)
2443 {
2444 if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same<NodeT, ChildT>::value)) ||
2445 NodeT::LEVEL > ChildT::LEVEL) return NULL;
2446 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2447 MapIter iter = this->findCoord(xyz);
2448 if (iter == mTable.end() || isTile(iter)) return NULL;
2449 return (boost::is_same<NodeT, ChildT>::value)
2450 ? reinterpret_cast<NodeT*>(&stealChild(iter, Tile(value, state)))
2451 : getChild(iter).template stealNode<NodeT>(xyz, value, state);
2452 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2453 }
2454
2455
2457
2458
2459 template<typename ChildT>
2460 inline void
2461 RootNode<ChildT>::addLeaf(LeafNodeType* leaf)
2462 {
2463 if (leaf == NULL) return;
2464 ChildT* child = NULL;
2465 const Coord& xyz = leaf->origin();
2466 MapIter iter = this->findCoord(xyz);
2467 if (iter == mTable.end()) {
2468 if (ChildT::LEVEL>0) {
2469 child = new ChildT(xyz, mBackground, false);
2470 } else {
2471 child = reinterpret_cast<ChildT*>(leaf);
2472 }
2473 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
2474 } else if (isChild(iter)) {
2475 if (ChildT::LEVEL>0) {
2476 child = &getChild(iter);
2477 } else {
2478 child = reinterpret_cast<ChildT*>(leaf);
2479 setChild(iter, *child);//this also deletes the existing child node
2480 }
2481 } else {//tile
2482 if (ChildT::LEVEL>0) {
2483 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2484 } else {
2485 child = reinterpret_cast<ChildT*>(leaf);
2486 }
2487 setChild(iter, *child);
2488 }
2489 child->addLeaf(leaf);
2490 }
2491
2492
2493 template<typename ChildT>
2494 template<typename AccessorT>
2495 inline void
2496 RootNode<ChildT>::addLeafAndCache(LeafNodeType* leaf, AccessorT& acc)
2497 {
2498 if (leaf == NULL) return;
2499 ChildT* child = NULL;
2500 const Coord& xyz = leaf->origin();
2501 MapIter iter = this->findCoord(xyz);
2502 if (iter == mTable.end()) {
2503 if (ChildT::LEVEL>0) {
2504 child = new ChildT(xyz, mBackground, false);
2505 } else {
2506 child = reinterpret_cast<ChildT*>(leaf);
2507 }
2508 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
2509 } else if (isChild(iter)) {
2510 if (ChildT::LEVEL>0) {
2511 child = &getChild(iter);
2512 } else {
2513 child = reinterpret_cast<ChildT*>(leaf);
2514 setChild(iter, *child);//this also deletes the existing child node
2515 }
2516 } else {//tile
2517 if (ChildT::LEVEL>0) {
2518 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2519 } else {
2520 child = reinterpret_cast<ChildT*>(leaf);
2521 }
2522 setChild(iter, *child);
2523 }
2524 acc.insert(xyz, child);
2525 child->addLeafAndCache(leaf, acc);
2526 }
2527
2528 template<typename ChildT>
2529 inline void
2530 RootNode<ChildT>::addTile(const Coord& xyz, const ValueType& value, bool state)
2531 {
2532 MapIter iter = this->findCoord(xyz);
2533 if (iter == mTable.end()) {//background
2534 mTable[this->coordToKey(xyz)] = NodeStruct(Tile(value, state));
2535 } else {//child or tile
2536 setTile(iter, Tile(value, state));//this also deletes the existing child node
2537 }
2538 }
2539
2540 template<typename ChildT>
2541 inline void
2542 RootNode<ChildT>::addTile(Index level, const Coord& xyz,
2543 const ValueType& value, bool state)
2544 {
2545 if (LEVEL >= level) {
2546 MapIter iter = this->findCoord(xyz);
2547 if (iter == mTable.end()) {//background
2548 if (LEVEL > level) {
2549 ChildT* child = new ChildT(xyz, mBackground, false);
2550 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
2551 child->addTile(level, xyz, value, state);
2552 } else {
2553 mTable[this->coordToKey(xyz)] = NodeStruct(Tile(value, state));
2554 }
2555 } else if (isChild(iter)) {//child
2556 if (LEVEL > level) {
2557 getChild(iter).addTile(level, xyz, value, state);
2558 } else {
2559 setTile(iter, Tile(value, state));//this also deletes the existing child node
2560 }
2561 } else {//tile
2562 if (LEVEL > level) {
2563 ChildT* child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2564 setChild(iter, *child);
2565 child->addTile(level, xyz, value, state);
2566 } else {
2567 setTile(iter, Tile(value, state));
2568 }
2569 }
2570 }
2571 }
2572
2573
2574 template<typename ChildT>
2575 template<typename AccessorT>
2576 inline void
2577 RootNode<ChildT>::addTileAndCache(Index level, const Coord& xyz, const ValueType& value,
2578 bool state, AccessorT& acc)
2579 {
2580 if (LEVEL >= level) {
2581 MapIter iter = this->findCoord(xyz);
2582 if (iter == mTable.end()) {//background
2583 if (LEVEL > level) {
2584 ChildT* child = new ChildT(xyz, mBackground, false);
2585 acc.insert(xyz, child);
2586 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
2587 child->addTileAndCache(level, xyz, value, state, acc);
2588 } else {
2589 mTable[this->coordToKey(xyz)] = NodeStruct(Tile(value, state));
2590 }
2591 } else if (isChild(iter)) {//child
2592 if (LEVEL > level) {
2593 ChildT* child = &getChild(iter);
2594 acc.insert(xyz, child);
2595 child->addTileAndCache(level, xyz, value, state, acc);
2596 } else {
2597 setTile(iter, Tile(value, state));//this also deletes the existing child node
2598 }
2599 } else {//tile
2600 if (LEVEL > level) {
2601 ChildT* child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2602 acc.insert(xyz, child);
2603 setChild(iter, *child);
2604 child->addTileAndCache(level, xyz, value, state, acc);
2605 } else {
2606 setTile(iter, Tile(value, state));
2607 }
2608 }
2609 }
2610 }
2611
2612
2614
2615
2616 template<typename ChildT>
2617 inline typename ChildT::LeafNodeType*
2618 RootNode<ChildT>::touchLeaf(const Coord& xyz)
2619 {
2620 ChildT* child = NULL;
2621 MapIter iter = this->findCoord(xyz);
2622 if (iter == mTable.end()) {
2623 child = new ChildT(xyz, mBackground, false);
2624 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
2625 } else if (isChild(iter)) {
2626 child = &getChild(iter);
2627 } else {
2628 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2629 setChild(iter, *child);
2630 }
2631 return child->touchLeaf(xyz);
2632 }
2633
2634
2635 template<typename ChildT>
2636 template<typename AccessorT>
2637 inline typename ChildT::LeafNodeType*
2638 RootNode<ChildT>::touchLeafAndCache(const Coord& xyz, AccessorT& acc)
2639 {
2640 ChildT* child = NULL;
2641 MapIter iter = this->findCoord(xyz);
2642 if (iter == mTable.end()) {
2643 child = new ChildT(xyz, mBackground, false);
2644 mTable[this->coordToKey(xyz)] = NodeStruct(*child);
2645 } else if (isChild(iter)) {
2646 child = &getChild(iter);
2647 } else {
2648 child = new ChildT(xyz, getTile(iter).value, isTileOn(iter));
2649 setChild(iter, *child);
2650 }
2651 acc.insert(xyz, child);
2652 return child->touchLeafAndCache(xyz, acc);
2653 }
2654
2655
2657
2658
2659 template<typename ChildT>
2660 template<typename NodeT>
2661 inline NodeT*
2662 RootNode<ChildT>::probeNode(const Coord& xyz)
2663 {
2664 if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same<NodeT, ChildT>::value)) ||
2665 NodeT::LEVEL > ChildT::LEVEL) return NULL;
2666 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2667 MapIter iter = this->findCoord(xyz);
2668 if (iter == mTable.end() || isTile(iter)) return NULL;
2669 ChildT* child = &getChild(iter);
2670 return (boost::is_same<NodeT, ChildT>::value)
2671 ? reinterpret_cast<NodeT*>(child)
2672 : child->template probeNode<NodeT>(xyz);
2673 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2674 }
2675
2676
2677 template<typename ChildT>
2678 template<typename NodeT>
2679 inline const NodeT*
2680 RootNode<ChildT>::probeConstNode(const Coord& xyz) const
2681 {
2682 if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same<NodeT, ChildT>::value)) ||
2683 NodeT::LEVEL > ChildT::LEVEL) return NULL;
2684 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2685 MapCIter iter = this->findCoord(xyz);
2686 if (iter == mTable.end() || isTile(iter)) return NULL;
2687 const ChildT* child = &getChild(iter);
2688 return (boost::is_same<NodeT, ChildT>::value)
2689 ? reinterpret_cast<const NodeT*>(child)
2690 : child->template probeConstNode<NodeT>(xyz);
2691 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2692 }
2693
2694
2695 template<typename ChildT>
2696 inline typename ChildT::LeafNodeType*
2697 RootNode<ChildT>::probeLeaf(const Coord& xyz)
2698 {
2699 return this->template probeNode<LeafNodeType>(xyz);
2700 }
2701
2702
2703 template<typename ChildT>
2704 inline const typename ChildT::LeafNodeType*
2705 RootNode<ChildT>::probeConstLeaf(const Coord& xyz) const
2706 {
2707 return this->template probeConstNode<LeafNodeType>(xyz);
2708 }
2709
2710
2711 template<typename ChildT>
2712 template<typename AccessorT>
2713 inline typename ChildT::LeafNodeType*
2714 RootNode<ChildT>::probeLeafAndCache(const Coord& xyz, AccessorT& acc)
2715 {
2716 return this->template probeNodeAndCache<LeafNodeType>(xyz, acc);
2717 }
2718
2719
2720 template<typename ChildT>
2721 template<typename AccessorT>
2722 inline const typename ChildT::LeafNodeType*
2723 RootNode<ChildT>::probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const
2724 {
2725 return this->template probeConstNodeAndCache<LeafNodeType>(xyz, acc);
2726 }
2727
2728
2729 template<typename ChildT>
2730 template<typename AccessorT>
2731 inline const typename ChildT::LeafNodeType*
2732 RootNode<ChildT>::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const
2733 {
2734 return this->probeConstLeafAndCache(xyz, acc);
2735 }
2736
2737
2738 template<typename ChildT>
2739 template<typename NodeT, typename AccessorT>
2740 inline NodeT*
2741 RootNode<ChildT>::probeNodeAndCache(const Coord& xyz, AccessorT& acc)
2742 {
2743 if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same<NodeT, ChildT>::value)) ||
2744 NodeT::LEVEL > ChildT::LEVEL) return NULL;
2745 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2746 MapIter iter = this->findCoord(xyz);
2747 if (iter == mTable.end() || isTile(iter)) return NULL;
2748 ChildT* child = &getChild(iter);
2749 acc.insert(xyz, child);
2750 return (boost::is_same<NodeT, ChildT>::value)
2751 ? reinterpret_cast<NodeT*>(child)
2752 : child->template probeNodeAndCache<NodeT>(xyz, acc);
2753 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2754 }
2755
2756
2757 template<typename ChildT>
2758 template<typename NodeT,typename AccessorT>
2759 inline const NodeT*
2760 RootNode<ChildT>::probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const
2761 {
2762 if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same<NodeT, ChildT>::value)) ||
2763 NodeT::LEVEL > ChildT::LEVEL) return NULL;
2764 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2765 MapCIter iter = this->findCoord(xyz);
2766 if (iter == mTable.end() || isTile(iter)) return NULL;
2767 const ChildT* child = &getChild(iter);
2768 acc.insert(xyz, child);
2769 return (boost::is_same<NodeT, ChildT>::value)
2770 ? reinterpret_cast<const NodeT*>(child)
2771 : child->template probeConstNodeAndCache<NodeT>(xyz, acc);
2772 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2773 }
2774
2775
2777
2778 template<typename ChildT>
2779 template<typename ArrayT>
2780 inline void
2781 RootNode<ChildT>::getNodes(ArrayT& array)
2782 {
2783 typedef typename ArrayT::value_type NodePtr;
2784 BOOST_STATIC_ASSERT(boost::is_pointer<NodePtr>::value);
2785 typedef typename boost::remove_pointer<NodePtr>::type NodeType;
2786 typedef typename boost::remove_const<NodeType>::type NonConstNodeType;
2787 typedef typename boost::mpl::contains<NodeChainType, NonConstNodeType>::type result;
2788 BOOST_STATIC_ASSERT(result::value);
2789 typedef typename boost::mpl::if_<boost::is_const<NodeType>,
2790 const ChildT, ChildT>::type ArrayChildT;
2791
2792 for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
2793 if (ChildT* child = iter->second.child) {
2794 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2795 if (boost::is_same<NodePtr, ArrayChildT*>::value) {
2796 array.push_back(reinterpret_cast<NodePtr>(iter->second.child));
2797 } else {
2798 child->getNodes(array);//descent
2799 }
2800 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2801 }
2802 }
2803 }
2804
2805 template<typename ChildT>
2806 template<typename ArrayT>
2807 inline void
2808 RootNode<ChildT>::getNodes(ArrayT& array) const
2809 {
2810 typedef typename ArrayT::value_type NodePtr;
2811 BOOST_STATIC_ASSERT(boost::is_pointer<NodePtr>::value);
2812 typedef typename boost::remove_pointer<NodePtr>::type NodeType;
2813 BOOST_STATIC_ASSERT(boost::is_const<NodeType>::value);
2814 typedef typename boost::remove_const<NodeType>::type NonConstNodeType;
2815 typedef typename boost::mpl::contains<NodeChainType, NonConstNodeType>::type result;
2816 BOOST_STATIC_ASSERT(result::value);
2817
2818 for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
2819 if (const ChildNodeType *child = iter->second.child) {
2820 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2821 if (boost::is_same<NodePtr, const ChildT*>::value) {
2822 array.push_back(reinterpret_cast<NodePtr>(iter->second.child));
2823 } else {
2824 child->getNodes(array);//descent
2825 }
2826 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2827 }
2828 }
2829 }
2830
2832
2833 template<typename ChildT>
2834 template<typename ArrayT>
2835 inline void
2836 RootNode<ChildT>::stealNodes(ArrayT& array, const ValueType& value, bool state)
2837 {
2838 typedef typename ArrayT::value_type NodePtr;
2839 BOOST_STATIC_ASSERT(boost::is_pointer<NodePtr>::value);
2840 typedef typename boost::remove_pointer<NodePtr>::type NodeType;
2841 typedef typename boost::remove_const<NodeType>::type NonConstNodeType;
2842 typedef typename boost::mpl::contains<NodeChainType, NonConstNodeType>::type result;
2843 BOOST_STATIC_ASSERT(result::value);
2844 typedef typename boost::mpl::if_<boost::is_const<NodeType>,
2845 const ChildT, ChildT>::type ArrayChildT;
2846
2847 for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) {
2848 if (ChildT* child = iter->second.child) {
2849 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2850 if (boost::is_same<NodePtr, ArrayChildT*>::value) {
2851 array.push_back(reinterpret_cast<NodePtr>(&stealChild(iter, Tile(value, state))));
2852 } else {
2853 child->stealNodes(array, value, state);//descent
2854 }
2855 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2856 }
2857 }
2858 }
2859
2860
2862
2863
2864 template<typename ChildT>
2865 inline void
2866 RootNode<ChildT>::voxelizeActiveTiles(bool threaded)
2867 {
2868 // These is little point in multi-threaded over the root table since
2869 // each tile spans a huge index space (by default 4096^3) and hence we
2870 // expect few if any at all. In fact, you're very likeky to run out
2871 // of memory if this method is called on a tree with root-level
2872 // active tiles!
2873 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
2874 if (this->isTileOff(i)) continue;
2875 ChildT* child = i->second.child;
2876 if (child==NULL) {
2877 child = new ChildT(i->first, this->getTile(i).value, true);
2878 i->second.child = child;
2879 }
2880 child->voxelizeActiveTiles(threaded);
2881 }
2882 }
2883
2884
2886
2887
2888 template<typename ChildT>
2889 template<MergePolicy Policy>
2890 inline void
2891 RootNode<ChildT>::merge(RootNode& other)
2892 {
2893 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
2894
2895 switch (Policy) {
2896
2897 default:
2898 case MERGE_ACTIVE_STATES:
2899 for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
2900 MapIter j = mTable.find(i->first);
2901 if (other.isChild(i)) {
2902 if (j == mTable.end()) { // insert other node's child
2903 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
2904 child.resetBackground(other.mBackground, mBackground);
2905 mTable[i->first] = NodeStruct(child);
2906 } else if (isTile(j)) {
2907 if (isTileOff(j)) { // replace inactive tile with other node's child
2908 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
2909 child.resetBackground(other.mBackground, mBackground);
2910 setChild(j, child);
2911 }
2912 } else { // merge both child nodes
2913 getChild(j).template merge<MERGE_ACTIVE_STATES>(getChild(i),
2914 other.mBackground, mBackground);
2915 }
2916 } else if (other.isTileOn(i)) {
2917 if (j == mTable.end()) { // insert other node's active tile
2918 mTable[i->first] = i->second;
2919 } else if (!isTileOn(j)) {
2920 // Replace anything except an active tile with the other node's active tile.
2921 setTile(j, Tile(other.getTile(i).value, true));
2922 }
2923 }
2924 }
2925 break;
2926
2927 case MERGE_NODES:
2928 for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
2929 MapIter j = mTable.find(i->first);
2930 if (other.isChild(i)) {
2931 if (j == mTable.end()) { // insert other node's child
2932 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
2933 child.resetBackground(other.mBackground, mBackground);
2934 mTable[i->first] = NodeStruct(child);
2935 } else if (isTile(j)) { // replace tile with other node's child
2936 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
2937 child.resetBackground(other.mBackground, mBackground);
2938 setChild(j, child);
2939 } else { // merge both child nodes
2940 getChild(j).template merge<MERGE_NODES>(
2941 getChild(i), other.mBackground, mBackground);
2942 }
2943 }
2944 }
2945 break;
2946
2947 case MERGE_ACTIVE_STATES_AND_NODES:
2948 for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
2949 MapIter j = mTable.find(i->first);
2950 if (other.isChild(i)) {
2951 if (j == mTable.end()) {
2952 // Steal and insert the other node's child.
2953 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
2954 child.resetBackground(other.mBackground, mBackground);
2955 mTable[i->first] = NodeStruct(child);
2956 } else if (isTile(j)) {
2957 // Replace this node's tile with the other node's child.
2958 ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false));
2959 child.resetBackground(other.mBackground, mBackground);
2960 const Tile tile = getTile(j);
2961 setChild(j, child);
2962 if (tile.active) {
2963 // Merge the other node's child with this node's active tile.
2964 child.template merge<MERGE_ACTIVE_STATES_AND_NODES>(
2965 tile.value, tile.active);
2966 }
2967 } else /*if (isChild(j))*/ {
2968 // Merge the other node's child into this node's child.
2969 getChild(j).template merge<MERGE_ACTIVE_STATES_AND_NODES>(getChild(i),
2970 other.mBackground, mBackground);
2971 }
2972 } else if (other.isTileOn(i)) {
2973 if (j == mTable.end()) {
2974 // Insert a copy of the other node's active tile.
2975 mTable[i->first] = i->second;
2976 } else if (isTileOff(j)) {
2977 // Replace this node's inactive tile with a copy of the other's active tile.
2978 setTile(j, Tile(other.getTile(i).value, true));
2979 } else if (isChild(j)) {
2980 // Merge the other node's active tile into this node's child.
2981 const Tile& tile = getTile(i);
2982 getChild(j).template merge<MERGE_ACTIVE_STATES_AND_NODES>(
2983 tile.value, tile.active);
2984 }
2985 } // else if (other.isTileOff(i)) {} // ignore the other node's inactive tiles
2986 }
2987 break;
2988 }
2989
2990 // Empty the other tree so as not to leave it in a partially cannibalized state.
2991 other.clear();
2992
2993 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
2994 }
2995
2996
2998
2999
3000 template<typename ChildT>
3001 template<typename OtherChildType>
3002 inline void
3003 RootNode<ChildT>::topologyUnion(const RootNode<OtherChildType>& other)
3004 {
3005 typedef RootNode<OtherChildType> OtherRootT;
3006 typedef typename OtherRootT::MapCIter OtherCIterT;
3007
3008 enforceSameConfiguration(other);
3009
3010 for (OtherCIterT i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
3011 MapIter j = mTable.find(i->first);
3012 if (other.isChild(i)) {
3013 if (j == mTable.end()) { // create child branch with identical topology
3014 mTable[i->first] = NodeStruct(
3015 *(new ChildT(other.getChild(i), mBackground, TopologyCopy())));
3016 } else if (this->isChild(j)) { // union with child branch
3017 this->getChild(j).topologyUnion(other.getChild(i));
3018 } else {// this is a tile so replace it with a child branch with identical topology
3019 ChildT* child = new ChildT(
3020 other.getChild(i), this->getTile(j).value, TopologyCopy());
3021 if (this->isTileOn(j)) child->setValuesOn();//this is an active tile
3022 this->setChild(j, *child);
3023 }
3024 } else if (other.isTileOn(i)) { // other is an active tile
3025 if (j == mTable.end()) { // insert an active tile
3026 mTable[i->first] = NodeStruct(Tile(mBackground, true));
3027 } else if (this->isChild(j)) {
3028 this->getChild(j).setValuesOn();
3029 } else if (this->isTileOff(j)) {
3030 this->setTile(j, Tile(this->getTile(j).value, true));
3031 }
3032 }
3033 }
3034 }
3035
3036 template<typename ChildT>
3037 template<typename OtherChildType>
3038 inline void
3039 RootNode<ChildT>::topologyIntersection(const RootNode<OtherChildType>& other)
3040 {
3041 typedef RootNode<OtherChildType> OtherRootT;
3042 typedef typename OtherRootT::MapCIter OtherCIterT;
3043
3044 enforceSameConfiguration(other);
3045
3046 std::set<Coord> tmp;//keys to erase
3047 for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
3048 OtherCIterT j = other.mTable.find(i->first);
3049 if (this->isChild(i)) {
3050 if (j == other.mTable.end() || other.isTileOff(j)) {
3051 tmp.insert(i->first);//delete child branch
3052 } else if (other.isChild(j)) { // intersect with child branch
3053 this->getChild(i).topologyIntersection(other.getChild(j), mBackground);
3054 }
3055 } else if (this->isTileOn(i)) {
3056 if (j == other.mTable.end() || other.isTileOff(j)) {
3057 this->setTile(i, Tile(this->getTile(i).value, false));//turn inactive
3058 } else if (other.isChild(j)) { //replace with a child branch with identical topology
3059 ChildT* child =
3060 new ChildT(other.getChild(j), this->getTile(i).value, TopologyCopy());
3061 this->setChild(i, *child);
3062 }
3063 }
3064 }
3065 for (std::set<Coord>::iterator i = tmp.begin(), e = tmp.end(); i != e; ++i) {
3066 MapIter it = this->findCoord(*i);
3067 setTile(it, Tile()); // delete any existing child node first
3068 mTable.erase(it);
3069 }
3070 }
3071
3072 template<typename ChildT>
3073 template<typename OtherChildType>
3074 inline void
3075 RootNode<ChildT>::topologyDifference(const RootNode<OtherChildType>& other)
3076 {
3077 typedef RootNode<OtherChildType> OtherRootT;
3078 typedef typename OtherRootT::MapCIter OtherCIterT;
3079
3080 enforceSameConfiguration(other);
3081
3082 for (OtherCIterT i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) {
3083 MapIter j = mTable.find(i->first);
3084 if (other.isChild(i)) {
3085 if (j == mTable.end() || this->isTileOff(j)) {
3086 //do nothing
3087 } else if (this->isChild(j)) { // difference with child branch
3088 this->getChild(j).topologyDifference(other.getChild(i), mBackground);
3089 } else if (this->isTileOn(j)) {
3090 // this is an active tile so create a child node and descent
3091 ChildT* child = new ChildT(j->first, this->getTile(j).value, true);
3092 child->topologyDifference(other.getChild(i), mBackground);
3093 this->setChild(j, *child);
3094 }
3095 } else if (other.isTileOn(i)) { // other is an active tile
3096 if (j == mTable.end() || this->isTileOff(j)) {
3097 // do nothing
3098 } else if (this->isChild(j)) {
3099 setTile(j, Tile()); // delete any existing child node first
3100 mTable.erase(j);
3101 } else if (this->isTileOn(j)) {
3102 this->setTile(j, Tile(this->getTile(j).value, false));
3103 }
3104 }
3105 }
3106 }
3107
3109
3110
3111 template<typename ChildT>
3112 template<typename CombineOp>
3113 inline void
3114 RootNode<ChildT>::combine(RootNode& other, CombineOp& op, bool prune)
3115 {
3116 CombineArgs<ValueType> args;
3117
3118 CoordSet keys;
3119 this->insertKeys(keys);
3120 other.insertKeys(keys);
3121
3122 for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) {
3123 MapIter iter = findOrAddCoord(*i), otherIter = other.findOrAddCoord(*i);
3124 if (isTile(iter) && isTile(otherIter)) {
3125 // Both this node and the other node have constant values (tiles).
3126 // Combine the two values and store the result as this node's new tile value.
3127 op(args.setARef(getTile(iter).value)
3128 .setAIsActive(isTileOn(iter))
3129 .setBRef(getTile(otherIter).value)
3130 .setBIsActive(isTileOn(otherIter)));
3131 setTile(iter, Tile(args.result(), args.resultIsActive()));
3132
3133 } else if (isChild(iter) && isTile(otherIter)) {
3134 // Combine this node's child with the other node's constant value.
3135 ChildT& child = getChild(iter);
3136 child.combine(getTile(otherIter).value, isTileOn(otherIter), op);
3137
3138 } else if (isTile(iter) && isChild(otherIter)) {
3139 // Combine this node's constant value with the other node's child,
3140 // but use a new functor in which the A and B values are swapped,
3141 // since the constant value is the A value, not the B value.
3142 SwappedCombineOp<ValueType, CombineOp> swappedOp(op);
3143 ChildT& child = getChild(otherIter);
3144 child.combine(getTile(iter).value, isTileOn(iter), swappedOp);
3145
3146 // Steal the other node's child.
3147 setChild(iter, stealChild(otherIter, Tile()));
3148
3149 } else /*if (isChild(iter) && isChild(otherIter))*/ {
3150 // Combine this node's child with the other node's child.
3151 ChildT &child = getChild(iter), &otherChild = getChild(otherIter);
3152 child.combine(otherChild, op);
3153 }
3154 if (prune && isChild(iter)) getChild(iter).prune();
3155 }
3156
3157 // Combine background values.
3158 op(args.setARef(mBackground).setBRef(other.mBackground));
3159 mBackground = args.result();
3160
3161 // Empty the other tree so as not to leave it in a partially cannibalized state.
3162 other.clear();
3163 }
3164
3165
3167
3168
3169 // This helper class is a friend of RootNode and is needed so that combine2
3170 // can be specialized for compatible and incompatible pairs of RootNode types.
3171 template<typename CombineOp, typename RootT, typename OtherRootT, bool Compatible = false>
3172 struct RootNodeCombineHelper
3173 {
3174 static inline void combine2(RootT& self, const RootT&, const OtherRootT& other1,
3175 CombineOp&, bool)
3176 {
3177 // If the two root nodes have different configurations or incompatible ValueTypes,
3178 // throw an exception.
3179 self.enforceSameConfiguration(other1);
3180 self.enforceCompatibleValueTypes(other1);
3181 // One of the above two tests should throw, so we should never get here:
3182 std::ostringstream ostr;
3183 ostr << "cannot combine a " << typeid(OtherRootT).name()
3184 << " into a " << typeid(RootT).name();
3185 OPENVDB_THROW(TypeError, ostr.str());
3186 }
3187 };
3188
3189 // Specialization for root nodes of compatible types
3190 template<typename CombineOp, typename RootT, typename OtherRootT>
3191 struct RootNodeCombineHelper<CombineOp, RootT, OtherRootT, /*Compatible=*/true>
3192 {
3193 static inline void combine2(RootT& self, const RootT& other0, const OtherRootT& other1,
3194 CombineOp& op, bool prune)
3195 {
3196 self.doCombine2(other0, other1, op, prune);
3197 }
3198 };
3199
3200
3201 template<typename ChildT>
3202 template<typename CombineOp, typename OtherRootNode>
3203 inline void
3204 RootNode<ChildT>::combine2(const RootNode& other0, const OtherRootNode& other1,
3205 CombineOp& op, bool prune)
3206 {
3207 typedef typename OtherRootNode::ValueType OtherValueType;
3208 static const bool compatible = (SameConfiguration<OtherRootNode>::value
3209 && CanConvertType</*from=*/OtherValueType, /*to=*/ValueType>::value);
3210 RootNodeCombineHelper<CombineOp, RootNode, OtherRootNode, compatible>::combine2(
3211 *this, other0, other1, op, prune);
3212 }
3213
3214
3215 template<typename ChildT>
3216 template<typename CombineOp, typename OtherRootNode>
3217 inline void
3218 RootNode<ChildT>::doCombine2(const RootNode& other0, const OtherRootNode& other1,
3219 CombineOp& op, bool prune)
3220 {
3221 enforceSameConfiguration(other1);
3222
3223 typedef typename OtherRootNode::ValueType OtherValueT;
3224 typedef typename OtherRootNode::Tile OtherTileT;
3225 typedef typename OtherRootNode::NodeStruct OtherNodeStructT;
3226 typedef typename OtherRootNode::MapCIter OtherMapCIterT;
3227
3228 CombineArgs<ValueType, OtherValueT> args;
3229
3230 CoordSet keys;
3231 other0.insertKeys(keys);
3232 other1.insertKeys(keys);
3233
3234 const NodeStruct bg0(Tile(other0.mBackground, /*active=*/false));
3235 const OtherNodeStructT bg1(OtherTileT(other1.mBackground, /*active=*/false));
3236
3237 for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) {
3238 MapIter thisIter = this->findOrAddCoord(*i);
3239 MapCIter iter0 = other0.findKey(*i);
3240 OtherMapCIterT iter1 = other1.findKey(*i);
3241 const NodeStruct& ns0 = (iter0 != other0.mTable.end()) ? iter0->second : bg0;
3242 const OtherNodeStructT& ns1 = (iter1 != other1.mTable.end()) ? iter1->second : bg1;
3243 if (ns0.isTile() && ns1.isTile()) {
3244 // Both input nodes have constant values (tiles).
3245 // Combine the two values and add a new tile to this node with the result.
3246 op(args.setARef(ns0.tile.value)
3247 .setAIsActive(ns0.isTileOn())
3248 .setBRef(ns1.tile.value)
3249 .setBIsActive(ns1.isTileOn()));
3250 setTile(thisIter, Tile(args.result(), args.resultIsActive()));
3251 } else {
3252 if (!isChild(thisIter)) {
3253 // Add a new child with the same coordinates, etc. as the other node's child.
3254 const Coord& childOrigin =
3255 ns0.isChild() ? ns0.child->origin() : ns1.child->origin();
3256 setChild(thisIter, *(new ChildT(childOrigin, getTile(thisIter).value)));
3257 }
3258 ChildT& child = getChild(thisIter);
3259
3260 if (ns0.isTile()) {
3261 // Combine node1's child with node0's constant value
3262 // and write the result into this node's child.
3263 child.combine2(ns0.tile.value, *ns1.child, ns0.isTileOn(), op);
3264 } else if (ns1.isTile()) {
3265 // Combine node0's child with node1's constant value
3266 // and write the result into this node's child.
3267 child.combine2(*ns0.child, ns1.tile.value, ns1.isTileOn(), op);
3268 } else {
3269 // Combine node0's child with node1's child
3270 // and write the result into this node's child.
3271 child.combine2(*ns0.child, *ns1.child, op);
3272 }
3273 }
3274 if (prune && isChild(thisIter)) getChild(thisIter).prune();
3275 }
3276
3277 // Combine background values.
3278 op(args.setARef(other0.mBackground).setBRef(other1.mBackground));
3279 mBackground = args.result();
3280 }
3281
3282
3284
3285
3286 template<typename ChildT>
3287 template<typename BBoxOp>
3288 inline void
3289 RootNode<ChildT>::visitActiveBBox(BBoxOp& op) const
3290 {
3291 const bool descent = op.template descent<LEVEL>();
3292 for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) {
3293 if (this->isTileOff(i)) continue;
3294 if (this->isChild(i) && descent) {
3295 this->getChild(i).visitActiveBBox(op);
3296 } else {
3297 #ifdef _MSC_VER
3298 op.operator()<LEVEL>(CoordBBox::createCube(i->first, ChildT::DIM));
3299 #else
3300 op.template operator()<LEVEL>(CoordBBox::createCube(i->first, ChildT::DIM));
3301 #endif
3302 }
3303 }
3304 }
3305
3306
3307 template<typename ChildT>
3308 template<typename VisitorOp>
3309 inline void
3310 RootNode<ChildT>::visit(VisitorOp& op)
3311 {
3312 doVisit<RootNode, VisitorOp, ChildAllIter>(*this, op);
3313 }
3314
3315
3316 template<typename ChildT>
3317 template<typename VisitorOp>
3318 inline void
3319 RootNode<ChildT>::visit(VisitorOp& op) const
3320 {
3321 doVisit<const RootNode, VisitorOp, ChildAllCIter>(*this, op);
3322 }
3323
3324
3325 template<typename ChildT>
3326 template<typename RootNodeT, typename VisitorOp, typename ChildAllIterT>
3327 inline void
3328 RootNode<ChildT>::doVisit(RootNodeT& self, VisitorOp& op)
3329 {
3330 typename RootNodeT::ValueType val;
3331 for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) {
3332 if (op(iter)) continue;
3333 if (typename ChildAllIterT::ChildNodeType* child = iter.probeChild(val)) {
3334 child->visit(op);
3335 }
3336 }
3337 }
3338
3339
3341
3342
3343 template<typename ChildT>
3344 template<typename OtherRootNodeType, typename VisitorOp>
3345 inline void
3346 RootNode<ChildT>::visit2(OtherRootNodeType& other, VisitorOp& op)
3347 {
3348 doVisit2<RootNode, OtherRootNodeType, VisitorOp, ChildAllIter,
3349 typename OtherRootNodeType::ChildAllIter>(*this, other, op);
3350 }
3351
3352
3353 template<typename ChildT>
3354 template<typename OtherRootNodeType, typename VisitorOp>
3355 inline void
3356 RootNode<ChildT>::visit2(OtherRootNodeType& other, VisitorOp& op) const
3357 {
3358 doVisit2<const RootNode, OtherRootNodeType, VisitorOp, ChildAllCIter,
3359 typename OtherRootNodeType::ChildAllCIter>(*this, other, op);
3360 }
3361
3362
3363 template<typename ChildT>
3364 template<
3365 typename RootNodeT,
3366 typename OtherRootNodeT,
3367 typename VisitorOp,
3368 typename ChildAllIterT,
3369 typename OtherChildAllIterT>
3370 inline void
3371 RootNode<ChildT>::doVisit2(RootNodeT& self, OtherRootNodeT& other, VisitorOp& op)
3372 {
3373 enforceSameConfiguration(other);
3374
3375 typename RootNodeT::ValueType val;
3376 typename OtherRootNodeT::ValueType otherVal;
3377
3378 // The two nodes are required to have corresponding table entries,
3379 // but since that might require background tiles to be added to one or both,
3380 // and the nodes might be const, we operate on shallow copies of the nodes instead.
3381 RootNodeT copyOfSelf(self.mBackground);
3382 copyOfSelf.mTable = self.mTable;
3383 OtherRootNodeT copyOfOther(other.mBackground);
3384 copyOfOther.mTable = other.mTable;
3385
3386 // Add background tiles to both nodes as needed.
3387 CoordSet keys;
3388 self.insertKeys(keys);
3389 other.insertKeys(keys);
3390 for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) {
3391 copyOfSelf.findOrAddCoord(*i);
3392 copyOfOther.findOrAddCoord(*i);
3393 }
3394
3395 ChildAllIterT iter = copyOfSelf.beginChildAll();
3396 OtherChildAllIterT otherIter = copyOfOther.beginChildAll();
3397
3398 for ( ; iter && otherIter; ++iter, ++otherIter)
3399 {
3400 const size_t skipBranch = static_cast<size_t>(op(iter, otherIter));
3401
3402 typename ChildAllIterT::ChildNodeType* child =
3403 (skipBranch & 1U) ? NULL : iter.probeChild(val);
3404 typename OtherChildAllIterT::ChildNodeType* otherChild =
3405 (skipBranch & 2U) ? NULL : otherIter.probeChild(otherVal);
3406
3407 if (child != NULL && otherChild != NULL) {
3408 child->visit2Node(*otherChild, op);
3409 } else if (child != NULL) {
3410 child->visit2(otherIter, op);
3411 } else if (otherChild != NULL) {
3412 otherChild->visit2(iter, op, /*otherIsLHS=*/true);
3413 }
3414 }
3415 // Remove any background tiles that were added above,
3416 // as well as any that were created by the visitors.
3417 copyOfSelf.eraseBackgroundTiles();
3418 copyOfOther.eraseBackgroundTiles();
3419
3420 // If either input node is non-const, replace its table with
3421 // the (possibly modified) copy.
3422 self.resetTable(copyOfSelf.mTable);
3423 other.resetTable(copyOfOther.mTable);
3424 }
3425
3426 } // namespace tree
3427 } // namespace OPENVDB_VERSION_NAME
3428 } // namespace openvdb
3429
3430 #endif // OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED
3431
3432 // Copyright (c) 2012-2016 DreamWorks Animation LLC
3433 // All rights reserved. This software is distributed under the
3434 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v3_2_0::tree::RootNode::visit2
void visit2(OtherRootNodeType &other, VisitorOp &)
Definition: RootNode.h:3346
openvdb::v3_2_0::tree::RootNode::probeConstNode
const NodeT * probeConstNode(const Coord &xyz) const
Return a pointer to the node that contains voxel (x, y, z). If no such node exists, return NULL.
Definition: RootNode.h:2680
openvdb::v3_2_0::tree::NodeChain
NodeChain<RootNodeType, RootNodeType::LEVEL>::Type is a boost::mpl::vector that lists the types of th...
Definition: RootNode.h:68
openvdb::v3_2_0::tree::RootNode::ValueConverter::Type
RootNode< typename ChildType::template ValueConverter< OtherValueType >::Type > Type
Definition: RootNode.h:93
openvdb::v3_2_0::CombineArgs::resultIsActive
bool resultIsActive() const
Definition: Types.h:376
openvdb::v3_2_0::tree::RootNode::nonLeafCount
Index32 nonLeafCount() const
Definition: RootNode.h:1562
openvdb::v3_2_0::tree::RootNode::ValueOffIter
ValueIter< RootNode, MapIter, ValueOffPred, ValueType > ValueOffIter
Definition: RootNode.h:403
openvdb::v3_2_0::util::RootNodeMask
Definition: NodeMasks.h:1068
openvdb::v3_2_0::tree::RootNode::setValueOnlyAndCache
void setValueOnlyAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition: RootNode.h:1895
openvdb::v3_2_0::tree::RootNode::clip
void clip(const CoordBBox &)
Set all voxels that lie outside the given axis-aligned box to the background.
Definition: RootNode.h:2381
openvdb::v3_2_0::tree::RootNode::offLeafVoxelCount
Index64 offLeafVoxelCount() const
Definition: RootNode.h:1620
openvdb::v3_2_0::tree::RootNode::modifyValue
void modifyValue(const Coord &xyz, const ModifyOp &op)
Apply a functor to the value of the voxel at the given coordinates and mark the voxel as active...
Definition: RootNode.h:1918
openvdb::v3_2_0::math::Coord::minComponent
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:191
Types.h
openvdb::v3_2_0::tree::RootNode::cbeginValueAll
ValueAllCIter cbeginValueAll() const
Definition: RootNode.h:421
openvdb::v3_2_0::tree::RootNode::cbeginValueOff
ValueOffCIter cbeginValueOff() const
Definition: RootNode.h:420
Compression.h
openvdb::v3_2_0::tree::RootNode::eraseBackgroundTiles
size_t eraseBackgroundTiles()
Remove all background tiles.
Definition: RootNode.h:1268
openvdb::v3_2_0::tree::RootNode::addLeaf
void addLeaf(LeafNodeType *leaf)
Add the given leaf node to this tree, creating a new branch if necessary. If a leaf node with the sam...
Definition: RootNode.h:2461
openvdb::v3_2_0::math::isExactlyEqual
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:407
openvdb::v3_2_0::math::Coord::setX
Coord & setX(Int32 x)
Definition: Coord.h:101
openvdb::v3_2_0::util::RootNodeMask::isOn
bool isOn(Index32 i) const
Definition: NodeMasks.h:1334
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
openvdb::v3_2_0::tree::RootNode::writeBuffers
void writeBuffers(std::ostream &, bool toHalf=false) const
Definition: RootNode.h:2337
openvdb::v3_2_0::tree::RootNode::getValueDepth
int getValueDepth(const Coord &xyz) const
Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides.
Definition: RootNode.h:1705
openvdb::v3_2_0::tools::copyToDense
void copyToDense(const GridOrTreeT &sparse, DenseT &dense, bool serial=false)
Populate a dense grid with the values of voxels from a sparse grid, where the sparse grid intersects ...
Definition: Dense.h:443
openvdb::v3_2_0::tree::RootNode::getNodeLog2Dims
static void getNodeLog2Dims(std::vector< Index > &dims)
Definition: RootNode.h:1321
openvdb::v3_2_0::TopologyCopy
Definition: Types.h:442
openvdb::v3_2_0::tree::RootNode::RootNode
RootNode(const RootNode &other)
Definition: RootNode.h:111
openvdb::v3_2_0::tree::NodeChain< HeadT, 1 >::Type
boost::mpl::vector< typename HeadT::ChildNodeType, HeadT >::type Type
Definition: RootNode.h:1023
openvdb::v3_2_0::tree::RootNode::touchLeafAndCache
LeafNodeType * touchLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as touchLeaf() but, if necessary, update the given accessor with pointers to the nodes along the...
openvdb::v3_2_0::tree::RootNodeCopyHelper
Definition: RootNode.h:70
openvdb::v3_2_0::tree::RootNode::numBackgroundTiles
size_t numBackgroundTiles() const
Return the number of background tiles.
Definition: RootNode.h:1256
openvdb::v3_2_0::tree::RootNode::setValueAndCache
void setValueAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition: RootNode.h:1854
openvdb::v3_2_0::util::FindHighestOn
Index32 FindHighestOn(Index32 v)
Return the most significant on bit of the given 32-bit value.
Definition: NodeMasks.h:151
openvdb::v3_2_0::tree::RootNode::readBuffers
void readBuffers(std::istream &, bool fromHalf=false)
Definition: RootNode.h:2347
openvdb::v3_2_0::tree::RootNode::NodeChainType
NodeChain< RootNode, LEVEL >::Type NodeChainType
NodeChainType is a list of this tree&#39;s node types, from LeafNodeType to RootNode. ...
Definition: RootNode.h:86
openvdb::v3_2_0::tree::RootNode::ChildOffCIter
ValueIter< const RootNode, MapCIter, ChildOffPred, ValueType > ChildOffCIter
Definition: RootNode.h:397
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:97
openvdb::v3_2_0::tree::RootNode::onVoxelCount
Index64 onVoxelCount() const
Definition: RootNode.h:1576
openvdb::v3_2_0::tree::RootNode::onTileCount
Index64 onTileCount() const
Definition: RootNode.h:1631
openvdb::v3_2_0::MERGE_ACTIVE_STATES
Definition: Types.h:265
openvdb::v3_2_0::tree::RootNode::ValueOffCIter
ValueIter< const RootNode, MapCIter, ValueOffPred, const ValueType > ValueOffCIter
Definition: RootNode.h:404
openvdb::v3_2_0::tree::RootNode::denseFill
void denseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value.
Definition: RootNode.h:2134
openvdb::v3_2_0::tree::RootNode::getHeight
Index getHeight() const
Definition: RootNode.h:490
openvdb::v3_2_0::io::truncateRealToHalf
T truncateRealToHalf(const T &val)
Return the given value truncated to 16-bit float precision.
Definition: Compression.h:153
openvdb::v3_2_0::CombineArgs::setARef
CombineArgs & setARef(const AValueType &a)
Redirect the A value to a new external source.
Definition: Types.h:365
openvdb::v3_2_0::tree::RootNode::isBackgroundTile
bool isBackgroundTile(const Tile &) const
Return true if the given tile is inactive and has the background value.
Definition: RootNode.h:1234
openvdb::v3_2_0::tree::RootNode::readTopology
bool readTopology(std::istream &, bool fromHalf=false)
Definition: RootNode.h:2223
openvdb::v3_2_0::tree::RootNode::setValueOn
void setValueOn(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as active. ...
Definition: RootNode.h:1835
openvdb::v3_2_0::tree::RootNode::beginChildAll
ChildAllIter beginChildAll()
Definition: RootNode.h:417
openvdb::v3_2_0::tree::RootNode::getNodes
void getNodes(ArrayT &array)
Adds all nodes of a certain type to a container with the following API:
Definition: RootNode.h:2781
openvdb::v3_2_0::tree::RootNode::copyToDense
void copyToDense(const CoordBBox &bbox, DenseT &dense) const
Copy into a dense grid the values of all voxels, both active and inactive, that intersect a given bou...
Definition: RootNode.h:2143
openvdb::v3_2_0::tree::RootNode::BOOST_STATIC_ASSERT
BOOST_STATIC_ASSERT(boost::mpl::size< NodeChainType >::value==LEVEL+1)
openvdb::v3_2_0::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:47
openvdb::v3_2_0::tree::NodeChain::SubtreeT
NodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
Definition: RootNode.h:1016
openvdb::v3_2_0::math::operator*
Mat3< typename promote< T0, T1 >::type > operator*(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Matrix multiplication.
Definition: Mat3.h:658
openvdb::v3_2_0::tree::RootNode::leafCount
Index32 leafCount() const
Definition: RootNode.h:1550
openvdb::v3_2_0::tree::RootNode::ValueType
ChildType::ValueType ValueType
Definition: RootNode.h:80
openvdb::v3_2_0::SwappedCombineOp
Definition: Types.h:403
openvdb::v3_2_0::tree::RootNode::prune
void prune(const ValueType &tolerance=zeroVal< ValueType >())
Reduce the memory footprint of this tree by replacing with tiles any nodes whose values are all the s...
Definition: RootNode.h:2421
openvdb::v3_2_0::tree::RootNode::operator=
RootNode & operator=(const RootNode &other)
Copy a root node of the same type as this node.
Definition: RootNode.h:1172
BBox.h
openvdb::v3_2_0::tree::RootNode::hasActiveTiles
bool hasActiveTiles() const
Definition: RootNode.h:1658
openvdb::v3_2_0::math::Coord::x
Int32 x() const
Definition: Coord.h:146
openvdb::v3_2_0::tree::RootNode::beginChildOff
ChildOffCIter beginChildOff() const
Definition: RootNode.h:413
openvdb::v3_2_0::tree::RootNode::evalActiveBoundingBox
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
Expand the specified bbox so it includes the active tiles of this root node as well as all the active...
Definition: RootNode.h:1489
openvdb::v3_2_0::tree::RootNodeCopyHelper::copyWithValueConversion
static void copyWithValueConversion(RootT &self, const OtherRootT &other)
Definition: RootNode.h:1116
openvdb::v3_2_0::tree::RootNode::topologyDifference
void topologyDifference(const RootNode< OtherChildType > &other)
Difference this tree&#39;s set of active values with the active values of the other tree, whose ValueType may be different. So a resulting voxel will be active only if the original voxel is active in this tree and inactive in the other tree.
Definition: RootNode.h:3075
openvdb::v3_2_0::tree::RootNode::getDepth
Index getDepth() const
Definition: RootNode.h:491
openvdb::v3_2_0::tree::RootNode::ValueConverter
ValueConverter<T>::Type is the type of a RootNode having the same child hierarchy as this node but a ...
Definition: RootNode.h:92
openvdb::v3_2_0::tree::RootNode::beginChildOn
ChildOnIter beginChildOn()
Definition: RootNode.h:415
openvdb::v3_2_0::tree::RootNode::BuildType
ChildType::BuildType BuildType
Definition: RootNode.h:81
openvdb::v3_2_0::tree::RootNode::getNodeBoundingBox
static CoordBBox getNodeBoundingBox()
Return the bounding box of this RootNode, i.e., an infinite bounding box.
Definition: RootNode.h:440
openvdb::v3_2_0::tree::RootNode::beginChildOff
ChildOffIter beginChildOff()
Definition: RootNode.h:416
openvdb::v3_2_0::tree::RootNode::addTile
void addTile(const Coord &xyz, const ValueType &value, bool state)
Add a tile containing voxel (x, y, z) at the root level, deleting the existing branch if necessary...
Definition: RootNode.h:2530
openvdb::v3_2_0::tree::RootNode::combine2
void combine2(const RootNode &other0, const OtherRootNode &other1, CombineOp &op, bool prune=false)
Definition: RootNode.h:3204
openvdb::v3_2_0::tree::RootNode::voxelizeActiveTiles
void voxelizeActiveTiles(bool threaded=true)
Densify active tiles, i.e., replace them with leaf-level active voxels.
Definition: RootNode.h:2866
openvdb::v3_2_0::tree::RootNode::ChildOffIter
ValueIter< RootNode, MapIter, ChildOffPred, const ValueType > ChildOffIter
Definition: RootNode.h:396
openvdb::v3_2_0::math::CoordBBox::inf
static CoordBBox inf()
Return an "infinite" bounding box, as defined by the Coord value range.
Definition: Coord.h:330
openvdb::v3_2_0::math::Coord::setY
Coord & setY(Int32 y)
Definition: Coord.h:102
openvdb::v3_2_0::math::Coord::lessThan
static bool lessThan(const Coord &a, const Coord &b)
Definition: Coord.h:224
openvdb::v3_2_0::math::isApproxEqual
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:370
openvdb::v3_2_0::tree::RootNode::ChildOnIter
ChildIter< RootNode, MapIter, ChildOnPred, ChildType > ChildOnIter
Definition: RootNode.h:394
openvdb::v3_2_0::Index
Index32 Index
Definition: Types.h:58
openvdb::v3_2_0::tree::RootNode::ChildAllIter
DenseIter< RootNode, MapIter, ChildType, ValueType > ChildAllIter
Definition: RootNode.h:398
openvdb::v3_2_0::tree::RootNode::probeConstLeaf
const LeafNodeType * probeConstLeaf(const Coord &xyz) const
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return NULL.
Definition: RootNode.h:2705
openvdb::v3_2_0::tree::RootNode::offVoxelCount
Index64 offVoxelCount() const
Definition: RootNode.h:1592
openvdb::v3_2_0::Int32
int32_t Int32
Definition: Types.h:60
openvdb::v3_2_0::tree::RootNode::beginValueAll
ValueAllIter beginValueAll()
Definition: RootNode.h:427
openvdb::v3_2_0::tree::RootNode::getValueAndCache
const ValueType & getValueAndCache(const Coord &xyz, AccessorT &) const
openvdb::v3_2_0::Index64
uint64_t Index64
Definition: Types.h:57
Exceptions.h
openvdb::v3_2_0::tree::RootNode::ChildAllCIter
DenseIter< const RootNode, MapCIter, const ChildType, const ValueType > ChildAllCIter
Definition: RootNode.h:399
openvdb::v3_2_0::tree::RootNode::stealNodes
void stealNodes(ArrayT &array)
Steals all nodes of a certain type from the tree and adds them to a container with the following API:...
Definition: RootNode.h:827
openvdb::v3_2_0::tree::RootNode::beginValueAll
ValueAllCIter beginValueAll() const
Definition: RootNode.h:424
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
Definition: version.h:43
openvdb::v3_2_0::tree::RootNode::LeafNodeType
ChildType::LeafNodeType LeafNodeType
Definition: RootNode.h:79
openvdb::v3_2_0::tools::clip
OPENVDB_STATIC_SPECIALIZATION GridType::Ptr clip(const GridType &grid, const BBoxd &)
Clip the given grid against a world-space bounding box and return a new grid containing the result...
Definition: Clip.h:356
openvdb::v3_2_0::tree::RootNode::stealNodes
void stealNodes(ArrayT &array, const ValueType &value, bool state)
Steals all nodes of a certain type from the tree and adds them to a container with the following API:...
Definition: RootNode.h:2836
openvdb::v3_2_0::tree::RootNode::beginValueOff
ValueOffCIter beginValueOff() const
Definition: RootNode.h:423
openvdb::v3_2_0::tree::RootNode::probeLeafAndCache
LeafNodeType * probeLeafAndCache(const Coord &xyz, AccessorT &acc)
Same as probeLeaf() but, if necessary, update the given accessor with pointers to the nodes along the...
openvdb::v3_2_0::tree::RootNode::probeNodeAndCache
NodeT * probeNodeAndCache(const Coord &xyz, AccessorT &acc)
Same as probeNode() but, if necessary, update the given accessor with pointers to the nodes along the...
Definition: RootNode.h:2741
openvdb::v3_2_0::math::Coord::setZ
Coord & setZ(Int32 z)
Definition: Coord.h:103
openvdb::v3_2_0::tree::RootNode::hasSameTopology
bool hasSameTopology(const RootNode< OtherChildType > &other) const
Return true if the given tree has the same node and active value topology as this tree (but possibly ...
Definition: RootNode.h:1358
openvdb::v3_2_0::tree::RootNode::stealNode
NodeT * stealNode(const Coord &xyz, const ValueType &value, bool state)
Return a pointer to the node of type NodeT that contains voxel (x, y, z) and replace it with a tile o...
Definition: RootNode.h:2442
openvdb::v3_2_0::tree::RootNode::~RootNode
~RootNode()
Definition: RootNode.h:159
openvdb::v3_2_0::math::CoordBBox::expand
void expand(ValueType padding)
Pad this bounding box with the specified padding.
Definition: Coord.h:401
openvdb::v3_2_0::io::setGridBackgroundValuePtr
OPENVDB_API void setGridBackgroundValuePtr(std::ios_base &, const void *background)
Specify (a pointer to) the background value of the grid currently being read from or written to the g...
openvdb::v3_2_0::tree::RootNode::addLeafAndCache
void addLeafAndCache(LeafNodeType *leaf, AccessorT &)
Same as addLeaf() but, if necessary, update the given accessor with pointers to the nodes along the p...
Definition: RootNode.h:2496
openvdb::v3_2_0::tree::RootNode::SameConfiguration
SameConfiguration<OtherNodeType>::value is true if and only if OtherNodeType is the type of a RootNod...
Definition: RootNode.h:100
openvdb::v3_2_0::tree::RootNode::hasSameConfiguration
static bool hasSameConfiguration(const RootNode< OtherChildType > &other)
Return false if the other node&#39;s dimensions don&#39;t match this node&#39;s.
Definition: RootNode.h:1405
openvdb::v3_2_0::OPENVDB_FILE_VERSION_ROOTNODE_MAP
Definition: version.h:100
openvdb::v3_2_0::CombineArgs::result
const AValueType & result() const
Get the output value.
Definition: Types.h:357
openvdb::v3_2_0::tree::RootNode::modifyValueAndCache
void modifyValueAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: RootNode.h:1950
openvdb::v3_2_0::tree::RootNode::ValueAllIter
ValueIter< RootNode, MapIter, ValueAllPred, ValueType > ValueAllIter
Definition: RootNode.h:405
openvdb::v3_2_0::tree::RootNodeCombineHelper::combine2
static void combine2(RootT &self, const RootT &, const OtherRootT &other1, CombineOp &, bool)
Definition: RootNode.h:3174
openvdb::v3_2_0::util::RootNodeMask::load
void load(std::istream &is)
Definition: NodeMasks.h:1375
openvdb::v3_2_0::tree::RootNode::modifyValueAndActiveState
void modifyValueAndActiveState(const Coord &xyz, const ModifyOp &op)
Apply a functor to the voxel at the given coordinates.
Definition: RootNode.h:1986
openvdb::v3_2_0::io::getFormatVersion
OPENVDB_API uint32_t getFormatVersion(std::ios_base &)
Return the file format version number associated with the given input stream.
openvdb::v3_2_0::tree::RootNode::setValueOff
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don&#39;t change its value.
Definition: RootNode.h:1727
openvdb::v3_2_0::tree::RootNode::combine
void combine(RootNode &other, CombineOp &, bool prune=false)
Definition: RootNode.h:3114
openvdb::v3_2_0::math::CoordBBox::translate
void translate(const Coord &t)
Translate this bounding box by .
Definition: Coord.h:440
openvdb::v3_2_0::math::Coord::offsetBy
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:111
openvdb::v3_2_0::tree::RootNode::beginValueOn
ValueOnCIter beginValueOn() const
Definition: RootNode.h:422
openvdb::v3_2_0::tree::RootNode::fill
void fill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value.
Definition: RootNode.h:2079
openvdb::v3_2_0::tree::RootNode::probeNode
NodeT * probeNode(const Coord &xyz)
Return a pointer to the node that contains voxel (x, y, z). If no such node exists, return NULL.
Definition: RootNode.h:2662
openvdb::v3_2_0::tree::RootNode::empty
bool empty() const
Return true if this node&#39;s table is either empty or contains only background tiles.
Definition: RootNode.h:475
openvdb::v3_2_0::tree::RootNode::clear
void clear()
Definition: RootNode.h:1478
openvdb::v3_2_0::tree::RootNode::beginValueOn
ValueOnIter beginValueOn()
Definition: RootNode.h:425
openvdb::v3_2_0::CanConvertType
CanConvertType<FromType, ToType>::value is true if a value of type ToType can be constructed from a v...
Definition: Types.h:183
openvdb
Definition: Exceptions.h:39
openvdb::v3_2_0::tree::RootNodeCopyHelper< RootT, OtherRootT, true >::copyWithValueConversion
static void copyWithValueConversion(RootT &self, const OtherRootT &other)
Definition: RootNode.h:1134
openvdb::v3_2_0::Index32
uint32_t Index32
Definition: Types.h:56
openvdb::v3_2_0::tree::SameRootConfig
Definition: RootNode.h:69
openvdb::v3_2_0::tree::RootNode::beginChildOn
ChildOnCIter beginChildOn() const
Definition: RootNode.h:412
OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:129
openvdb::v3_2_0::tree::RootNode::probeLeaf
LeafNodeType * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, return NULL.
Definition: RootNode.h:2697
openvdb::v3_2_0::tree::RootNode::cbeginChildOn
ChildOnCIter cbeginChildOn() const
Definition: RootNode.h:409
openvdb::v3_2_0::tree::RootNodeCombineHelper< CombineOp, RootT, OtherRootT, true >::combine2
static void combine2(RootT &self, const RootT &other0, const OtherRootT &other1, CombineOp &op, bool prune)
Definition: RootNode.h:3193
openvdb::v3_2_0::tree::RootNode::beginChildAll
ChildAllCIter beginChildAll() const
Definition: RootNode.h:414
openvdb::v3_2_0::tree::NodeChain::Type
boost::mpl::push_back< SubtreeT, HeadT >::type Type
Definition: RootNode.h:1017
openvdb::v3_2_0::tree::RootNode::setActiveStateAndCache
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Definition: RootNode.h:1764
openvdb::v3_2_0::tree::RootNode::getTableSize
Index getTableSize() const
Return the number of entries in this node&#39;s table.
Definition: RootNode.h:487
openvdb::v3_2_0::tree::RootNode::topologyIntersection
void topologyIntersection(const RootNode< OtherChildType > &other)
Intersects this tree&#39;s set of active values with the active values of the other tree, whose ValueType may be different.
Definition: RootNode.h:3039
openvdb::v3_2_0::tree::RootNode::setValueOnly
void setValueOnly(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates but don&#39;t change its active state.
Definition: RootNode.h:1876
openvdb::v3_2_0::tree::RootNode::ChildOnCIter
ChildIter< const RootNode, MapCIter, ChildOnPred, const ChildType > ChildOnCIter
Definition: RootNode.h:395
openvdb::v3_2_0::tree::RootNode::RootNode
RootNode(const RootNode< OtherChildType > &other)
Construct a new tree that reproduces the topology and active states of a tree of a different ValueTyp...
Definition: RootNode.h:120
openvdb::v3_2_0::tree::RootNode::isValueOnAndCache
bool isValueOnAndCache(const Coord &xyz, AccessorT &) const
Definition: RootNode.h:1669
openvdb::v3_2_0::tree::RootNode::setValueOffAndCache
void setValueOffAndCache(const Coord &xyz, const ValueType &value, AccessorT &)
Definition: RootNode.h:1811
openvdb::v3_2_0::tree::RootNode::RootNode
RootNode()
Construct a new tree with a background value of 0.
Definition: RootNode.h:1050
openvdb::v3_2_0::tree::RootNode::ValueOnCIter
ValueIter< const RootNode, MapCIter, ValueOnPred, const ValueType > ValueOnCIter
Definition: RootNode.h:402
openvdb::v3_2_0::math::Coord::z
Int32 z() const
Definition: Coord.h:148
openvdb::v3_2_0::tree::RootNode::getIndexRange
void getIndexRange(CoordBBox &bbox) const
Return the current index range. Both min and max are inclusive.
Definition: RootNode.h:1345
openvdb::v3_2_0::tree::RootNode::visitActiveBBox
void visitActiveBBox(BBoxOp &) const
Call the templated functor BBoxOp with bounding box information for all active tiles and leaf nodes i...
Definition: RootNode.h:3289
openvdb::v3_2_0::tree::RootNode::getValue
const ValueType & getValue(const Coord &xyz) const
Definition: RootNode.h:1681
version.h
openvdb::v3_2_0::tree::RootNode::touchLeaf
LeafNodeType * touchLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z). If no such node exists, create one that preserves the values and active states of all voxels.
Definition: RootNode.h:2618
openvdb::v3_2_0::TypeError
Definition: Exceptions.h:87
openvdb::v3_2_0::tree::RootNode::getMinIndex
Coord getMinIndex() const
Return the smallest index of the current tree.
Definition: RootNode.h:1330
openvdb::v3_2_0::tree::RootNode::topologyUnion
void topologyUnion(const RootNode< OtherChildType > &other)
Union this tree&#39;s set of active values with the active values of the other tree, whose ValueType may ...
Definition: RootNode.h:3003
openvdb::v3_2_0::math::CoordBBox::min
const Coord & min() const
Definition: Coord.h:332
openvdb::v3_2_0::tree::RootNode::background
const ValueType & background() const
Return this node&#39;s background value.
Definition: RootNode.h:457
openvdb::v3_2_0::tree::RootNode::getLevel
static Index getLevel()
Definition: RootNode.h:482
openvdb::v3_2_0::tree::RootNode::getValueDepthAndCache
int getValueDepthAndCache(const Coord &xyz, AccessorT &) const
Definition: RootNode.h:1715
openvdb::v3_2_0::math::operator==
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:450
openvdb::v3_2_0::math::CoordBBox::hasOverlap
bool hasOverlap(const CoordBBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition: Coord.h:395
openvdb::v3_2_0::math::CoordBBox::max
const Coord & max() const
Definition: Coord.h:333
OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:130
openvdb::v3_2_0::tree::RootNodeCombineHelper
Definition: RootNode.h:71
openvdb::v3_2_0::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:259
openvdb::v3_2_0::tree::RootNode::memUsage
Index64 memUsage() const
Return the total amount of memory in bytes occupied by this node and its children.
Definition: RootNode.h:1464
openvdb::v3_2_0::tree::RootNode::cbeginChildAll
ChildAllCIter cbeginChildAll() const
Definition: RootNode.h:411
openvdb::v3_2_0::tree::RootNode::isValueOn
bool isValueOn(const Coord &xyz) const
Definition: RootNode.h:1649
openvdb::v3_2_0::MERGE_ACTIVE_STATES_AND_NODES
Definition: Types.h:267
openvdb::v3_2_0::tree::RootNode::ValueAllCIter
ValueIter< const RootNode, MapCIter, ValueAllPred, const ValueType > ValueAllCIter
Definition: RootNode.h:406
openvdb::v3_2_0::tree::RootNode::probeValueAndCache
bool probeValueAndCache(const Coord &xyz, ValueType &value, AccessorT &) const
Definition: RootNode.h:2060
openvdb::v3_2_0::math::Coord::read
void read(std::istream &is)
Definition: Coord.h:235
openvdb::v3_2_0::math::Coord::y
Int32 y() const
Definition: Coord.h:147
openvdb::v3_2_0::tree::RootNode::setActiveState
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don&#39;t change its value.
Definition: RootNode.h:1741
openvdb::v3_2_0::ValueError
Definition: Exceptions.h:88
openvdb::v3_2_0::math::operator!=
bool operator!=(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Inequality operator, does exact floating point comparisons.
Definition: Vec3.h:458
openvdb::v3_2_0::tree::RootNode::probeValue
bool probeValue(const Coord &xyz, ValueType &value) const
Definition: RootNode.h:2044
openvdb::v3_2_0::tools::prune
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition: Prune.h:374
openvdb::v3_2_0::tree::RootNode::writeTopology
bool writeTopology(std::ostream &, bool toHalf=false) const
Definition: RootNode.h:2187
openvdb::v3_2_0::tree::RootNode::ChildNodeType
ChildType ChildNodeType
Definition: RootNode.h:78
openvdb::v3_2_0::tree::RootNode::getWidth
Index getWidth() const
Definition: RootNode.h:489
openvdb::v3_2_0::tree::RootNode::sparseFill
void sparseFill(const CoordBBox &bbox, const ValueType &value, bool active=true)
Set all voxels within a given axis-aligned box to a constant value.
Definition: RootNode.h:563
openvdb::v3_2_0::tree::RootNode::hasCompatibleValueType
static bool hasCompatibleValueType(const RootNode< OtherChildType > &other)
Definition: RootNode.h:1437
openvdb::v3_2_0::tree::RootNode::expand
bool expand(const Coord &xyz)
Expand this node&#39;s table so that (x, y, z) is included in the index range.
Definition: RootNode.h:1307
openvdb::v3_2_0::tree::RootNode::visit
void visit(VisitorOp &)
Definition: RootNode.h:3310
openvdb::v3_2_0::tree::RootNode::cbeginChildOff
ChildOffCIter cbeginChildOff() const
Definition: RootNode.h:410
openvdb::v3_2_0::math::negative
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:116
NodeMasks.h
openvdb::v3_2_0::tree::RootNode::beginValueOff
ValueOffIter beginValueOff()
Definition: RootNode.h:426
openvdb::v3_2_0::math::CoordBBox::isInside
bool isInside(const Coord &xyz) const
Return true if point (x, y, z) is inside this bounding box.
Definition: Coord.h:383
openvdb::v3_2_0::PartialCreate
Definition: Types.h:444
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
openvdb::v3_2_0::tree::RootNode::setBackground
void setBackground(const ValueType &value, bool updateChildNodes)
Change inactive tiles or voxels with a value equal to +/- the old background to the specified value (...
Definition: RootNode.h:1207
openvdb::v3_2_0::tree::RootNode::ValueOnIter
ValueIter< RootNode, MapIter, ValueOnPred, ValueType > ValueOnIter
Definition: RootNode.h:401
openvdb::v3_2_0::MERGE_NODES
Definition: Types.h:266
openvdb::v3_2_0::tree::RootNode::merge
void merge(RootNode &other)
Efficiently merge another tree into this tree using one of several schemes.
Definition: RootNode.h:2891
openvdb::v3_2_0::tree::RootNode::modifyValueAndActiveStateAndCache
void modifyValueAndActiveStateAndCache(const Coord &xyz, const ModifyOp &op, AccessorT &)
Definition: RootNode.h:2013
openvdb::v3_2_0::math::CoordBBox::empty
bool empty() const
Definition: Coord.h:350
openvdb::v3_2_0::math::Coord::asPointer
const Int32 * asPointer() const
Definition: Coord.h:157
openvdb::v3_2_0::tree::RootNode::probeConstNodeAndCache
const NodeT * probeConstNodeAndCache(const Coord &xyz, AccessorT &acc) const
Same as probeNode() but, if necessary, update the given accessor with pointers to the nodes along the...
Definition: RootNode.h:2760
openvdb::v3_2_0::CombineArgs
This struct collects both input and output arguments to "grid combiner" functors used with the tree::...
Definition: Types.h:312
openvdb::v3_2_0::tree::RootNode::getMaxIndex
Coord getMaxIndex() const
Return the largest index of the current tree.
Definition: RootNode.h:1337
openvdb::v3_2_0::tree::RootNode::onLeafVoxelCount
Index64 onLeafVoxelCount() const
Definition: RootNode.h:1608
openvdb::v3_2_0::tree::RootNode::cbeginValueOn
ValueOnCIter cbeginValueOn() const
Definition: RootNode.h:419
openvdb::v3_2_0::tree::RootNode::probeConstLeafAndCache
const LeafNodeType * probeConstLeafAndCache(const Coord &xyz, AccessorT &acc) const
Same as probeLeaf() but, if necessary, update the given accessor with pointers to the nodes along the...
openvdb::v3_2_0::tree::RootNode
Definition: RootNode.h:75
openvdb::v3_2_0::tree::RootNode::getChildDim
static Index getChildDim()
Definition: RootNode.h:484
openvdb::v3_2_0::tree::RootNode::addTileAndCache
void addTileAndCache(Index level, const Coord &xyz, const ValueType &, bool state, AccessorT &)
Same as addTile() but, if necessary, update the given accessor with pointers to the nodes along the p...
Definition: RootNode.h:2577
openvdb::v3_2_0::math::CoordBBox::createCube
static CoordBBox createCube(const Coord &min, ValueType dim)
Definition: Coord.h:324
openvdb::v3_2_0::zeroVal
T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:94
openvdb::v3_2_0::tools::composite::min
const boost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:128