1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 \*---------------------------------------------------------------------------*/
32 #include "treeBoundBox.H"
33 #include <OpenFOAM/long.H>
34 #include <OpenFOAM/linePointRef.H>
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 const Foam::label Foam::treeNode<Type>::leafOffset(100);
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 void Foam::treeNode<Type>::setAsNode(const label octant)
47 subNodeTypes_ |= (0x1 << octant);
52 void Foam::treeNode<Type>::setAsLeaf(const label octant)
54 subNodeTypes_ &= ~(0x1 << octant);
58 // Set pointer to sub node
60 void Foam::treeNode<Type>::setNodePtr
63 treeElem<Type>* treeNodePtr
67 subNodes_[octant] = treeNodePtr;
71 // Set pointer to sub leaf
73 void Foam::treeNode<Type>::setLeafPtr
76 treeElem<Type>* treeLeafPtr
80 subNodes_[octant] = treeLeafPtr;
85 void Foam::treeNode<Type>::setVolType
91 if ((type < 0) || (type > 3))
93 FatalErrorIn("treeNode<Type>::setVolType(const label, const label)")
94 << "Type " << type << " not within range 0..3" << endl;
97 // Clear out two bits at position 2*octant
98 volType_ &= ~(0x3 << 2*octant);
100 // Add the two bits of type
101 volType_ |= (type << 2*octant);
105 template <class Type>
106 void Foam::treeNode<Type>::space(Ostream& os, const label n)
108 for (label i=0; i<n; i++)
115 // look in single octant starting from <start>
116 template <class Type>
117 const Foam::treeLeaf<Type>* Foam::treeNode<Type>::findLeafLineOctant
122 const vector& direction,
127 static const char* functionName =
128 "treeNode<Type>::findLeafLineOctant"
129 "(const int, const Type&, const label, const vector&,"
130 " point&, const point&)";
134 space(Pout, 2*level);
135 Pout<< "findLeafLineOctant : bb:" << this->bb()
136 << " start:" << start
138 << " mid:" << midpoint()
139 << " Searching octant:" << octant
143 if (subNodes()[octant])
147 // Node: recurse into subnodes
148 const treeNode<Type>* subNodePtr = getNodePtr(octant);
150 if (subNodePtr->bb().contains(direction, start))
152 // Search on lower level
153 const treeLeaf<Type>* subLeafPtr = subNodePtr->findLeafLine
163 space(Pout, 2*level);
164 Pout<< "findLeafLineOctant : bb:" << this->bb()
165 << " returning from sub treeNode"
166 << " with start:" << start << " subLeaf:"
167 << long(subLeafPtr) << endl;
174 FatalErrorIn(functionName)
175 << "Sub node " << subNodePtr->bb()
176 << " at octant " << octant
177 << " does not contain start " << start
178 << abort(FatalError);
184 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
186 if (subLeafPtr->bb().contains(direction, start))
188 // Step to end of subleaf bb
192 !subLeafPtr->bb().intersects
200 FatalErrorIn(functionName)
201 << "Sub leaf contains start " << start
202 << " but line does not intersect its bb "
204 << abort(FatalError);
210 space(Pout, 2*level);
211 Pout<< "findLeafLineOctant : returning from intersecting"
212 << " treeLeaf " << subLeafPtr->bb()
213 << " with start:" << start << " subLeaf:"
214 << long(subLeafPtr) << endl;
221 FatalErrorIn(functionName)
222 << "Sub leaf " << subLeafPtr->bb()
223 << " at octant " << octant
224 << " does not contain start " << start
225 << abort(FatalError);
231 // Empty subNode. Transfer across.
232 const treeBoundBox emptyBb = this->bb().subBbox(midpoint(), octant);
234 if (emptyBb.contains(direction, start))
238 space(Pout, 2*level);
239 Pout<< "findLeafLineOctant : Empty node. Octant:" << octant
240 << " start:" << start
241 << " bb:" << this->bb()
242 << " emptyBb:" << emptyBb << endl;
245 // Update start by clipping to emptyBb
257 FatalErrorIn(functionName)
258 << "Empty node contains start " << start
259 << " but line does not intersect its (calculated)"
261 << endl << "This might be due to truncation error"
262 << abort(FatalError);
268 space(Pout, 2*level);
269 Pout<< "findLeafLineOctant : returning from intersecting with"
270 << " empty " << emptyBb
271 << " with start:" << start << " subLeaf:" << 0 << endl;
278 FatalErrorIn(functionName)
279 << "Empty node " << emptyBb
280 << " at octant " << octant
281 << " does not contain start " << start
282 << abort(FatalError);
286 FatalErrorIn(functionName)
287 << "Octant " << octant << " of cube " << this->bb()
288 << " does not contain start " << start
289 << abort(FatalError);
295 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
297 // Construct from components
298 template <class Type>
299 Foam::treeNode<Type>::treeNode(const treeBoundBox& bb)
307 for (label octantI=0; octantI<8; octantI++)
309 subNodes_[octantI] = NULL;
310 setVolType(octantI, octree<Type>::UNKNOWN);
315 // Construct from Istream
316 template <class Type>
317 Foam::treeNode<Type>::treeNode(Istream& is)
323 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
325 template <class Type>
326 Foam::treeNode<Type>::~treeNode()
328 for (int octant=0; octant<8; octant++)
330 if (subNodes()[octant])
334 delete getNodePtr(octant);
338 delete getLeafPtr(octant);
345 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
347 // Distributes cells to subLeaves
348 template <class Type>
349 void Foam::treeNode<Type>::distribute
354 const labelList& indices
360 Pout<< "treeNode::distributing " << indices.size() << endl;
363 // Create subLeaves if necessary
364 for (label octant=0; octant<8; octant++)
366 if (subNodes()[octant])
368 printNode(Pout, level);
371 "treeNode<Type>::distribute(const label, octree<Type>&, "
372 "const Type&, const labelList&)"
373 ) << "subNode already available at octant:" << octant
374 << abort(FatalError);
378 treeLeaf<Type>* subLeafPtr = new treeLeaf<Type>
380 this->bb().subBbox(midpoint(), octant),
384 top.setLeaves(top.nLeaves() + 1);
385 setLeafPtr(octant, subLeafPtr);
390 // add cells to correct sub leaf
393 const label shapei = indices[i];
395 for (label octant=0; octant<8; octant++)
397 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
399 if (shapes.overlaps(shapei, leafPtr->bb()))
404 Pout<< "inserting " << shapei;
405 shapes.write(Pout, shapei);
406 Pout<< " into " << leafPtr->bb() << endl;
408 leafPtr->insert(shapei);
409 top.setEntries(top.nEntries() + 1);
414 // Trim size of subLeaves
415 for (label octant=0; octant<8; octant++)
417 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
419 if (subLeafPtr->size() == 0)
421 // Contains no data. Delete.
422 setLeafPtr(octant, NULL);
424 top.setLeaves(top.nLeaves() - 1);
428 // Trim to actual size.
436 Pout<< "end of treeNode::distribute" << endl;
441 // Descends to refineLevel and checks the subLeaves for redistribution
442 template <class Type>
443 void Foam::treeNode<Type>::redistribute
448 const label refineLevel
454 Pout<< "treeNode::redistribute with level:" << level
455 << " refineLevel:" << refineLevel << endl;
458 // Descend to correct level
459 if (level < refineLevel)
461 for (label octant=0; octant<8; octant++)
463 if (subNodes()[octant])
467 getNodePtr(octant)->redistribute
480 // Reached correct (should also be deepest) level of treeNode
484 Pout<< "treeNode::redistribute : now at correct level" << endl;
487 // handle redistribution of sub leaves
488 for (label octant=0; octant<8; octant++)
490 if (subNodes()[octant])
496 "treeNode<Type>::redistribute(const int, octree& top,"
497 "const int, const treeBoundBox&)"
498 ) << "found treeNode instead of treeLeaf" << endl
499 << abort(FatalError);
503 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
505 treeLeaf<Type>* newSubPtr = leafPtr->redistribute
512 if (newSubPtr && (newSubPtr != leafPtr))
514 // redistribute has created nodePtr
515 // so delete no longer used subPtr and update info
519 << top.nEntries() - leafPtr->size()
520 << " entries" << endl;
522 top.setEntries(top.nEntries() - leafPtr->size());
526 top.setLeaves(top.nLeaves() - 1);
528 setNodePtr(octant, newSubPtr);
536 Pout<< "end of treeNode::redistribute for correct level" << endl;
543 Pout<< "return from treeNode::redistribute with bb:" << this->bb()
550 template <class Type>
551 Foam::label Foam::treeNode<Type>::setSubNodeType
561 Pout<< "treeNode::setSubNodeType with level:" << level
562 << " bb:" << this->bb() << endl;
567 for (label octant=0; octant<8; octant++)
571 if (subNodes()[octant])
575 subType = getNodePtr(octant)->setSubNodeType
584 subType = getLeafPtr(octant)->setSubNodeType
594 // No data in this one. Set type for octant acc. to its bounding
596 const treeBoundBox subBb = this->bb().subBbox(midpoint(), octant);
598 subType = shapes.getSampleType(top, subBb.midpoint());
604 Pout<< "treeNode::setSubNodeType : setting octant with bb:"
605 << this->bb().subBbox(midpoint(), octant)
606 << " to type:" << octree<Type>::volType(subType) << endl;
608 setVolType(octant, subType);
610 // Combine sub node types into type for treeNode. Result is 'mixed' if
611 // types differ among subnodes.
616 else if (subType != myType)
618 myType = octree<Type>::MIXED;
625 Pout<< "return from treeNode::setSubNodeType with type:"
626 << octree<Type>::volType(myType)
627 << " bb:" << this->bb() << endl;
635 template <class Type>
636 Foam::label Foam::treeNode<Type>::getSampleType
639 const octree<Type>& top,
647 Pout<< "treeNode::getSampleType with level:" << level
648 << " bb:" << this->bb() << " sample:" << sample << endl;
651 // Determine octant of bb. If on edge just use whichever octant.
654 label octant = this->bb().subOctant(midpoint(), sample, onEdge);
656 label type = getVolType(octant);
658 if (type == octree<Type>::MIXED)
660 // At this level multiple sub types. Recurse to resolve.
661 if (subNodes()[octant])
665 // Node: recurse into subnodes
666 type = getNodePtr(octant)->getSampleType
677 type = getLeafPtr(octant)->getSampleType
688 // Problem: empty subnode should have a type
691 "treeNode<Type>::getSampleType"
692 "(const label, octree<Type>&, const Type&, const point&)"
693 ) << "Empty node bb:" << this->bb().subBbox(midpoint(), octant)
694 << " has non-mixed type:"
695 << octree<Type>::volType(type)
696 << abort(FatalError);
700 if (type == octree<Type>::MIXED)
704 "treeNode<Type>::getSampleType"
705 "(const label, octree<Type>&, const Type&, const point&)"
706 ) << "Type is MIXED when searching for " << sample
707 << " at level " << this->bb() << endl
708 << "This probably is because the octree has not been constructed"
709 << " with search facility." << exit(FatalError);
715 Pout<< "return from treeNode::getSampleType with type:"
716 << octree<Type>::volType(type)
717 << " bb:" << this->bb()
718 << " sample:" << sample << endl;
724 template <class Type>
725 Foam::label Foam::treeNode<Type>::find
731 // Find octant of sample. Don't care if on edge (since any item on edge
732 // will have been inserted in both subcubes)
735 label octant = this->bb().subOctant(midpoint(), sample, onEdge);
737 if (subNodes()[octant])
741 // Node: recurse into subnodes
742 return getNodePtr(octant)->find(shapes, sample);
746 // Leaf: let leaf::find handle this
747 return getLeafPtr(octant)->find(shapes, sample);
754 template <class Type>
755 bool Foam::treeNode<Type>::findTightest
759 treeBoundBox& tightest
762 bool changed = false;
764 // Estimate for best place to start searching
765 label sampleOctant = this->bb().subOctant(midpoint(), sample, onEdge);
767 // Go into all suboctants (one containing sample first) and update tightest.
768 // Order of visiting is if e.g. sampleOctant = 5:
770 for (label octantI=0; octantI<8; octantI++)
775 // Use sampleOctant first
776 octant = sampleOctant;
778 else if (octantI == sampleOctant)
787 if (subNodes()[octant])
791 // Node: recurse into subnodes
792 const treeNode<Type>* subNodePtr = getNodePtr(octant);
794 if (subNodePtr->bb().overlaps(tightest))
796 // there might be a better fit inside this subNode
797 changed |= subNodePtr->findTightest
807 // Leaf: let leaf::find handle this
808 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
810 if (subLeafPtr->bb().overlaps(tightest))
812 // there might be a better fit inside this subLeaf
813 changed |= subLeafPtr->findTightest
828 template <class Type>
829 bool Foam::treeNode<Type>::findNearest
833 treeBoundBox& tightest,
840 Pout<< "In findNearest with sample:" << sample << " cube:"
841 << this->bb() << " tightest:" << tightest << endl;
844 bool changed = false;
846 // Estimate for best place to start searching
847 label sampleOctant = this->bb().subOctant(midpoint(), sample, onEdge);
849 // Go into all suboctants (one containing sample first) and update tightest.
850 // Order of visiting is if e.g. sampleOctant = 5:
852 for (label octantI=0; octantI<8; octantI++)
857 // Use sampleOctant first
858 octant = sampleOctant;
860 else if (octantI == sampleOctant)
869 if (subNodes()[octant])
874 const treeNode<Type>* subNodePtr = getNodePtr(octant);
876 if (subNodePtr->bb().overlaps(tightest))
878 // there might be a better fit inside this subNode
879 changed |= subNodePtr->findNearest
891 // Leaf: let leaf::find handle this
892 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
894 if (subLeafPtr->bb().overlaps(tightest))
896 // there might be a better fit inside this subNode
897 changed |= subLeafPtr->findNearest
912 Pout<< "Exiting findNearest for sample:" << sample << " cube:"
913 << this->bb() << " tightestI:" << tightestI << endl;
920 template <class Type>
921 bool Foam::treeNode<Type>::findNearest
924 const linePointRef& ln,
925 treeBoundBox& tightest,
927 point& linePoint, // nearest point on line
928 point& shapePoint // nearest point on shape
931 bool changed = false;
933 // Estimate for best place to start searching
934 label sampleOctant = this->bb().subOctant(midpoint(), ln.centre(), onEdge);
936 // Go into all suboctants (one containing sample first) and update tightest.
937 // Order of visiting is if e.g. sampleOctant = 5:
939 for (label octantI=0; octantI<8; octantI++)
944 // Use sampleOctant first
945 octant = sampleOctant;
947 else if (octantI == sampleOctant)
956 if (subNodes()[octant])
961 const treeNode<Type>* subNodePtr = getNodePtr(octant);
963 if (subNodePtr->bb().overlaps(tightest))
965 // there might be a better fit inside this subNode
966 changed |= subNodePtr->findNearest
979 // Leaf: let leaf::find handle this
980 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
982 if (subLeafPtr->bb().overlaps(tightest))
984 // there might be a better fit inside this subNode
985 changed |= subLeafPtr->findNearest
1003 template <class Type>
1004 bool Foam::treeNode<Type>::findBox
1007 const boundBox& box,
1008 labelHashSet& elements
1011 bool changed = false;
1012 bool onEdge = false;
1013 // Estimate for best place to start searching
1014 label sampleOctant = this->bb().subOctant
1021 // Go into all suboctants (one containing sample first) and update tightest.
1022 // Order of visiting is if e.g. sampleOctant = 5:
1024 for (label octantI=0; octantI<8; octantI++)
1029 // Use sampleOctant first
1030 octant = sampleOctant;
1032 else if (octantI == sampleOctant)
1041 if (subNodes()[octant])
1046 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1048 if (subNodePtr->bb().overlaps(box))
1051 changed |= subNodePtr->findBox(shapes, box, elements);
1056 // Leaf: let leaf::find handle this
1057 const treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1059 if (subLeafPtr->bb().overlaps(box))
1062 changed |= subLeafPtr->findBox(shapes, box, elements);
1072 // look from <start> in current cube (given by this->bb()).
1073 template <class Type>
1074 const Foam::treeLeaf<Type>* Foam::treeNode<Type>::findLeafLine
1084 space(Pout, 2*level);
1085 Pout<< "findLeafLine : bb:" << this->bb() << " mid:" << midpoint()
1086 << " start:" << start << endl;
1089 scalar typDim = this->bb().avgDim();
1091 const vector direction = end - start;
1093 // Loop on current level until start has been updated to be outside
1094 // of this->bb(). Note that max only four subcubes can be crossed so this is
1095 // check on whether there are any truncation error problems.
1101 if (!this->bb().contains(direction, start))
1105 space(Pout, 2*level);
1106 Pout<< "findLeafLine : Start not inside bb " << this->bb()
1107 << ". Returning with start:" << start << " subLeaf:"
1113 // Check if start and <end> equal
1114 if ((mag(start - end)/typDim) < SMALL)
1118 space(Pout, 2*level);
1119 Pout<< "findLeafLine : start equals end"
1120 << ". Returning with start:" << start << " subLeaf:"
1128 // Too many iterations. Is hanging. Handle outside of loop.
1132 bool onEdge = false;
1133 label octant = this->bb().subOctant
1135 midpoint(), direction, start, onEdge
1138 // Try finding non-empty treeleaf in octant
1139 const treeLeaf<Type>* leafPtr = findLeafLineOctant
1151 // Found treeLeaf -> return
1154 space(Pout, 2*level);
1155 Pout<< "findLeafLine : Found treeLeaf"
1156 << ". Returning with start:" << start << " subLeaf:"
1157 << long(leafPtr) << endl;
1166 // Check if is hanging. Max 4 octants can be crossed by a straight line
1169 "treeNode<Type>::findLeafLine"
1170 "(const label, octree<Type>&, point&,"
1172 ) << "Did not leave bb " << this->bb()
1173 << " after " << iter
1174 << " iterations of updating starting point."
1175 << "start:" << start << " end:" << end
1176 << abort(FatalError);
1182 template <class Type>
1183 void Foam::treeNode<Type>::findLeaves
1185 List<treeLeaf<Type>*>& leafArray,
1189 // Go into all sub boxes
1190 for (label octant=0; octant<8; octant++)
1192 if (subNodes()[octant])
1196 // Node: recurse into subnodes
1197 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1198 subNodePtr->findLeaves(leafArray, leafIndex);
1203 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1204 leafArray[leafIndex++] = subLeafPtr;
1211 template <class Type>
1212 void Foam::treeNode<Type>::findLeaves
1214 List<const treeLeaf<Type>*>& leafArray,
1218 // Go into all sub boxes
1219 for (label octant=0; octant<8; octant++)
1221 if (subNodes()[octant])
1225 // Node: recurse into subnodes
1226 const treeNode<Type>* subNodePtr = getNodePtr(octant);
1227 subNodePtr->findLeaves(leafArray, leafIndex);
1232 treeLeaf<Type>* subLeafPtr = getLeafPtr(octant);
1233 leafArray[leafIndex++] = subLeafPtr;
1240 template <class Type>
1241 void Foam::treeNode<Type>::printNode
1249 os << "node:" << this->bb() << endl;
1251 for (label octant=0; octant<8; octant++)
1253 label type = getVolType(octant);
1255 string typeString = octree<Type>::volType(type);
1257 if (!subNodes_[octant])
1260 os << octant << ":" << typeString << " : null" << endl;
1262 else if (isNode(octant))
1265 os << octant << ":" << typeString << " : node" << endl;
1266 getNodePtr(octant)->printNode(os, level+1);
1271 os << octant << ":" << typeString << " : leaf" << endl;
1273 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
1274 leafPtr->printLeaf(os, level+1);
1280 template <class Type>
1281 void Foam::treeNode<Type>::writeOBJ
1288 point midPoint(this->bb().midpoint());
1290 label midVertNo = vertNo;
1291 os << "v " << midPoint.x() << " " << midPoint.y() << " "
1292 << midPoint.z() << endl;
1295 for (label octant=0; octant<8; octant++)
1297 if (subNodes_[octant])
1301 treeNode<Type>* nodePtr = getNodePtr(octant);
1303 point subMidPoint(nodePtr->bb().midpoint());
1304 os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
1305 << subMidPoint.z() << endl;
1306 os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
1309 nodePtr->writeOBJ(os, level+1, vertNo);
1313 treeLeaf<Type>* leafPtr = getLeafPtr(octant);
1315 point subMidPoint(leafPtr->bb().midpoint());
1316 os << "v " << subMidPoint.x() << " " << subMidPoint.y() << " "
1317 << subMidPoint.z() << endl;
1318 os << "l " << midVertNo + 1<< " " << vertNo + 1 << endl;
1321 //leafPtr->writeOBJ(os, level+1, vertNo);
1328 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
1330 template <class Type>
1331 Foam::Istream& Foam::operator>>(Istream& is, treeNode<Type>& oc)
1333 for (label octant = 0; octant < 8; octant++)
1335 oc.subNodes_[octant] = NULL;
1342 // Read number of entries folllowing
1345 is.readBegin("treeNode");
1346 for (label octant = 0; octant < nPtrs; octant++)
1351 if (index >= treeNode<Type>::leafOffset)
1353 // Leaf recognized by out of range index
1354 treeLeaf<Type>* leafPtr = new treeLeaf<Type>(is);
1355 oc.setLeafPtr(index - treeNode<Type>::leafOffset, leafPtr);
1359 oc.setNodePtr(index, new treeNode<Type>(is));
1363 // Read end of treeNode list
1364 is.readEnd("treeNode");
1366 // Check state of Istream
1367 is.check("Istream& operator>>(Istream&, treeNode&)");
1373 template <class Type>
1374 Foam::Ostream& Foam::operator<<(Ostream& os, const treeNode<Type>& tn)
1376 // Count valid subnodes:
1378 // - treeLeafs with non-zero cell list.
1380 for (label octant = 0; octant < 8; octant++)
1382 if (tn.subNodes_[octant])
1384 if (tn.isNode(octant) || tn.getLeafPtr(octant)->indices().size())
1392 // output subnodes as list of length nPtrs
1393 os << token::SPACE << tn.bb() << token::SPACE << nPtrs
1394 << token::SPACE << token::BEGIN_LIST;
1396 for (label octant = 0; octant < 8; octant++)
1398 if (tn.subNodes_[octant])
1400 if (tn.isNode(octant))
1402 const treeNode<Type>* subNodePtr = tn.getNodePtr(octant);
1404 // Node: output index, value
1405 os << token::SPACE << octant << token::SPACE << *subNodePtr
1408 else if (tn.getLeafPtr(octant)->indices().size())
1410 // treeLeaf: mark by putting index invalid
1411 const treeLeaf<Type>* subLeafPtr = tn.getLeafPtr(octant);
1413 os << token::SPACE << octant + treeNode<Type>::leafOffset
1414 << token::SPACE << *subLeafPtr
1420 os << token::SPACE << token::END_LIST;
1426 // ************************ vim: set sw=4 sts=4 et: ************************ //