OpenVDB: RootNode.h Source File

OpenVDB 3.1.0

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

- File List
- File Members

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