1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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
25 \*---------------------------------------------------------------------------*/
27 #include "indexedOctree.H"
28 #include "linePointRef.H"
29 #include "meshTools.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 Foam::scalar Foam::indexedOctree<Type>::perturbTol_ = 10*SMALL;
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 // Does bb intersect a sphere around sample? Or is any corner point of bb
41 // closer than nearestDistSqr to sample.
43 bool Foam::indexedOctree<Type>::overlaps
47 const scalar nearestDistSqr,
51 // Find out where sample is in relation to bb.
52 // Find nearest point on bb.
55 for (direction dir = 0; dir < vector::nComponents; dir++)
57 scalar d0 = p0[dir] - sample[dir];
58 scalar d1 = p1[dir] - sample[dir];
60 if ((d0 > 0) != (d1 > 0))
62 // sample inside both extrema. This component does not add any
65 else if (mag(d0) < mag(d1))
74 if (distSqr > nearestDistSqr)
84 // Does bb intersect a sphere around sample? Or is any corner point of bb
85 // closer than nearestDistSqr to sample.
87 bool Foam::indexedOctree<Type>::overlaps
89 const treeBoundBox& parentBb,
90 const direction octant,
91 const scalar nearestDistSqr,
95 //- Accelerated version of
96 // treeBoundBox subBb(parentBb.subBbox(mid, octant))
105 const point& min = parentBb.min();
106 const point& max = parentBb.max();
110 if (octant & treeBoundBox::RIGHTHALF)
119 if (octant & treeBoundBox::TOPHALF)
128 if (octant & treeBoundBox::FRONTHALF)
137 const point mid(0.5*(min+max));
139 return overlaps(mid, other, nearestDistSqr, sample);
144 // Construction helper routines
145 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148 // Split list of indices into 8 bins
149 template <class Type>
150 void Foam::indexedOctree<Type>::divide
152 const labelList& indices,
153 const treeBoundBox& bb,
154 labelListList& result
157 List<DynamicList<label> > subIndices(8);
158 for (direction octant = 0; octant < subIndices.size(); octant++)
160 subIndices[octant].setCapacity(indices.size()/8);
163 // Precalculate bounding boxes.
164 FixedList<treeBoundBox, 8> subBbs;
165 for (direction octant = 0; octant < subBbs.size(); octant++)
167 subBbs[octant] = bb.subBbox(octant);
172 label shapeI = indices[i];
174 for (direction octant = 0; octant < 8; octant++)
176 if (shapes_.overlaps(shapeI, subBbs[octant]))
178 subIndices[octant].append(shapeI);
184 for (direction octant = 0; octant < subIndices.size(); octant++)
186 result[octant].transfer(subIndices[octant]);
191 // Subdivide the (content) node.
192 template <class Type>
193 typename Foam::indexedOctree<Type>::node
194 Foam::indexedOctree<Type>::divide
196 const treeBoundBox& bb,
197 DynamicList<labelList>& contents,
201 const labelList& indices = contents[contentI];
207 bb.min()[0] >= bb.max()[0]
208 || bb.min()[1] >= bb.max()[1]
209 || bb.min()[2] >= bb.max()[2]
212 FatalErrorIn("indexedOctree<Type>::divide(..)")
213 << "Badly formed bounding box:" << bb
214 << abort(FatalError);
220 labelListList dividedIndices(8);
221 divide(indices, bb, dividedIndices);
223 // Have now divided the indices into 8 (possibly empty) subsets.
224 // Replace current contentI with the first (non-empty) subset.
226 bool replaced = false;
228 for (direction octant = 0; octant < dividedIndices.size(); octant++)
230 labelList& subIndices = dividedIndices[octant];
232 if (subIndices.size())
236 contents[contentI].transfer(subIndices);
237 nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
242 // Store at end of contents.
243 // note dummy append + transfer trick
244 label sz = contents.size();
245 contents.append(labelList(0));
246 contents[sz].transfer(subIndices);
247 nod.subNodes_[octant] = contentPlusOctant(sz, octant);
252 // Mark node as empty
253 nod.subNodes_[octant] = emptyPlusOctant(octant);
261 // Split any contents node with more than minSize elements.
262 template <class Type>
263 void Foam::indexedOctree<Type>::splitNodes
266 DynamicList<indexedOctree<Type>::node>& nodes,
267 DynamicList<labelList>& contents
270 label currentSize = nodes.size();
272 // Take care to loop only over old nodes.
273 // Also we loop over the same DynamicList which gets modified and
274 // moved so make sure not to keep any references!
275 for (label nodeI = 0; nodeI < currentSize; nodeI++)
279 direction octant = 0;
280 octant < nodes[nodeI].subNodes_.size();
284 labelBits index = nodes[nodeI].subNodes_[octant];
288 // tree node. Leave intact.
290 else if (isContent(index))
292 label contentI = getContent(index);
294 if (contents[contentI].size() > minSize)
296 // Create node for content.
298 // Find the bounding box for the subnode
299 const node& nod = nodes[nodeI];
300 const treeBoundBox bb(nod.bb_.subBbox(octant));
302 node subNode(divide(bb, contents, contentI));
303 subNode.parent_ = nodeI;
304 label sz = nodes.size();
305 nodes.append(subNode);
306 nodes[nodeI].subNodes_[octant] = nodePlusOctant(sz, octant);
314 // Reorder contents to be in same order as nodes. Returns number of nodes on
316 template <class Type>
317 Foam::label Foam::indexedOctree<Type>::compactContents
319 DynamicList<node>& nodes,
320 DynamicList<labelList>& contents,
321 const label compactLevel,
325 List<labelList>& compactedContents,
329 const node& nod = nodes[nodeI];
333 if (level < compactLevel)
335 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
337 labelBits index = nod.subNodes_[octant];
341 nNodes += compactContents
354 else if (level == compactLevel)
356 // Compact all content on this level
357 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
359 labelBits index = nod.subNodes_[octant];
361 if (isContent(index))
363 label contentI = getContent(index);
365 compactedContents[compactI].transfer(contents[contentI]);
367 // Subnode is at compactI. Adapt nodeI to point to it
368 nodes[nodeI].subNodes_[octant] =
369 contentPlusOctant(compactI, octant);
373 else if (isNode(index))
383 // Pre-calculates wherever possible the volume status per node/subnode.
384 // Recurses to determine status of lowest level boxes. Level above is
385 // combination of octants below.
386 template <class Type>
387 typename Foam::indexedOctree<Type>::volumeType
388 Foam::indexedOctree<Type>::calcVolumeType
393 const node& nod = nodes_[nodeI];
395 volumeType myType = UNKNOWN;
397 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
401 labelBits index = nod.subNodes_[octant];
405 // tree node. Recurse.
406 subType = calcVolumeType(getNode(index));
408 else if (isContent(index))
410 // Contents. Depending on position in box might be on either
416 // No data in this octant. Set type for octant acc. to the mid
417 // of its bounding box.
418 const treeBoundBox subBb = nod.bb_.subBbox(octant);
422 shapes_.getVolumeType(*this, subBb.midpoint())
427 nodeTypes_.set((nodeI<<3)+octant, subType);
429 // Combine sub node types into type for treeNode. Result is 'mixed' if
430 // types differ among subnodes.
431 if (myType == UNKNOWN)
435 else if (subType != myType)
444 template <class Type>
445 typename Foam::indexedOctree<Type>::volumeType
446 Foam::indexedOctree<Type>::getVolumeType
452 const node& nod = nodes_[nodeI];
454 direction octant = nod.bb_.subOctant(sample);
456 volumeType octantType = volumeType(nodeTypes_.get((nodeI<<3)+octant));
458 if (octantType == INSIDE)
462 else if (octantType == OUTSIDE)
466 else if (octantType == UNKNOWN)
468 // Can happen for e.g. non-manifold surfaces.
471 else if (octantType == MIXED)
473 labelBits index = nod.subNodes_[octant];
478 volumeType subType = getVolumeType(getNode(index), sample);
482 else if (isContent(index))
484 // Content. Defer to shapes.
485 return volumeType(shapes_.getVolumeType(*this, sample));
489 // Empty node. Cannot have 'mixed' as its type since not divided
490 // up and has no items inside it.
493 "indexedOctree<Type>::getVolumeType"
494 "(const label, const point&)"
495 ) << "Sample:" << sample << " node:" << nodeI
496 << " with bb:" << nodes_[nodeI].bb_ << nl
497 << "Empty subnode has invalid volume type MIXED."
498 << abort(FatalError);
507 "indexedOctree<Type>::getVolumeType"
508 "(const label, const point&)"
509 ) << "Sample:" << sample << " at node:" << nodeI
510 << " octant:" << octant
511 << " with bb:" << nod.bb_.subBbox(octant) << nl
512 << "Node has invalid volume type " << octantType
513 << abort(FatalError);
520 template <class Type>
521 typename Foam::indexedOctree<Type>::volumeType
522 Foam::indexedOctree<Type>::getSide
524 const vector& outsideNormal,
528 if ((outsideNormal&vec) >= 0)
544 // Find nearest point starting from nodeI
545 template <class Type>
546 void Foam::indexedOctree<Type>::findNearest
551 scalar& nearestDistSqr,
552 label& nearestShapeI,
556 const node& nod = nodes_[nodeI];
558 // Determine order to walk through octants
559 FixedList<direction, 8> octantOrder;
560 nod.bb_.searchOrder(sample, octantOrder);
562 // Go into all suboctants (one containing sample first) and update nearest.
563 for (direction i = 0; i < 8; i++)
565 direction octant = octantOrder[i];
567 labelBits index = nod.subNodes_[octant];
571 label subNodeI = getNode(index);
573 const treeBoundBox& subBb = nodes_[subNodeI].bb_;
575 if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
588 else if (isContent(index))
603 contents_[getContent(index)],
616 // Find nearest point to line.
617 template <class Type>
618 void Foam::indexedOctree<Type>::findNearest
621 const linePointRef& ln,
623 treeBoundBox& tightest,
624 label& nearestShapeI,
629 const node& nod = nodes_[nodeI];
630 const treeBoundBox& nodeBb = nod.bb_;
632 // Determine order to walk through octants
633 FixedList<direction, 8> octantOrder;
634 nod.bb_.searchOrder(ln.centre(), octantOrder);
636 // Go into all suboctants (one containing sample first) and update nearest.
637 for (direction i = 0; i < 8; i++)
639 direction octant = octantOrder[i];
641 labelBits index = nod.subNodes_[octant];
645 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
647 if (subBb.overlaps(tightest))
661 else if (isContent(index))
663 const treeBoundBox subBb(nodeBb.subBbox(octant));
665 if (subBb.overlaps(tightest))
669 contents_[getContent(index)],
683 template <class Type>
684 Foam::treeBoundBox Foam::indexedOctree<Type>::subBbox
686 const label parentNodeI,
687 const direction octant
690 // Get type of node at octant
691 const node& nod = nodes_[parentNodeI];
692 labelBits index = nod.subNodes_[octant];
697 return nodes_[getNode(index)].bb_;
702 return nod.bb_.subBbox(octant);
707 // Takes a bb and a point on/close to the edge of the bb and pushes the point
708 // inside by a small fraction.
709 template <class Type>
710 Foam::point Foam::indexedOctree<Type>::pushPoint
712 const treeBoundBox& bb,
714 const bool pushInside
717 // Get local length scale.
718 const vector perturbVec = perturbTol_*(bb.span());
720 point perturbedPt(pt);
722 // Modify all components which are close to any face of the bb to be
723 // well inside/outside them.
727 for (direction dir = 0; dir < vector::nComponents; dir++)
729 if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
731 // Close to 'left' side. Push well beyond left side.
732 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
733 perturbedPt[dir] = bb.min()[dir] + perturbDist;
735 else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
737 // Close to 'right' side. Push well beyond right side.
738 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
739 perturbedPt[dir] = bb.max()[dir] - perturbDist;
745 for (direction dir = 0; dir < vector::nComponents; dir++)
747 if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
749 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
750 perturbedPt[dir] = bb.min()[dir] - perturbDist;
752 else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
754 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
755 perturbedPt[dir] = bb.max()[dir] + perturbDist;
762 if (pushInside != bb.contains(perturbedPt))
764 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
765 << "pushed point:" << pt
766 << " to:" << perturbedPt
767 << " wanted side:" << pushInside
768 << " obtained side:" << bb.contains(perturbedPt)
770 << abort(FatalError);
778 // Takes a bb and a point on the edge of the bb and pushes the point
779 // outside by a small fraction.
780 template <class Type>
781 Foam::point Foam::indexedOctree<Type>::pushPoint
783 const treeBoundBox& bb,
784 const direction faceID,
786 const bool pushInside
789 // Get local length scale.
790 const vector perturbVec = perturbTol_*bb.span();
792 point perturbedPt(pt);
794 // Modify all components which are close to any face of the bb to be
795 // well outside them.
799 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
800 << abort(FatalError);
803 if (faceID & treeBoundBox::LEFTBIT)
807 perturbedPt[0] = bb.min()[0] + (perturbVec[0] + ROOTVSMALL);
811 perturbedPt[0] = bb.min()[0] - (perturbVec[0] + ROOTVSMALL);
814 else if (faceID & treeBoundBox::RIGHTBIT)
818 perturbedPt[0] = bb.max()[0] - (perturbVec[0] + ROOTVSMALL);
822 perturbedPt[0] = bb.max()[0] + (perturbVec[0] + ROOTVSMALL);
826 if (faceID & treeBoundBox::BOTTOMBIT)
830 perturbedPt[1] = bb.min()[1] + (perturbVec[1] + ROOTVSMALL);
834 perturbedPt[1] = bb.min()[1] - (perturbVec[1] + ROOTVSMALL);
837 else if (faceID & treeBoundBox::TOPBIT)
841 perturbedPt[1] = bb.max()[1] - (perturbVec[1] + ROOTVSMALL);
845 perturbedPt[1] = bb.max()[1] + (perturbVec[1] + ROOTVSMALL);
849 if (faceID & treeBoundBox::BACKBIT)
853 perturbedPt[2] = bb.min()[2] + (perturbVec[2] + ROOTVSMALL);
857 perturbedPt[2] = bb.min()[2] - (perturbVec[2] + ROOTVSMALL);
860 else if (faceID & treeBoundBox::FRONTBIT)
864 perturbedPt[2] = bb.max()[2] - (perturbVec[2] + ROOTVSMALL);
868 perturbedPt[2] = bb.max()[2] + (perturbVec[2] + ROOTVSMALL);
874 if (pushInside != bb.contains(perturbedPt))
876 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
877 << "pushed point:" << pt << " on face:" << faceString(faceID)
878 << " to:" << perturbedPt
879 << " wanted side:" << pushInside
880 << " obtained side:" << bb.contains(perturbedPt)
882 << abort(FatalError);
890 // Guarantees that if pt is on a face it gets perturbed so it is away
891 // from the face edges.
892 // If pt is not on a face does nothing.
893 template <class Type>
894 Foam::point Foam::indexedOctree<Type>::pushPointIntoFace
896 const treeBoundBox& bb,
897 const vector& dir, // end-start
903 if (bb.posBits(pt) != 0)
905 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
906 << " bb:" << bb << endl
907 << "does not contain point " << pt << abort(FatalError);
913 // - point exactly on multiple faces. Push away from all but one.
914 // - point on a single face. Push away from edges of face.
916 direction ptFaceID = bb.faceBits(pt);
918 direction nFaces = 0;
919 FixedList<direction, 3> faceIndices;
921 if (ptFaceID & treeBoundBox::LEFTBIT)
923 faceIndices[nFaces++] = treeBoundBox::LEFT;
925 else if (ptFaceID & treeBoundBox::RIGHTBIT)
927 faceIndices[nFaces++] = treeBoundBox::RIGHT;
930 if (ptFaceID & treeBoundBox::BOTTOMBIT)
932 faceIndices[nFaces++] = treeBoundBox::BOTTOM;
934 else if (ptFaceID & treeBoundBox::TOPBIT)
936 faceIndices[nFaces++] = treeBoundBox::TOP;
939 if (ptFaceID & treeBoundBox::BACKBIT)
941 faceIndices[nFaces++] = treeBoundBox::BACK;
943 else if (ptFaceID & treeBoundBox::FRONTBIT)
945 faceIndices[nFaces++] = treeBoundBox::FRONT;
949 // Determine the face we want to keep the point on
951 direction keepFaceID;
955 // Return original point
958 else if (nFaces == 1)
960 // Point is on a single face
961 keepFaceID = faceIndices[0];
965 // Determine best face out of faceIndices[0 .. nFaces-1].
966 // The best face is the one most perpendicular to the ray direction.
968 keepFaceID = faceIndices[0];
969 scalar maxInproduct = mag(treeBoundBox::faceNormals[keepFaceID] & dir);
971 for (direction i = 1; i < nFaces; i++)
973 direction face = faceIndices[i];
974 scalar s = mag(treeBoundBox::faceNormals[face] & dir);
975 if (s > maxInproduct)
984 // 1. Push point into bb, away from all corners
986 point facePoint(pushPoint(bb, pt, true));
987 direction faceID = 0;
989 // 2. Snap it back onto the preferred face
991 if (keepFaceID == treeBoundBox::LEFT)
993 facePoint.x() = bb.min().x();
994 faceID = treeBoundBox::LEFTBIT;
996 else if (keepFaceID == treeBoundBox::RIGHT)
998 facePoint.x() = bb.max().x();
999 faceID = treeBoundBox::RIGHTBIT;
1001 else if (keepFaceID == treeBoundBox::BOTTOM)
1003 facePoint.y() = bb.min().y();
1004 faceID = treeBoundBox::BOTTOMBIT;
1006 else if (keepFaceID == treeBoundBox::TOP)
1008 facePoint.y() = bb.max().y();
1009 faceID = treeBoundBox::TOPBIT;
1011 else if (keepFaceID == treeBoundBox::BACK)
1013 facePoint.z() = bb.min().z();
1014 faceID = treeBoundBox::BACKBIT;
1016 else if (keepFaceID == treeBoundBox::FRONT)
1018 facePoint.z() = bb.max().z();
1019 faceID = treeBoundBox::FRONTBIT;
1025 if (faceID != bb.faceBits(facePoint))
1027 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
1028 << "Pushed point from " << pt
1029 << " on face:" << ptFaceID << " of bb:" << bb << endl
1030 << "onto " << facePoint
1031 << " on face:" << faceID
1032 << " which is not consistent with geometric face "
1033 << bb.faceBits(facePoint)
1034 << abort(FatalError);
1036 if (bb.posBits(facePoint) != 0)
1038 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
1039 << " bb:" << bb << endl
1040 << "does not contain perturbed point "
1041 << facePoint << abort(FatalError);
1050 //// Takes a bb and a point on the outside of the bb. Checks if on multiple faces
1051 //// and if so perturbs point so it is only on one face.
1052 //template <class Type>
1053 //void Foam::indexedOctree<Type>::checkMultipleFaces
1055 // const treeBoundBox& bb,
1056 // const vector& dir, // end-start
1057 // pointIndexHit& faceHitInfo,
1058 // direction& faceID
1061 // // Do the quick elimination of no or one face.
1065 // || (faceID == treeBoundBox::LEFTBIT)
1066 // || (faceID == treeBoundBox::RIGHTBIT)
1067 // || (faceID == treeBoundBox::BOTTOMBIT)
1068 // || (faceID == treeBoundBox::TOPBIT)
1069 // || (faceID == treeBoundBox::BACKBIT)
1070 // || (faceID == treeBoundBox::FRONTBIT)
1077 // // Check the direction of vector w.r.t. faces being intersected.
1078 // FixedList<scalar, 6> inproducts(-GREAT);
1080 // direction nFaces = 0;
1082 // if (faceID & treeBoundBox::LEFTBIT)
1084 // inproducts[treeBoundBox::LEFT] = mag
1086 // treeBoundBox::faceNormals[treeBoundBox::LEFT]
1091 // if (faceID & treeBoundBox::RIGHTBIT)
1093 // inproducts[treeBoundBox::RIGHT] = mag
1095 // treeBoundBox::faceNormals[treeBoundBox::RIGHT]
1101 // if (faceID & treeBoundBox::BOTTOMBIT)
1103 // inproducts[treeBoundBox::BOTTOM] = mag
1105 // treeBoundBox::faceNormals[treeBoundBox::BOTTOM]
1110 // if (faceID & treeBoundBox::TOPBIT)
1112 // inproducts[treeBoundBox::TOP] = mag
1114 // treeBoundBox::faceNormals[treeBoundBox::TOP]
1120 // if (faceID & treeBoundBox::BACKBIT)
1122 // inproducts[treeBoundBox::BACK] = mag
1124 // treeBoundBox::faceNormals[treeBoundBox::BACK]
1129 // if (faceID & treeBoundBox::FRONTBIT)
1131 // inproducts[treeBoundBox::FRONT] = mag
1133 // treeBoundBox::faceNormals[treeBoundBox::FRONT]
1139 // if (nFaces == 0 || nFaces == 1 || nFaces > 3)
1141 // FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)")
1142 // << "Problem : nFaces:" << nFaces << abort(FatalError);
1145 // // Keep point on most perpendicular face; shift it away from the aligned
1147 // // E.g. line hits top and left face:
1153 // // Shift point down (away from top):
1160 // label maxIndex = -1;
1161 // scalar maxInproduct = -GREAT;
1163 // for (direction i = 0; i < 6; i++)
1165 // if (inproducts[i] > maxInproduct)
1167 // maxInproduct = inproducts[i];
1172 // if (maxIndex == -1)
1174 // FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)")
1175 // << "Problem maxIndex:" << maxIndex << " inproducts:" << inproducts
1176 // << abort(FatalError);
1179 // const point oldPoint(faceHitInfo.rawPoint());
1180 // const direction oldFaceID = faceID;
1182 // // 1. Push point into bb, away from all corners
1184 // faceHitInfo.rawPoint() = pushPoint(bb, oldFaceID, oldPoint, true);
1186 // // 2. Snap it back onto the preferred face
1188 // if (maxIndex == treeBoundBox::LEFT)
1190 // faceHitInfo.rawPoint().x() = bb.min().x();
1191 // faceID = treeBoundBox::LEFTBIT;
1193 // else if (maxIndex == treeBoundBox::RIGHT)
1195 // faceHitInfo.rawPoint().x() = bb.max().x();
1196 // faceID = treeBoundBox::RIGHTBIT;
1198 // else if (maxIndex == treeBoundBox::BOTTOM)
1200 // faceHitInfo.rawPoint().y() = bb.min().y();
1201 // faceID = treeBoundBox::BOTTOMBIT;
1203 // else if (maxIndex == treeBoundBox::TOP)
1205 // faceHitInfo.rawPoint().y() = bb.max().y();
1206 // faceID = treeBoundBox::TOPBIT;
1208 // else if (maxIndex == treeBoundBox::BACK)
1210 // faceHitInfo.rawPoint().z() = bb.min().z();
1211 // faceID = treeBoundBox::BACKBIT;
1213 // else if (maxIndex == treeBoundBox::FRONT)
1215 // faceHitInfo.rawPoint().z() = bb.max().z();
1216 // faceID = treeBoundBox::FRONTBIT;
1219 // Pout<< "From ray:" << dir
1220 // << " from point:" << oldPoint
1221 // << " on faces:" << faceString(oldFaceID)
1222 // << " of bb:" << bb
1223 // << " with inprods:" << inproducts
1224 // << " maxIndex:" << maxIndex << endl
1225 // << "perturbed to point:" << faceHitInfo.rawPoint()
1226 // << " on face:" << faceString(faceID)
1232 // if (faceID != bb.faceBits(faceHitInfo.rawPoint()))
1234 // FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)")
1235 // << "Pushed point from " << oldPoint
1236 // << " on face:" << oldFaceID << " of bb:" << bb << endl
1237 // << "onto " << faceHitInfo.rawPoint()
1238 // << " on face:" << faceID
1239 // << " which is not consistent with geometric face "
1240 // << bb.faceBits(faceHitInfo.rawPoint())
1241 // << abort(FatalError);
1247 // Get parent node and octant. Return false if top of tree reached.
1248 template <class Type>
1249 bool Foam::indexedOctree<Type>::walkToParent
1252 const direction octant,
1258 parentNodeI = nodes_[nodeI].parent_;
1260 if (parentNodeI == -1)
1262 // Reached edge of tree
1266 const node& parentNode = nodes_[parentNodeI];
1268 // Find octant nodeI is in.
1271 for (direction i = 0; i < parentNode.subNodes_.size(); i++)
1273 labelBits index = parentNode.subNodes_[i];
1275 if (isNode(index) && getNode(index) == nodeI)
1282 if (parentOctant == 255)
1284 FatalErrorIn("walkToParent(..)")
1285 << "Problem: no parent found for octant:" << octant
1286 << " node:" << nodeI
1287 << abort(FatalError);
1294 // Walk tree to neighbouring node. Gets current position as
1295 // node and octant in this node and walks in the direction given by
1296 // the facePointBits (combination of treeBoundBox::LEFTBIT, TOPBIT etc.)
1297 // Returns false if edge of tree hit.
1298 template <class Type>
1299 bool Foam::indexedOctree<Type>::walkToNeighbour
1301 const point& facePoint,
1302 const direction faceID, // face(s) that facePoint is on
1307 label oldNodeI = nodeI;
1308 direction oldOctant = octant;
1310 // Find out how to test for octant. Say if we want to go left we need
1311 // to traverse up the tree until we hit a node where our octant is
1314 // Coordinate direction to test
1315 const direction X = treeBoundBox::RIGHTHALF;
1316 const direction Y = treeBoundBox::TOPHALF;
1317 const direction Z = treeBoundBox::FRONTHALF;
1319 direction octantMask = 0;
1320 direction wantedValue = 0;
1322 if ((faceID & treeBoundBox::LEFTBIT) != 0)
1324 // We want to go left so check if in right octant (i.e. x-bit is set)
1328 else if ((faceID & treeBoundBox::RIGHTBIT) != 0)
1330 octantMask |= X; // wantedValue already 0
1333 if ((faceID & treeBoundBox::BOTTOMBIT) != 0)
1335 // Want to go down so check for y-bit set.
1339 else if ((faceID & treeBoundBox::TOPBIT) != 0)
1341 // Want to go up so check for y-bit not set.
1345 if ((faceID & treeBoundBox::BACKBIT) != 0)
1350 else if ((faceID & treeBoundBox::FRONTBIT) != 0)
1355 // So now we have the coordinate directions in the octant we need to check
1356 // and the resulting value.
1370 // e.g. ray is at (a) in octant 0(or 4) with faceIDs : LEFTBIT+TOPBIT.
1371 // If we would be in octant 1(or 5) we could go to the correct octant
1372 // in the same node by just flipping the x and y bits (exoring).
1373 // But if we are not in octant 1/5 we have to go up until we are.
1374 // In general for leftbit+topbit:
1375 // - we have to check for x and y : octantMask = 011
1376 // - the checked bits have to be : wantedValue = ?01
1379 //Pout<< "For point " << facePoint << endl;
1381 // Go up until we have chance to cross to the wanted direction
1382 while (wantedValue != (octant & octantMask))
1384 // Go up to the parent.
1386 // Remove the directions that are not on the boundary of the parent.
1387 // See diagram above
1388 if (wantedValue & X) // && octantMask&X
1390 // Looking for right octant.
1393 // My octant is one of the left ones so punch out the x check
1402 // My octant is right but I want to go left.
1408 if (wantedValue & Y)
1425 if (wantedValue & Z)
1445 walkToParent(nodeI, octant, parentNodeI, parentOctant);
1447 if (parentNodeI == -1)
1449 // Reached edge of tree
1453 //Pout<< " walked from node:" << nodeI << " octant:" << octant
1454 // << " bb:" << nodes_[nodeI].bb_.subBbox(octant) << endl
1455 // << " to:" << parentNodeI << " octant:" << parentOctant
1456 // << " bb:" << nodes_[parentNodeI].bb_.subBbox(parentOctant)
1459 //Pout<< " octantMask:" << octantMask
1460 // << " wantedValue:" << wantedValue << endl;
1462 nodeI = parentNodeI;
1463 octant = parentOctant;
1466 // So now we hit the correct parent node. Switch to the correct octant.
1467 // Is done by jumping to the 'other half' so if e.g. in x direction in
1468 // right half we now jump to the left half.
1469 octant ^= octantMask;
1471 //Pout<< " to node:" << nodeI << " octant:" << octant
1472 // << " subBb:" <<subBbox(nodeI, octant) << endl;
1477 const treeBoundBox subBb(subBbox(nodeI, octant));
1479 if (!subBb.contains(facePoint))
1481 FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
1482 << "When searching for " << facePoint
1483 << " ended up in node:" << nodeI
1484 << " octant:" << octant
1485 << " with bb:" << subBb
1486 << abort(FatalError);
1491 // See if we need to travel down. Note that we already go into the
1492 // the first level ourselves (instead of having findNode decide)
1493 labelBits index = nodes_[nodeI].subNodes_[octant];
1497 labelBits node = findNode(getNode(index), facePoint);
1499 nodeI = getNode(node);
1500 octant = getOctant(node);
1506 const treeBoundBox subBb(subBbox(nodeI, octant));
1508 if (nodeI == oldNodeI && octant == oldOctant)
1510 FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
1511 << "Did not go to neighbour when searching for " << facePoint
1513 << " starting from face:" << faceString(faceID)
1514 << " node:" << nodeI
1515 << " octant:" << octant
1517 << abort(FatalError);
1520 if (!subBb.contains(facePoint))
1522 FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
1523 << "When searching for " << facePoint
1524 << " ended up in node:" << nodeI
1525 << " octant:" << octant
1527 << abort(FatalError);
1536 template <class Type>
1537 Foam::word Foam::indexedOctree<Type>::faceString
1539 const direction faceID
1548 if (faceID & treeBoundBox::LEFTBIT)
1550 if (!desc.empty()) desc += "+";
1553 if (faceID & treeBoundBox::RIGHTBIT)
1555 if (!desc.empty()) desc += "+";
1558 if (faceID & treeBoundBox::BOTTOMBIT)
1560 if (!desc.empty()) desc += "+";
1563 if (faceID & treeBoundBox::TOPBIT)
1565 if (!desc.empty()) desc += "+";
1568 if (faceID & treeBoundBox::BACKBIT)
1570 if (!desc.empty()) desc += "+";
1573 if (faceID & treeBoundBox::FRONTBIT)
1575 if (!desc.empty()) desc += "+";
1582 // Traverse a node. If intersects a triangle return first intersection point:
1583 // hitInfo.index = index of shape
1584 // hitInfo.point = point on shape
1585 // Else return a miss and the bounding box face hit:
1586 // hitInfo.point = coordinate of intersection of ray with bounding box
1587 // hitBits = posbits of point on bounding box
1588 template <class Type>
1589 void Foam::indexedOctree<Type>::traverseNode
1592 const point& treeStart,
1593 const vector& treeVec,
1598 const direction octant,
1600 pointIndexHit& hitInfo,
1606 const treeBoundBox octantBb(subBbox(nodeI, octant));
1608 if (octantBb.posBits(start) != 0)
1610 FatalErrorIn("indexedOctree<Type>::traverseNode(..)")
1611 << "Node:" << nodeI << " octant:" << octant
1612 << " bb:" << octantBb << endl
1613 << "does not contain point " << start << abort(FatalError);
1618 const node& nod = nodes_[nodeI];
1620 labelBits index = nod.subNodes_[octant];
1622 if (isContent(index))
1624 const labelList& indices = contents_[getContent(index)];
1628 // Find any intersection
1630 forAll(indices, elemI)
1632 label shapeI = indices[elemI];
1635 bool hit = shapes_.intersects(shapeI, start, end, pt);
1639 // Hit so pt is nearer than nearestPoint.
1642 hitInfo.setIndex(shapeI);
1643 hitInfo.setPoint(pt);
1650 // Find nearest intersection.
1652 point nearestPoint(end);
1654 forAll(indices, elemI)
1656 label shapeI = indices[elemI];
1659 bool hit = shapes_.intersects(shapeI, start, nearestPoint, pt);
1663 // Hit so pt is nearer than nearestPoint.
1667 hitInfo.setIndex(shapeI);
1668 hitInfo.setPoint(pt);
1674 // Found intersected shape.
1680 // Nothing intersected in this node
1681 // Traverse to end of node. Do by ray tracing back from end and finding
1682 // intersection with bounding box of node.
1683 // start point is now considered to be inside bounding box.
1685 const treeBoundBox octantBb(subBbox(nodeI, octant));
1688 bool intersected = octantBb.intersects
1691 (start-end), //treeVec,
1703 // Return miss. Set misspoint to face.
1704 hitInfo.setPoint(pt);
1708 // Rare case: did not find intersection of ray with octantBb. Can
1709 // happen if end is on face/edge of octantBb. Do like
1710 // lagrangian and re-track with perturbed vector (slightly pushed out
1713 point perturbedEnd(pushPoint(octantBb, end, false));
1718 // Dump octantBb to obj
1719 writeOBJ(nodeI, octant);
1720 // Dump ray to obj as well
1722 OFstream str("ray.obj");
1723 meshTools::writeOBJ(str, start);
1724 meshTools::writeOBJ(str, end);
1725 str << "l 1 2" << nl;
1727 WarningIn("indexedOctree<Type>::traverseNode(..)")
1728 << "Did not intersect ray from endpoint:" << end
1729 << " to startpoint:" << start
1730 << " with bounding box:" << octantBb << nl
1731 << "Re-intersecting with perturbed endpoint:" << perturbedEnd
1752 // Find first intersection
1753 template <class Type>
1754 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1757 const point& treeStart,
1758 const point& treeEnd,
1759 const label startNodeI,
1760 const direction startOctant,
1764 const vector treeVec(treeEnd - treeStart);
1766 // Current node as parent+octant
1767 label nodeI = startNodeI;
1768 direction octant = startOctant;
1772 Pout<< "findLine : treeStart:" << treeStart
1773 << " treeEnd:" << treeEnd << endl
1775 << " octant:" << octant
1776 << " bb:" << subBbox(nodeI, octant) << endl;
1779 // Current position. Initialize to miss
1780 pointIndexHit hitInfo(false, treeStart, -1);
1784 for (; i < 100000; i++)
1786 // Ray-trace to end of current node. Updates point (either on triangle
1787 // in case of hit or on node bounding box in case of miss)
1789 const treeBoundBox octantBb(subBbox(nodeI, octant));
1791 // Make sure point is away from any edges/corners
1805 << " at current:" << hitInfo.rawPoint()
1806 << " (perturbed:" << startPoint << ")" << endl
1807 << " node:" << nodeI
1808 << " octant:" << octant
1809 << " bb:" << subBbox(nodeI, octant) << endl;
1815 // Faces of current bounding box current point is on
1816 direction hitFaceID = 0;
1824 startPoint, // Note: pass in copy since hitInfo
1825 // also used in return value.
1826 treeEnd, // pass in overall end so is nicely outside bb
1834 // Did we hit a triangle?
1840 if (hitFaceID == 0 || hitInfo.rawPoint() == treeEnd)
1842 // endpoint inside the tree. Return miss.
1846 // Create a point on other side of face.
1847 point perturbedPoint
1854 false // push outside of octantBb
1860 Pout<< " iter:" << i
1861 << " hit face:" << faceString(hitFaceID)
1862 << " at:" << hitInfo.rawPoint() << nl
1863 << " node:" << nodeI
1864 << " octant:" << octant
1865 << " bb:" << subBbox(nodeI, octant) << nl
1866 << " walking to neighbour containing:" << perturbedPoint
1871 // Nothing hit so we are on face of bounding box (given as node+octant+
1872 // position bits). Traverse to neighbouring node. Use slightly perturbed
1875 bool ok = walkToNeighbour
1878 hitFaceID, // face(s) that hitInfo is on
1886 // Hit the edge of the tree. Return miss.
1892 const treeBoundBox octantBb(subBbox(nodeI, octant));
1893 Pout<< " walked for point:" << hitInfo.rawPoint() << endl
1894 << " to neighbour node:" << nodeI
1895 << " octant:" << octant
1896 << " face:" << faceString(octantBb.faceBits(hitInfo.rawPoint()))
1897 << " of octantBb:" << octantBb << endl
1904 // Probably in loop.
1907 // Redo intersection but now with verbose flag switched on.
1920 FatalErrorIn("indexedOctree<Type>::findLine(..)")
1921 << "Got stuck in loop raytracing from:" << treeStart
1922 << " to:" << treeEnd << endl
1923 << "inside top box:" << subBbox(startNodeI, startOctant)
1924 << abort(FatalError);
1928 WarningIn("indexedOctree<Type>::findLine(..)")
1929 << "Got stuck in loop raytracing from:" << treeStart
1930 << " to:" << treeEnd << endl
1931 << "inside top box:" << subBbox(startNodeI, startOctant)
1940 // Find first intersection
1941 template <class Type>
1942 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1949 pointIndexHit hitInfo;
1953 const treeBoundBox& treeBb = nodes_[0].bb_;
1955 // No effort is made to deal with points which are on edge of tree
1956 // bounding box for now.
1958 direction startBit = treeBb.posBits(start);
1959 direction endBit = treeBb.posBits(end);
1961 if ((startBit & endBit) != 0)
1963 // Both start and end outside domain and in same block.
1964 return pointIndexHit(false, vector::zero, -1);
1968 // Trim segment to treeBb
1970 point trackStart(start);
1971 point trackEnd(end);
1975 // Track start to inside domain.
1976 if (!treeBb.intersects(start, end, trackStart))
1978 return pointIndexHit(false, vector::zero, -1);
1984 // Track end to inside domain.
1985 if (!treeBb.intersects(end, trackStart, trackEnd))
1987 return pointIndexHit(false, vector::zero, -1);
1992 // Find lowest level tree node that start is in.
1993 labelBits index = findNode(0, trackStart);
1995 label parentNodeI = getNode(index);
1996 direction octant = getOctant(index);
2012 template <class Type>
2013 void Foam::indexedOctree<Type>::findBox
2016 const treeBoundBox& searchBox,
2017 labelHashSet& elements
2020 const node& nod = nodes_[nodeI];
2021 const treeBoundBox& nodeBb = nod.bb_;
2023 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2025 labelBits index = nod.subNodes_[octant];
2029 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
2031 if (subBb.overlaps(searchBox))
2033 findBox(getNode(index), searchBox, elements);
2036 else if (isContent(index))
2038 const treeBoundBox subBb(nodeBb.subBbox(octant));
2040 if (subBb.overlaps(searchBox))
2042 const labelList& indices = contents_[getContent(index)];
2046 label shapeI = indices[i];
2048 if (shapes_.overlaps(shapeI, searchBox))
2050 elements.insert(shapeI);
2059 // Number of elements in node.
2060 template <class Type>
2061 Foam::label Foam::indexedOctree<Type>::countElements
2063 const labelBits index
2071 label nodeI = getNode(index);
2073 const node& nod = nodes_[nodeI];
2075 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2077 nElems += countElements(nod.subNodes_[octant]);
2080 else if (isContent(index))
2082 nElems += contents_[getContent(index)].size();
2093 template <class Type>
2094 void Foam::indexedOctree<Type>::writeOBJ
2097 const direction octant
2102 "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
2105 labelBits index = nodes_[nodeI].subNodes_[octant];
2111 subBb = nodes_[getNode(index)].bb_;
2113 else if (isContent(index))
2115 subBb = nodes_[nodeI].bb_.subBbox(octant);
2118 Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
2119 << " to " << str.name() << endl;
2123 // Dump bounding box
2124 pointField bbPoints(subBb.points());
2126 label pointVertI = vertI;
2129 meshTools::writeOBJ(str, bbPoints[i]);
2133 forAll(treeBoundBox::edges, i)
2135 const edge& e = treeBoundBox::edges[i];
2137 str<< "l " << e[0]+pointVertI+1 << ' ' << e[1]+pointVertI+1 << nl;
2142 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
2144 template <class Type>
2145 Foam::indexedOctree<Type>::indexedOctree(const Type& shapes)
2154 template <class Type>
2155 Foam::indexedOctree<Type>::indexedOctree
2158 const List<node>& nodes,
2159 const labelListList& contents
2164 contents_(contents),
2169 template <class Type>
2170 Foam::indexedOctree<Type>::indexedOctree
2173 const treeBoundBox& bb,
2174 const label maxLevels, // maximum number of levels
2175 const scalar maxLeafRatio,
2176 const scalar maxDuplicity
2186 Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2187 << " shapes:" << shapes.size() << nl
2188 << " bb:" << bb << nl
2192 if (shapes.size() == 0)
2197 // Start off with one node with all shapes in it.
2198 DynamicList<node> nodes(label(shapes.size() / maxLeafRatio));
2199 DynamicList<labelList> contents(label(shapes.size() / maxLeafRatio));
2200 contents.append(identity(shapes.size()));
2203 node topNode(divide(bb, contents, 0));
2204 nodes.append(topNode);
2207 // Now have all contents at level 1. Create levels by splitting levels
2212 for (; nLevels < maxLevels; nLevels++)
2214 // Count number of references into shapes (i.e. contents)
2218 nEntries += contents[i].size();
2223 Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2224 << " nLevels:" << nLevels << nl
2225 << " nEntries per treeLeaf:" << nEntries/contents.size()
2227 << " nEntries per shape (duplicity):"
2228 << nEntries/shapes.size()
2235 //nEntries < maxLeafRatio*contents.size()
2237 nEntries > maxDuplicity*shapes.size()
2244 // Split nodes with more than maxLeafRatio elements
2245 label nOldNodes = nodes.size();
2248 label(maxLeafRatio),
2253 if (nOldNodes == nodes.size())
2264 // Compact such that deeper level contents are always after the
2265 // ones for a shallower level. This way we can slice a coarser level
2267 contents_.setSize(contents.size());
2285 if (compactI == contents_.size())
2287 // Transferred all contents to contents_ (in order breadth first)
2293 nodes_.transfer(nodes);
2299 forAll(contents_, i)
2301 nEntries += contents_[i].size();
2304 Pout<< "indexedOctree<Type>::indexedOctree"
2305 << " : finished construction of tree of:" << shapes.typeName
2307 << " bb:" << this->bb() << nl
2308 << " shapes:" << shapes.size() << nl
2309 << " nLevels:" << nLevels << nl
2310 << " treeNodes:" << nodes_.size() << nl
2311 << " nEntries:" << nEntries << nl
2313 << scalar(nEntries)/contents.size() << nl
2314 << " per shape (duplicity):"
2315 << scalar(nEntries)/shapes.size() << nl
2321 template <class Type>
2322 Foam::indexedOctree<Type>::indexedOctree
2335 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2337 template <class Type>
2338 Foam::scalar& Foam::indexedOctree<Type>::perturbTol()
2344 template <class Type>
2345 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
2347 const point& sample,
2348 const scalar startDistSqr
2351 scalar nearestDistSqr = startDistSqr;
2352 label nearestShapeI = -1;
2369 nearestPoint = vector::zero;
2372 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2376 template <class Type>
2377 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
2379 const linePointRef& ln,
2380 treeBoundBox& tightest,
2384 label nearestShapeI = -1;
2402 nearestPoint = vector::zero;
2405 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2409 // Find nearest intersection
2410 template <class Type>
2411 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
2417 return findLine(false, start, end);
2421 // Find nearest intersection
2422 template <class Type>
2423 Foam::pointIndexHit Foam::indexedOctree<Type>::findLineAny
2429 return findLine(true, start, end);
2433 template <class Type>
2434 Foam::labelList Foam::indexedOctree<Type>::findBox
2436 const treeBoundBox& searchBox
2439 // Storage for labels of shapes inside bb. Size estimate.
2440 labelHashSet elements(shapes_.size() / 100);
2444 findBox(0, searchBox, elements);
2447 return elements.toc();
2451 // Find node (as parent+octant) containing point
2452 template <class Type>
2453 Foam::labelBits Foam::indexedOctree<Type>::findNode
2461 // Empty tree. Return what?
2462 return nodePlusOctant(nodeI, 0);
2465 const node& nod = nodes_[nodeI];
2469 if (!nod.bb_.contains(sample))
2471 FatalErrorIn("findNode(..)")
2472 << "Cannot find " << sample << " in node " << nodeI
2473 << abort(FatalError);
2477 direction octant = nod.bb_.subOctant(sample);
2479 labelBits index = nod.subNodes_[octant];
2484 return findNode(getNode(index), sample);
2486 else if (isContent(index))
2488 // Content. Return treenode+octant
2489 return nodePlusOctant(nodeI, octant);
2493 // Empty. Return treenode+octant
2494 return nodePlusOctant(nodeI, octant);
2499 // Determine type (inside/outside/mixed) per node.
2500 template <class Type>
2501 typename Foam::indexedOctree<Type>::volumeType
2502 Foam::indexedOctree<Type>::getVolumeType
2512 if (nodeTypes_.size() != 8*nodes_.size())
2514 // Calculate type for every octant of node.
2516 nodeTypes_.setSize(8*nodes_.size());
2517 nodeTypes_ = UNKNOWN;
2528 forAll(nodeTypes_, i)
2530 volumeType type = volumeType(nodeTypes_.get(i));
2532 if (type == UNKNOWN)
2536 else if (type == MIXED)
2540 else if (type == INSIDE)
2544 else if (type == OUTSIDE)
2550 FatalErrorIn("getVolumeType") << abort(FatalError);
2554 Pout<< "indexedOctree<Type>::getVolumeType : "
2556 << " nodes_:" << nodes_.size()
2557 << " nodeTypes_:" << nodeTypes_.size()
2558 << " nUNKNOWN:" << nUNKNOWN
2559 << " nMIXED:" << nMIXED
2560 << " nINSIDE:" << nINSIDE
2561 << " nOUTSIDE:" << nOUTSIDE
2566 return getVolumeType(0, sample);
2570 // Print contents of nodeI
2571 template <class Type>
2572 void Foam::indexedOctree<Type>::print
2575 const bool printContents,
2579 const node& nod = nodes_[nodeI];
2580 const treeBoundBox& bb = nod.bb_;
2582 os << "nodeI:" << nodeI << " bb:" << bb << nl
2583 << "parent:" << nod.parent_ << nl
2584 << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
2586 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2588 const treeBoundBox subBb(bb.subBbox(octant));
2590 labelBits index = nod.subNodes_[octant];
2595 label subNodeI = getNode(index);
2597 os << "octant:" << octant
2598 << " node: n:" << countElements(index)
2599 << " bb:" << subBb << endl;
2601 string oldPrefix = os.prefix();
2602 os.prefix() = " " + oldPrefix;
2604 print(os, printContents, subNodeI);
2606 os.prefix() = oldPrefix;
2608 else if (isContent(index))
2610 const labelList& indices = contents_[getContent(index)];
2612 os << "octant:" << octant
2613 << " content: n:" << indices.size()
2621 os << ' ' << indices[j];
2628 os << "octant:" << octant << " empty:" << subBb << endl;
2634 // Print contents of nodeI
2635 template <class Type>
2636 bool Foam::indexedOctree<Type>::write(Ostream& os) const
2644 template <class Type>
2645 Foam::Ostream& Foam::operator<<(Ostream& os, const indexedOctree<Type>& t)
2648 os << t.bb() << token::SPACE << t.nodes()
2649 << token::SPACE << t.contents();
2653 // ************************************************************************* //