1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "indexedOctree.H"
27 #include "linePointRef.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 Foam::scalar Foam::indexedOctree<Type>::perturbTol_ = 10*SMALL;
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 // Does bb intersect a sphere around sample? Or is any corner point of bb
40 // closer than nearestDistSqr to sample.
42 bool Foam::indexedOctree<Type>::overlaps
46 const scalar nearestDistSqr,
50 // Find out where sample is in relation to bb.
51 // Find nearest point on bb.
54 for (direction dir = 0; dir < vector::nComponents; dir++)
56 scalar d0 = p0[dir] - sample[dir];
57 scalar d1 = p1[dir] - sample[dir];
59 if ((d0 > 0) != (d1 > 0))
61 // sample inside both extrema. This component does not add any
64 else if (mag(d0) < mag(d1))
73 if (distSqr > nearestDistSqr)
83 // Does bb intersect a sphere around sample? Or is any corner point of bb
84 // closer than nearestDistSqr to sample.
86 bool Foam::indexedOctree<Type>::overlaps
88 const treeBoundBox& parentBb,
89 const direction octant,
90 const scalar nearestDistSqr,
94 //- Accelerated version of
95 // treeBoundBox subBb(parentBb.subBbox(mid, octant))
104 const point& min = parentBb.min();
105 const point& max = parentBb.max();
109 if (octant & treeBoundBox::RIGHTHALF)
118 if (octant & treeBoundBox::TOPHALF)
127 if (octant & treeBoundBox::FRONTHALF)
136 const point mid(0.5*(min+max));
138 return overlaps(mid, other, nearestDistSqr, sample);
143 // Construction helper routines
144 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147 // Split list of indices into 8 bins
148 template <class Type>
149 void Foam::indexedOctree<Type>::divide
151 const labelList& indices,
152 const treeBoundBox& bb,
153 labelListList& result
156 List<DynamicList<label> > subIndices(8);
157 for (direction octant = 0; octant < subIndices.size(); octant++)
159 subIndices[octant].setCapacity(indices.size()/8);
162 // Precalculate bounding boxes.
163 FixedList<treeBoundBox, 8> subBbs;
164 for (direction octant = 0; octant < subBbs.size(); octant++)
166 subBbs[octant] = bb.subBbox(octant);
171 label shapeI = indices[i];
173 for (direction octant = 0; octant < 8; octant++)
175 if (shapes_.overlaps(shapeI, subBbs[octant]))
177 subIndices[octant].append(shapeI);
183 for (direction octant = 0; octant < subIndices.size(); octant++)
185 result[octant].transfer(subIndices[octant]);
190 // Subdivide the (content) node.
191 template <class Type>
192 typename Foam::indexedOctree<Type>::node
193 Foam::indexedOctree<Type>::divide
195 const treeBoundBox& bb,
196 DynamicList<labelList>& contents,
200 const labelList& indices = contents[contentI];
206 bb.min()[0] >= bb.max()[0]
207 || bb.min()[1] >= bb.max()[1]
208 || bb.min()[2] >= bb.max()[2]
211 FatalErrorIn("indexedOctree<Type>::divide(..)")
212 << "Badly formed bounding box:" << bb
213 << abort(FatalError);
219 labelListList dividedIndices(8);
220 divide(indices, bb, dividedIndices);
222 // Have now divided the indices into 8 (possibly empty) subsets.
223 // Replace current contentI with the first (non-empty) subset.
225 bool replaced = false;
227 for (direction octant = 0; octant < dividedIndices.size(); octant++)
229 labelList& subIndices = dividedIndices[octant];
231 if (subIndices.size())
235 contents[contentI].transfer(subIndices);
236 nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
241 // Store at end of contents.
242 // note dummy append + transfer trick
243 label sz = contents.size();
244 contents.append(labelList(0));
245 contents[sz].transfer(subIndices);
246 nod.subNodes_[octant] = contentPlusOctant(sz, octant);
251 // Mark node as empty
252 nod.subNodes_[octant] = emptyPlusOctant(octant);
260 // Split any contents node with more than minSize elements.
261 template <class Type>
262 void Foam::indexedOctree<Type>::splitNodes
265 DynamicList<indexedOctree<Type>::node>& nodes,
266 DynamicList<labelList>& contents
269 label currentSize = nodes.size();
271 // Take care to loop only over old nodes.
272 // Also we loop over the same DynamicList which gets modified and
273 // moved so make sure not to keep any references!
274 for (label nodeI = 0; nodeI < currentSize; nodeI++)
278 direction octant = 0;
279 octant < nodes[nodeI].subNodes_.size();
283 labelBits index = nodes[nodeI].subNodes_[octant];
287 // tree node. Leave intact.
289 else if (isContent(index))
291 label contentI = getContent(index);
293 if (contents[contentI].size() > minSize)
295 // Create node for content.
297 // Find the bounding box for the subnode
298 const node& nod = nodes[nodeI];
299 const treeBoundBox bb(nod.bb_.subBbox(octant));
301 node subNode(divide(bb, contents, contentI));
302 subNode.parent_ = nodeI;
303 label sz = nodes.size();
304 nodes.append(subNode);
305 nodes[nodeI].subNodes_[octant] = nodePlusOctant(sz, octant);
313 // Reorder contents to be in same order as nodes. Returns number of nodes on
315 template <class Type>
316 Foam::label Foam::indexedOctree<Type>::compactContents
318 DynamicList<node>& nodes,
319 DynamicList<labelList>& contents,
320 const label compactLevel,
324 List<labelList>& compactedContents,
328 const node& nod = nodes[nodeI];
332 if (level < compactLevel)
334 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
336 labelBits index = nod.subNodes_[octant];
340 nNodes += compactContents
353 else if (level == compactLevel)
355 // Compact all content on this level
356 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
358 labelBits index = nod.subNodes_[octant];
360 if (isContent(index))
362 label contentI = getContent(index);
364 compactedContents[compactI].transfer(contents[contentI]);
366 // Subnode is at compactI. Adapt nodeI to point to it
367 nodes[nodeI].subNodes_[octant] =
368 contentPlusOctant(compactI, octant);
372 else if (isNode(index))
382 // Pre-calculates wherever possible the volume status per node/subnode.
383 // Recurses to determine status of lowest level boxes. Level above is
384 // combination of octants below.
385 template <class Type>
386 typename Foam::indexedOctree<Type>::volumeType
387 Foam::indexedOctree<Type>::calcVolumeType
392 const node& nod = nodes_[nodeI];
394 volumeType myType = UNKNOWN;
396 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
400 labelBits index = nod.subNodes_[octant];
404 // tree node. Recurse.
405 subType = calcVolumeType(getNode(index));
407 else if (isContent(index))
409 // Contents. Depending on position in box might be on either
415 // No data in this octant. Set type for octant acc. to the mid
416 // of its bounding box.
417 const treeBoundBox subBb = nod.bb_.subBbox(octant);
421 shapes_.getVolumeType(*this, subBb.midpoint())
426 nodeTypes_.set((nodeI<<3)+octant, subType);
428 // Combine sub node types into type for treeNode. Result is 'mixed' if
429 // types differ among subnodes.
430 if (myType == UNKNOWN)
434 else if (subType != myType)
443 template <class Type>
444 typename Foam::indexedOctree<Type>::volumeType
445 Foam::indexedOctree<Type>::getVolumeType
451 const node& nod = nodes_[nodeI];
453 direction octant = nod.bb_.subOctant(sample);
455 volumeType octantType = volumeType(nodeTypes_.get((nodeI<<3)+octant));
457 if (octantType == INSIDE)
461 else if (octantType == OUTSIDE)
465 else if (octantType == UNKNOWN)
467 // Can happen for e.g. non-manifold surfaces.
470 else if (octantType == MIXED)
472 labelBits index = nod.subNodes_[octant];
477 volumeType subType = getVolumeType(getNode(index), sample);
481 else if (isContent(index))
483 // Content. Defer to shapes.
484 return volumeType(shapes_.getVolumeType(*this, sample));
488 // Empty node. Cannot have 'mixed' as its type since not divided
489 // up and has no items inside it.
492 "indexedOctree<Type>::getVolumeType"
493 "(const label, const point&)"
494 ) << "Sample:" << sample << " node:" << nodeI
495 << " with bb:" << nodes_[nodeI].bb_ << nl
496 << "Empty subnode has invalid volume type MIXED."
497 << abort(FatalError);
506 "indexedOctree<Type>::getVolumeType"
507 "(const label, const point&)"
508 ) << "Sample:" << sample << " at node:" << nodeI
509 << " octant:" << octant
510 << " with bb:" << nod.bb_.subBbox(octant) << nl
511 << "Node has invalid volume type " << octantType
512 << abort(FatalError);
519 template <class Type>
520 typename Foam::indexedOctree<Type>::volumeType
521 Foam::indexedOctree<Type>::getSide
523 const vector& outsideNormal,
527 if ((outsideNormal&vec) >= 0)
543 // Find nearest point starting from nodeI
544 template <class Type>
545 void Foam::indexedOctree<Type>::findNearest
550 scalar& nearestDistSqr,
551 label& nearestShapeI,
555 const node& nod = nodes_[nodeI];
557 // Determine order to walk through octants
558 FixedList<direction, 8> octantOrder;
559 nod.bb_.searchOrder(sample, octantOrder);
561 // Go into all suboctants (one containing sample first) and update nearest.
562 for (direction i = 0; i < 8; i++)
564 direction octant = octantOrder[i];
566 labelBits index = nod.subNodes_[octant];
570 label subNodeI = getNode(index);
572 const treeBoundBox& subBb = nodes_[subNodeI].bb_;
574 if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
587 else if (isContent(index))
602 contents_[getContent(index)],
615 // Find nearest point to line.
616 template <class Type>
617 void Foam::indexedOctree<Type>::findNearest
620 const linePointRef& ln,
622 treeBoundBox& tightest,
623 label& nearestShapeI,
628 const node& nod = nodes_[nodeI];
629 const treeBoundBox& nodeBb = nod.bb_;
631 // Determine order to walk through octants
632 FixedList<direction, 8> octantOrder;
633 nod.bb_.searchOrder(ln.centre(), octantOrder);
635 // Go into all suboctants (one containing sample first) and update nearest.
636 for (direction i = 0; i < 8; i++)
638 direction octant = octantOrder[i];
640 labelBits index = nod.subNodes_[octant];
644 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
646 if (subBb.overlaps(tightest))
660 else if (isContent(index))
662 const treeBoundBox subBb(nodeBb.subBbox(octant));
664 if (subBb.overlaps(tightest))
668 contents_[getContent(index)],
682 template <class Type>
683 Foam::treeBoundBox Foam::indexedOctree<Type>::subBbox
685 const label parentNodeI,
686 const direction octant
689 // Get type of node at octant
690 const node& nod = nodes_[parentNodeI];
691 labelBits index = nod.subNodes_[octant];
696 return nodes_[getNode(index)].bb_;
701 return nod.bb_.subBbox(octant);
706 // Takes a bb and a point on/close to the edge of the bb and pushes the point
707 // inside by a small fraction.
708 template <class Type>
709 Foam::point Foam::indexedOctree<Type>::pushPoint
711 const treeBoundBox& bb,
713 const bool pushInside
716 // Get local length scale.
717 const vector perturbVec = perturbTol_*bb.span();
719 point perturbedPt(pt);
721 // Modify all components which are close to any face of the bb to be
722 // well inside/outside them.
726 for (direction dir = 0; dir < vector::nComponents; dir++)
728 if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
730 // Close to 'left' side. Push well beyond left side.
731 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
732 perturbedPt[dir] = bb.min()[dir] + perturbDist;
734 else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
736 // Close to 'right' side. Push well beyond right side.
737 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
738 perturbedPt[dir] = bb.max()[dir] - perturbDist;
744 for (direction dir = 0; dir < vector::nComponents; dir++)
746 if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
748 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
749 perturbedPt[dir] = bb.min()[dir] - perturbDist;
751 else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
753 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
754 perturbedPt[dir] = bb.max()[dir] + perturbDist;
761 if (pushInside != bb.contains(perturbedPt))
763 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
764 << "pushed point:" << pt
765 << " to:" << perturbedPt
766 << " wanted side:" << pushInside
767 << " obtained side:" << bb.contains(perturbedPt)
769 << abort(FatalError);
777 // Takes a bb and a point on the edge of the bb and pushes the point
778 // outside by a small fraction.
779 template <class Type>
780 Foam::point Foam::indexedOctree<Type>::pushPoint
782 const treeBoundBox& bb,
783 const direction faceID,
785 const bool pushInside
788 // Get local length scale.
789 const vector perturbVec = perturbTol_*bb.span();
791 point perturbedPt(pt);
793 // Modify all components which are close to any face of the bb to be
794 // well outside them.
798 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
799 << abort(FatalError);
802 if (faceID & treeBoundBox::LEFTBIT)
806 perturbedPt[0] = bb.min()[0] + (perturbVec[0] + ROOTVSMALL);
810 perturbedPt[0] = bb.min()[0] - (perturbVec[0] + ROOTVSMALL);
813 else if (faceID & treeBoundBox::RIGHTBIT)
817 perturbedPt[0] = bb.max()[0] - (perturbVec[0] + ROOTVSMALL);
821 perturbedPt[0] = bb.max()[0] + (perturbVec[0] + ROOTVSMALL);
825 if (faceID & treeBoundBox::BOTTOMBIT)
829 perturbedPt[1] = bb.min()[1] + (perturbVec[1] + ROOTVSMALL);
833 perturbedPt[1] = bb.min()[1] - (perturbVec[1] + ROOTVSMALL);
836 else if (faceID & treeBoundBox::TOPBIT)
840 perturbedPt[1] = bb.max()[1] - (perturbVec[1] + ROOTVSMALL);
844 perturbedPt[1] = bb.max()[1] + (perturbVec[1] + ROOTVSMALL);
848 if (faceID & treeBoundBox::BACKBIT)
852 perturbedPt[2] = bb.min()[2] + (perturbVec[2] + ROOTVSMALL);
856 perturbedPt[2] = bb.min()[2] - (perturbVec[2] + ROOTVSMALL);
859 else if (faceID & treeBoundBox::FRONTBIT)
863 perturbedPt[2] = bb.max()[2] - (perturbVec[2] + ROOTVSMALL);
867 perturbedPt[2] = bb.max()[2] + (perturbVec[2] + ROOTVSMALL);
873 if (pushInside != bb.contains(perturbedPt))
875 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
876 << "pushed point:" << pt << " on face:" << faceString(faceID)
877 << " to:" << perturbedPt
878 << " wanted side:" << pushInside
879 << " obtained side:" << bb.contains(perturbedPt)
881 << abort(FatalError);
889 // Guarantees that if pt is on a face it gets perturbed so it is away
890 // from the face edges.
891 // If pt is not on a face does nothing.
892 template <class Type>
893 Foam::point Foam::indexedOctree<Type>::pushPointIntoFace
895 const treeBoundBox& bb,
896 const vector& dir, // end-start
902 if (bb.posBits(pt) != 0)
904 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
905 << " bb:" << bb << endl
906 << "does not contain point " << pt << abort(FatalError);
912 // - point exactly on multiple faces. Push away from all but one.
913 // - point on a single face. Push away from edges of face.
915 direction ptFaceID = bb.faceBits(pt);
917 direction nFaces = 0;
918 FixedList<direction, 3> faceIndices;
920 if (ptFaceID & treeBoundBox::LEFTBIT)
922 faceIndices[nFaces++] = treeBoundBox::LEFT;
924 else if (ptFaceID & treeBoundBox::RIGHTBIT)
926 faceIndices[nFaces++] = treeBoundBox::RIGHT;
929 if (ptFaceID & treeBoundBox::BOTTOMBIT)
931 faceIndices[nFaces++] = treeBoundBox::BOTTOM;
933 else if (ptFaceID & treeBoundBox::TOPBIT)
935 faceIndices[nFaces++] = treeBoundBox::TOP;
938 if (ptFaceID & treeBoundBox::BACKBIT)
940 faceIndices[nFaces++] = treeBoundBox::BACK;
942 else if (ptFaceID & treeBoundBox::FRONTBIT)
944 faceIndices[nFaces++] = treeBoundBox::FRONT;
948 // Determine the face we want to keep the point on
950 direction keepFaceID;
954 // Return original point
957 else if (nFaces == 1)
959 // Point is on a single face
960 keepFaceID = faceIndices[0];
964 // Determine best face out of faceIndices[0 .. nFaces-1].
965 // The best face is the one most perpendicular to the ray direction.
967 keepFaceID = faceIndices[0];
968 scalar maxInproduct = mag(treeBoundBox::faceNormals[keepFaceID] & dir);
970 for (direction i = 1; i < nFaces; i++)
972 direction face = faceIndices[i];
973 scalar s = mag(treeBoundBox::faceNormals[face] & dir);
974 if (s > maxInproduct)
983 // 1. Push point into bb, away from all corners
985 point facePoint(pushPoint(bb, pt, true));
986 direction faceID = 0;
988 // 2. Snap it back onto the preferred face
990 if (keepFaceID == treeBoundBox::LEFT)
992 facePoint.x() = bb.min().x();
993 faceID = treeBoundBox::LEFTBIT;
995 else if (keepFaceID == treeBoundBox::RIGHT)
997 facePoint.x() = bb.max().x();
998 faceID = treeBoundBox::RIGHTBIT;
1000 else if (keepFaceID == treeBoundBox::BOTTOM)
1002 facePoint.y() = bb.min().y();
1003 faceID = treeBoundBox::BOTTOMBIT;
1005 else if (keepFaceID == treeBoundBox::TOP)
1007 facePoint.y() = bb.max().y();
1008 faceID = treeBoundBox::TOPBIT;
1010 else if (keepFaceID == treeBoundBox::BACK)
1012 facePoint.z() = bb.min().z();
1013 faceID = treeBoundBox::BACKBIT;
1015 else if (keepFaceID == treeBoundBox::FRONT)
1017 facePoint.z() = bb.max().z();
1018 faceID = treeBoundBox::FRONTBIT;
1024 if (faceID != bb.faceBits(facePoint))
1026 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
1027 << "Pushed point from " << pt
1028 << " on face:" << ptFaceID << " of bb:" << bb << endl
1029 << "onto " << facePoint
1030 << " on face:" << faceID
1031 << " which is not consistent with geometric face "
1032 << bb.faceBits(facePoint)
1033 << abort(FatalError);
1035 if (bb.posBits(facePoint) != 0)
1037 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
1038 << " bb:" << bb << endl
1039 << "does not contain perturbed point "
1040 << facePoint << abort(FatalError);
1049 //// Takes a bb and a point on the outside of the bb. Checks if on multiple
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)];
1630 // Find any intersection
1632 forAll(indices, elemI)
1634 label shapeI = indices[elemI];
1637 bool hit = shapes_.intersects(shapeI, start, end, pt);
1639 // Note that intersection of shape might actually be
1640 // in a neighbouring box. For findAny this is not important.
1643 // Hit so pt is nearer than nearestPoint.
1646 hitInfo.setIndex(shapeI);
1647 hitInfo.setPoint(pt);
1654 // Find nearest intersection
1656 const treeBoundBox octantBb(subBbox(nodeI, octant));
1658 point nearestPoint(end);
1660 forAll(indices, elemI)
1662 label shapeI = indices[elemI];
1665 bool hit = shapes_.intersects
1673 // Note that intersection of shape might actually be
1674 // in a neighbouring box. Since we need to maintain strict
1675 // (findAny=false) ordering skip such an intersection. It
1676 // will be found when we are doing the next box.
1678 if (hit && octantBb.contains(pt))
1680 // Hit so pt is nearer than nearestPoint.
1684 hitInfo.setIndex(shapeI);
1685 hitInfo.setPoint(pt);
1691 // Found intersected shape.
1698 // Nothing intersected in this node
1699 // Traverse to end of node. Do by ray tracing back from end and finding
1700 // intersection with bounding box of node.
1701 // start point is now considered to be inside bounding box.
1703 const treeBoundBox octantBb(subBbox(nodeI, octant));
1706 bool intersected = octantBb.intersects
1709 (start-end), //treeVec,
1721 // Return miss. Set misspoint to face.
1722 hitInfo.setPoint(pt);
1726 // Rare case: did not find intersection of ray with octantBb. Can
1727 // happen if end is on face/edge of octantBb. Do like
1728 // lagrangian and re-track with perturbed vector (slightly pushed out
1731 point perturbedEnd(pushPoint(octantBb, end, false));
1750 // Find first intersection
1751 template <class Type>
1752 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1755 const point& treeStart,
1756 const point& treeEnd,
1757 const label startNodeI,
1758 const direction startOctant,
1762 const vector treeVec(treeEnd - treeStart);
1764 // Current node as parent+octant
1765 label nodeI = startNodeI;
1766 direction octant = startOctant;
1770 Pout<< "findLine : treeStart:" << treeStart
1771 << " treeEnd:" << treeEnd << endl
1773 << " octant:" << octant
1774 << " bb:" << subBbox(nodeI, octant) << endl;
1777 // Current position. Initialize to miss
1778 pointIndexHit hitInfo(false, treeStart, -1);
1782 for (; i < 100000; i++)
1784 // Ray-trace to end of current node. Updates point (either on triangle
1785 // in case of hit or on node bounding box in case of miss)
1787 const treeBoundBox octantBb(subBbox(nodeI, octant));
1789 // Make sure point is away from any edges/corners
1803 << " at current:" << hitInfo.rawPoint()
1804 << " (perturbed:" << startPoint << ")" << endl
1805 << " node:" << nodeI
1806 << " octant:" << octant
1807 << " bb:" << subBbox(nodeI, octant) << endl;
1813 // Faces of current bounding box current point is on
1814 direction hitFaceID = 0;
1822 startPoint, // Note: pass in copy since hitInfo
1823 // also used in return value.
1824 treeEnd, // pass in overall end so is nicely outside bb
1832 // Did we hit a triangle?
1838 if (hitFaceID == 0 || hitInfo.rawPoint() == treeEnd)
1840 // endpoint inside the tree. Return miss.
1844 // Create a point on other side of face.
1845 point perturbedPoint
1852 false // push outside of octantBb
1858 Pout<< " iter:" << i
1859 << " hit face:" << faceString(hitFaceID)
1860 << " at:" << hitInfo.rawPoint() << nl
1861 << " node:" << nodeI
1862 << " octant:" << octant
1863 << " bb:" << subBbox(nodeI, octant) << nl
1864 << " walking to neighbour containing:" << perturbedPoint
1869 // Nothing hit so we are on face of bounding box (given as node+octant+
1870 // position bits). Traverse to neighbouring node. Use slightly perturbed
1873 bool ok = walkToNeighbour
1876 hitFaceID, // face(s) that hitInfo is on
1884 // Hit the edge of the tree. Return miss.
1890 const treeBoundBox octantBb(subBbox(nodeI, octant));
1891 Pout<< " walked for point:" << hitInfo.rawPoint() << endl
1892 << " to neighbour node:" << nodeI
1893 << " octant:" << octant
1894 << " face:" << faceString(octantBb.faceBits(hitInfo.rawPoint()))
1895 << " of octantBb:" << octantBb << endl
1902 // Probably in loop.
1905 // Redo intersection but now with verbose flag switched on.
1918 FatalErrorIn("indexedOctree<Type>::findLine(..)")
1919 << "Got stuck in loop raytracing from:" << treeStart
1920 << " to:" << treeEnd << endl
1921 << "inside top box:" << subBbox(startNodeI, startOctant)
1922 << abort(FatalError);
1926 WarningIn("indexedOctree<Type>::findLine(..)")
1927 << "Got stuck in loop raytracing from:" << treeStart
1928 << " to:" << treeEnd << endl
1929 << "inside top box:" << subBbox(startNodeI, startOctant)
1938 // Find first intersection
1939 template <class Type>
1940 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1947 pointIndexHit hitInfo;
1951 const treeBoundBox& treeBb = nodes_[0].bb_;
1953 // No effort is made to deal with points which are on edge of tree
1954 // bounding box for now.
1956 direction startBit = treeBb.posBits(start);
1957 direction endBit = treeBb.posBits(end);
1959 if ((startBit & endBit) != 0)
1961 // Both start and end outside domain and in same block.
1962 return pointIndexHit(false, vector::zero, -1);
1966 // Trim segment to treeBb
1968 point trackStart(start);
1969 point trackEnd(end);
1973 // Track start to inside domain.
1974 if (!treeBb.intersects(start, end, trackStart))
1976 return pointIndexHit(false, vector::zero, -1);
1982 // Track end to inside domain.
1983 if (!treeBb.intersects(end, trackStart, trackEnd))
1985 return pointIndexHit(false, vector::zero, -1);
1990 // Find lowest level tree node that start is in.
1991 labelBits index = findNode(0, trackStart);
1993 label parentNodeI = getNode(index);
1994 direction octant = getOctant(index);
2010 template <class Type>
2011 void Foam::indexedOctree<Type>::findBox
2014 const treeBoundBox& searchBox,
2015 labelHashSet& elements
2018 const node& nod = nodes_[nodeI];
2019 const treeBoundBox& nodeBb = nod.bb_;
2021 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2023 labelBits index = nod.subNodes_[octant];
2027 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
2029 if (subBb.overlaps(searchBox))
2031 findBox(getNode(index), searchBox, elements);
2034 else if (isContent(index))
2036 const treeBoundBox subBb(nodeBb.subBbox(octant));
2038 if (subBb.overlaps(searchBox))
2040 const labelList& indices = contents_[getContent(index)];
2044 label shapeI = indices[i];
2046 if (shapes_.overlaps(shapeI, searchBox))
2048 elements.insert(shapeI);
2057 template <class Type>
2058 template <class CompareOp>
2059 void Foam::indexedOctree<Type>::findNear
2061 const scalar nearDist,
2063 const indexedOctree<Type>& tree1,
2064 const labelBits index1,
2065 const treeBoundBox& bb1,
2066 const indexedOctree<Type>& tree2,
2067 const labelBits index2,
2068 const treeBoundBox& bb2,
2072 const vector nearSpan(nearDist, nearDist, nearDist);
2074 if (tree1.isNode(index1))
2076 const node& nod1 = tree1.nodes()[tree1.getNode(index1)];
2077 const treeBoundBox searchBox
2083 if (tree2.isNode(index2))
2085 if (bb2.overlaps(searchBox))
2087 const node& nod2 = tree2.nodes()[tree2.getNode(index2)];
2089 for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++)
2091 labelBits subIndex2 = nod2.subNodes_[i2];
2092 const treeBoundBox subBb2
2094 tree2.isNode(subIndex2)
2095 ? tree2.nodes()[tree2.getNode(subIndex2)].bb_
2114 else if (tree2.isContent(index2))
2116 // index2 is leaf, index1 not yet.
2117 for (direction i1 = 0; i1 < nod1.subNodes_.size(); i1++)
2119 labelBits subIndex1 = nod1.subNodes_[i1];
2120 const treeBoundBox subBb1
2122 tree1.isNode(subIndex1)
2123 ? tree1.nodes()[tree1.getNode(subIndex1)].bb_
2142 else if (tree1.isContent(index1))
2144 const treeBoundBox searchBox
2150 if (tree2.isNode(index2))
2153 tree2.nodes()[tree2.getNode(index2)];
2155 if (bb2.overlaps(searchBox))
2157 for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++)
2159 labelBits subIndex2 = nod2.subNodes_[i2];
2160 const treeBoundBox subBb2
2162 tree2.isNode(subIndex2)
2163 ? tree2.nodes()[tree2.getNode(subIndex2)].bb_
2182 else if (tree2.isContent(index2))
2184 // Both are leaves. Check n^2.
2186 const labelList& indices1 =
2187 tree1.contents()[tree1.getContent(index1)];
2188 const labelList& indices2 =
2189 tree2.contents()[tree2.getContent(index2)];
2193 label shape1 = indices1[i];
2197 label shape2 = indices2[j];
2199 if ((&tree1 != &tree2) || (shape1 != shape2))
2231 // Number of elements in node.
2232 template <class Type>
2233 Foam::label Foam::indexedOctree<Type>::countElements
2235 const labelBits index
2243 label nodeI = getNode(index);
2245 const node& nod = nodes_[nodeI];
2247 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2249 nElems += countElements(nod.subNodes_[octant]);
2252 else if (isContent(index))
2254 nElems += contents_[getContent(index)].size();
2265 template <class Type>
2266 void Foam::indexedOctree<Type>::writeOBJ
2269 const direction octant
2274 "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
2277 labelBits index = nodes_[nodeI].subNodes_[octant];
2283 subBb = nodes_[getNode(index)].bb_;
2285 else if (isContent(index) || isEmpty(index))
2287 subBb = nodes_[nodeI].bb_.subBbox(octant);
2290 Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
2291 << " to " << str.name() << endl;
2293 // Dump bounding box
2294 pointField bbPoints(subBb.points());
2298 const point& pt = bbPoints[i];
2300 str<< "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
2303 forAll(treeBoundBox::edges, i)
2305 const edge& e = treeBoundBox::edges[i];
2307 str<< "l " << e[0] + 1 << ' ' << e[1] + 1 << nl;
2312 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
2314 template <class Type>
2315 Foam::indexedOctree<Type>::indexedOctree(const Type& shapes)
2324 template <class Type>
2325 Foam::indexedOctree<Type>::indexedOctree
2328 const List<node>& nodes,
2329 const labelListList& contents
2334 contents_(contents),
2339 template <class Type>
2340 Foam::indexedOctree<Type>::indexedOctree
2343 const treeBoundBox& bb,
2344 const label maxLevels, // maximum number of levels
2345 const scalar maxLeafRatio,
2346 const scalar maxDuplicity
2356 Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2357 << " shapes:" << shapes.size() << nl
2358 << " bb:" << bb << nl
2362 if (shapes.size() == 0)
2367 // Start off with one node with all shapes in it.
2368 DynamicList<node> nodes(label(shapes.size() / maxLeafRatio));
2369 DynamicList<labelList> contents(label(shapes.size() / maxLeafRatio));
2370 contents.append(identity(shapes.size()));
2373 node topNode(divide(bb, contents, 0));
2374 nodes.append(topNode);
2377 // Now have all contents at level 1. Create levels by splitting levels
2382 for (; nLevels < maxLevels; nLevels++)
2384 // Count number of references into shapes (i.e. contents)
2388 nEntries += contents[i].size();
2393 Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2394 << " nLevels:" << nLevels << nl
2395 << " nEntries per treeLeaf:" << nEntries/contents.size()
2397 << " nEntries per shape (duplicity):"
2398 << nEntries/shapes.size()
2405 //nEntries < maxLeafRatio*contents.size()
2407 nEntries > maxDuplicity*shapes.size()
2414 // Split nodes with more than maxLeafRatio elements
2415 label nOldNodes = nodes.size();
2418 label(maxLeafRatio),
2423 if (nOldNodes == nodes.size())
2434 // Compact such that deeper level contents are always after the
2435 // ones for a shallower level. This way we can slice a coarser level
2437 contents_.setSize(contents.size());
2455 if (compactI == contents_.size())
2457 // Transferred all contents to contents_ (in order breadth first)
2463 nodes_.transfer(nodes);
2469 forAll(contents_, i)
2471 nEntries += contents_[i].size();
2474 Pout<< "indexedOctree<Type>::indexedOctree"
2475 << " : finished construction of tree of:" << shapes.typeName
2477 << " bb:" << this->bb() << nl
2478 << " shapes:" << shapes.size() << nl
2479 << " nLevels:" << nLevels << nl
2480 << " treeNodes:" << nodes_.size() << nl
2481 << " nEntries:" << nEntries << nl
2483 << scalar(nEntries)/contents.size() << nl
2484 << " per shape (duplicity):"
2485 << scalar(nEntries)/shapes.size() << nl
2491 template <class Type>
2492 Foam::indexedOctree<Type>::indexedOctree
2505 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2507 template <class Type>
2508 Foam::scalar& Foam::indexedOctree<Type>::perturbTol()
2514 template <class Type>
2515 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
2517 const point& sample,
2518 const scalar startDistSqr
2521 scalar nearestDistSqr = startDistSqr;
2522 label nearestShapeI = -1;
2523 point nearestPoint = vector::zero;
2538 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2542 template <class Type>
2543 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
2545 const linePointRef& ln,
2546 treeBoundBox& tightest,
2550 label nearestShapeI = -1;
2568 nearestPoint = vector::zero;
2571 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2575 // Find nearest intersection
2576 template <class Type>
2577 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
2583 return findLine(false, start, end);
2587 // Find nearest intersection
2588 template <class Type>
2589 Foam::pointIndexHit Foam::indexedOctree<Type>::findLineAny
2595 return findLine(true, start, end);
2599 template <class Type>
2600 Foam::labelList Foam::indexedOctree<Type>::findBox
2602 const treeBoundBox& searchBox
2605 // Storage for labels of shapes inside bb. Size estimate.
2606 labelHashSet elements(shapes_.size() / 100);
2610 findBox(0, searchBox, elements);
2613 return elements.toc();
2617 // Find node (as parent+octant) containing point
2618 template <class Type>
2619 Foam::labelBits Foam::indexedOctree<Type>::findNode
2627 // Empty tree. Return what?
2628 return nodePlusOctant(nodeI, 0);
2631 const node& nod = nodes_[nodeI];
2635 if (!nod.bb_.contains(sample))
2637 FatalErrorIn("findNode(..)")
2638 << "Cannot find " << sample << " in node " << nodeI
2639 << abort(FatalError);
2643 direction octant = nod.bb_.subOctant(sample);
2645 labelBits index = nod.subNodes_[octant];
2650 return findNode(getNode(index), sample);
2652 else if (isContent(index))
2654 // Content. Return treenode+octant
2655 return nodePlusOctant(nodeI, octant);
2659 // Empty. Return treenode+octant
2660 return nodePlusOctant(nodeI, octant);
2665 template <class Type>
2666 Foam::label Foam::indexedOctree<Type>::findInside(const point& sample) const
2668 labelBits index = findNode(0, sample);
2670 const node& nod = nodes_[getNode(index)];
2672 labelBits contentIndex = nod.subNodes_[getOctant(index)];
2674 // Need to check for the presence of content, in-case the node is empty
2675 if (isContent(contentIndex))
2677 labelList indices = contents_[getContent(contentIndex)];
2679 forAll(indices, elemI)
2681 label shapeI = indices[elemI];
2683 if (shapes_.contains(shapeI, sample))
2694 template <class Type>
2695 const Foam::labelList& Foam::indexedOctree<Type>::findIndices
2700 labelBits index = findNode(0, sample);
2702 const node& nod = nodes_[getNode(index)];
2704 labelBits contentIndex = nod.subNodes_[getOctant(index)];
2706 // Need to check for the presence of content, in-case the node is empty
2707 if (isContent(contentIndex))
2709 return contents_[getContent(contentIndex)];
2713 return emptyList<label>();
2718 // Determine type (inside/outside/mixed) per node.
2719 template <class Type>
2720 typename Foam::indexedOctree<Type>::volumeType
2721 Foam::indexedOctree<Type>::getVolumeType
2731 if (nodeTypes_.size() != 8*nodes_.size())
2733 // Calculate type for every octant of node.
2735 nodeTypes_.setSize(8*nodes_.size());
2736 nodeTypes_ = UNKNOWN;
2747 forAll(nodeTypes_, i)
2749 volumeType type = volumeType(nodeTypes_.get(i));
2751 if (type == UNKNOWN)
2755 else if (type == MIXED)
2759 else if (type == INSIDE)
2763 else if (type == OUTSIDE)
2769 FatalErrorIn("getVolumeType") << abort(FatalError);
2773 Pout<< "indexedOctree<Type>::getVolumeType : "
2775 << " nodes_:" << nodes_.size()
2776 << " nodeTypes_:" << nodeTypes_.size()
2777 << " nUNKNOWN:" << nUNKNOWN
2778 << " nMIXED:" << nMIXED
2779 << " nINSIDE:" << nINSIDE
2780 << " nOUTSIDE:" << nOUTSIDE
2785 return getVolumeType(0, sample);
2789 template <class Type>
2790 template <class CompareOp>
2791 void Foam::indexedOctree<Type>::findNear
2793 const scalar nearDist,
2794 const indexedOctree<Type>& tree2,
2803 nodePlusOctant(0, 0),
2806 nodePlusOctant(0, 0),
2813 // Print contents of nodeI
2814 template <class Type>
2815 void Foam::indexedOctree<Type>::print
2818 const bool printContents,
2822 const node& nod = nodes_[nodeI];
2823 const treeBoundBox& bb = nod.bb_;
2825 os << "nodeI:" << nodeI << " bb:" << bb << nl
2826 << "parent:" << nod.parent_ << nl
2827 << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
2829 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2831 const treeBoundBox subBb(bb.subBbox(octant));
2833 labelBits index = nod.subNodes_[octant];
2838 label subNodeI = getNode(index);
2840 os << "octant:" << octant
2841 << " node: n:" << countElements(index)
2842 << " bb:" << subBb << endl;
2844 string oldPrefix = os.prefix();
2845 os.prefix() = " " + oldPrefix;
2847 print(os, printContents, subNodeI);
2849 os.prefix() = oldPrefix;
2851 else if (isContent(index))
2853 const labelList& indices = contents_[getContent(index)];
2857 writeOBJ(nodeI, octant);
2860 os << "octant:" << octant
2861 << " content: n:" << indices.size()
2869 os << ' ' << indices[j];
2878 writeOBJ(nodeI, octant);
2881 os << "octant:" << octant << " empty:" << subBb << endl;
2887 // Print contents of nodeI
2888 template <class Type>
2889 bool Foam::indexedOctree<Type>::write(Ostream& os) const
2897 template <class Type>
2898 Foam::Ostream& Foam::operator<<(Ostream& os, const indexedOctree<Type>& t)
2901 os << t.bb() << token::SPACE << t.nodes()
2902 << token::SPACE << t.contents();
2906 // ************************************************************************* //