BUG: UListIO: byteSize overflowing on really big faceLists
[OpenFOAM-2.0.x.git] / src / OpenFOAM / algorithms / indexedOctree / indexedOctree.C
blob29b75ece0fe9b9c53c01d83c51f457decd2d757d
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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
19     for more details.
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"
28 #include "OFstream.H"
29 #include "ListOps.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 template <class Type>
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.
41 template <class Type>
42 bool Foam::indexedOctree<Type>::overlaps
44     const point& p0,
45     const point& p1,
46     const scalar nearestDistSqr,
47     const point& sample
50     // Find out where sample is in relation to bb.
51     // Find nearest point on bb.
52     scalar distSqr = 0;
54     for (direction dir = 0; dir < vector::nComponents; dir++)
55     {
56         scalar d0 = p0[dir] - sample[dir];
57         scalar d1 = p1[dir] - sample[dir];
59         if ((d0 > 0) != (d1 > 0))
60         {
61             // sample inside both extrema. This component does not add any
62             // distance.
63         }
64         else if (mag(d0) < mag(d1))
65         {
66             distSqr += d0*d0;
67         }
68         else
69         {
70             distSqr += d1*d1;
71         }
73         if (distSqr > nearestDistSqr)
74         {
75             return false;
76         }
77     }
79     return true;
83 // Does bb intersect a sphere around sample? Or is any corner point of bb
84 // closer than nearestDistSqr to sample.
85 template <class Type>
86 bool Foam::indexedOctree<Type>::overlaps
88     const treeBoundBox& parentBb,
89     const direction octant,
90     const scalar nearestDistSqr,
91     const point& sample
94     //- Accelerated version of
95     //     treeBoundBox subBb(parentBb.subBbox(mid, octant))
96     //     overlaps
97     //     (
98     //          subBb.min(),
99     //          subBb.max(),
100     //          nearestDistSqr,
101     //          sample
102     //     )
104     const point& min = parentBb.min();
105     const point& max = parentBb.max();
107     point other;
109     if (octant & treeBoundBox::RIGHTHALF)
110     {
111         other.x() = max.x();
112     }
113     else
114     {
115         other.x() = min.x();
116     }
118     if (octant & treeBoundBox::TOPHALF)
119     {
120         other.y() = max.y();
121     }
122     else
123     {
124         other.y() = min.y();
125     }
127     if (octant & treeBoundBox::FRONTHALF)
128     {
129         other.z() = max.z();
130     }
131     else
132     {
133         other.z() = min.z();
134     }
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
154 ) const
156     List<DynamicList<label> > subIndices(8);
157     for (direction octant = 0; octant < subIndices.size(); octant++)
158     {
159         subIndices[octant].setCapacity(indices.size()/8);
160     }
162     // Precalculate bounding boxes.
163     FixedList<treeBoundBox, 8> subBbs;
164     for (direction octant = 0; octant < subBbs.size(); octant++)
165     {
166         subBbs[octant] = bb.subBbox(octant);
167     }
169     forAll(indices, i)
170     {
171         label shapeI = indices[i];
173         for (direction octant = 0; octant < 8; octant++)
174         {
175             if (shapes_.overlaps(shapeI, subBbs[octant]))
176             {
177                 subIndices[octant].append(shapeI);
178             }
179         }
180     }
182     result.setSize(8);
183     for (direction octant = 0; octant < subIndices.size(); octant++)
184     {
185         result[octant].transfer(subIndices[octant]);
186     }
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,
197     const label contentI
198 ) const
200     const labelList& indices = contents[contentI];
202     node nod;
204     if
205     (
206         bb.min()[0] >= bb.max()[0]
207      || bb.min()[1] >= bb.max()[1]
208      || bb.min()[2] >= bb.max()[2]
209     )
210     {
211         FatalErrorIn("indexedOctree<Type>::divide(..)")
212             << "Badly formed bounding box:" << bb
213             << abort(FatalError);
214     }
216     nod.bb_ = bb;
217     nod.parent_ = -1;
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.
224     // Append the rest.
225     bool replaced = false;
227     for (direction octant = 0; octant < dividedIndices.size(); octant++)
228     {
229         labelList& subIndices = dividedIndices[octant];
231         if (subIndices.size())
232         {
233             if (!replaced)
234             {
235                 contents[contentI].transfer(subIndices);
236                 nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
237                 replaced = true;
238             }
239             else
240             {
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);
247             }
248         }
249         else
250         {
251             // Mark node as empty
252             nod.subNodes_[octant] = emptyPlusOctant(octant);
253         }
254     }
256     return nod;
260 // Split any contents node with more than minSize elements.
261 template <class Type>
262 void Foam::indexedOctree<Type>::splitNodes
264     const label minSize,
265     DynamicList<indexedOctree<Type>::node>& nodes,
266     DynamicList<labelList>& contents
267 ) const
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++)
275     {
276         for
277         (
278             direction octant = 0;
279             octant < nodes[nodeI].subNodes_.size();
280             octant++
281         )
282         {
283             labelBits index = nodes[nodeI].subNodes_[octant];
285             if (isNode(index))
286             {
287                 // tree node. Leave intact.
288             }
289             else if (isContent(index))
290             {
291                 label contentI = getContent(index);
293                 if (contents[contentI].size() > minSize)
294                 {
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);
306                 }
307             }
308         }
309     }
313 // Reorder contents to be in same order as nodes. Returns number of nodes on
314 // the compactLevel.
315 template <class Type>
316 Foam::label Foam::indexedOctree<Type>::compactContents
318     DynamicList<node>& nodes,
319     DynamicList<labelList>& contents,
320     const label compactLevel,
321     const label nodeI,
322     const label level,
324     List<labelList>& compactedContents,
325     label& compactI
328     const node& nod = nodes[nodeI];
330     label nNodes = 0;
332     if (level < compactLevel)
333     {
334         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
335         {
336             labelBits index = nod.subNodes_[octant];
338             if (isNode(index))
339             {
340                 nNodes += compactContents
341                 (
342                     nodes,
343                     contents,
344                     compactLevel,
345                     getNode(index),
346                     level+1,
347                     compactedContents,
348                     compactI
349                 );
350             }
351         }
352     }
353     else if (level == compactLevel)
354     {
355         // Compact all content on this level
356         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
357         {
358             labelBits index = nod.subNodes_[octant];
360             if (isContent(index))
361             {
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);
370                 compactI++;
371             }
372             else if (isNode(index))
373             {
374                 nNodes++;
375             }
376         }
377     }
378     return nNodes;
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
389     const label nodeI
390 ) const
392     const node& nod = nodes_[nodeI];
394     volumeType myType = UNKNOWN;
396     for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
397     {
398         volumeType subType;
400         labelBits index = nod.subNodes_[octant];
402         if (isNode(index))
403         {
404             // tree node. Recurse.
405             subType = calcVolumeType(getNode(index));
406         }
407         else if (isContent(index))
408         {
409             // Contents. Depending on position in box might be on either
410             // side.
411             subType = MIXED;
412         }
413         else
414         {
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);
419             subType = volumeType
420             (
421                 shapes_.getVolumeType(*this, subBb.midpoint())
422             );
423         }
425         // Store octant type
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)
431         {
432             myType = subType;
433         }
434         else if (subType != myType)
435         {
436             myType = MIXED;
437         }
438     }
439     return myType;
443 template <class Type>
444 typename Foam::indexedOctree<Type>::volumeType
445 Foam::indexedOctree<Type>::getVolumeType
447     const label nodeI,
448     const point& sample
449 ) const
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)
458     {
459         return octantType;
460     }
461     else if (octantType == OUTSIDE)
462     {
463         return octantType;
464     }
465     else if (octantType == UNKNOWN)
466     {
467         // Can happen for e.g. non-manifold surfaces.
468         return octantType;
469     }
470     else if (octantType == MIXED)
471     {
472         labelBits index = nod.subNodes_[octant];
474         if (isNode(index))
475         {
476             // Recurse
477             volumeType subType = getVolumeType(getNode(index), sample);
479             return subType;
480         }
481         else if (isContent(index))
482         {
483             // Content. Defer to shapes.
484             return volumeType(shapes_.getVolumeType(*this, sample));
485         }
486         else
487         {
488             // Empty node. Cannot have 'mixed' as its type since not divided
489             // up and has no items inside it.
490             FatalErrorIn
491             (
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);
499             return UNKNOWN;
500         }
501     }
502     else
503     {
504         FatalErrorIn
505         (
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);
514         return UNKNOWN;
515     }
519 template <class Type>
520 typename Foam::indexedOctree<Type>::volumeType
521 Foam::indexedOctree<Type>::getSide
523     const vector& outsideNormal,
524     const vector& vec
527     if ((outsideNormal&vec) >= 0)
528     {
529         return OUTSIDE;
530     }
531     else
532     {
533         return INSIDE;
534     }
539 // Query routines
540 // ~~~~~~~~~~~~~~
543 // Find nearest point starting from nodeI
544 template <class Type>
545 void Foam::indexedOctree<Type>::findNearest
547     const label nodeI,
548     const point& sample,
550     scalar& nearestDistSqr,
551     label& nearestShapeI,
552     point& nearestPoint
553 ) const
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++)
563     {
564         direction octant = octantOrder[i];
566         labelBits index = nod.subNodes_[octant];
568         if (isNode(index))
569         {
570             label subNodeI = getNode(index);
572             const treeBoundBox& subBb = nodes_[subNodeI].bb_;
574             if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
575             {
576                 findNearest
577                 (
578                     subNodeI,
579                     sample,
581                     nearestDistSqr,
582                     nearestShapeI,
583                     nearestPoint
584                 );
585             }
586         }
587         else if (isContent(index))
588         {
589             if
590             (
591                 overlaps
592                 (
593                     nod.bb_,
594                     octant,
595                     nearestDistSqr,
596                     sample
597                 )
598             )
599             {
600                 shapes_.findNearest
601                 (
602                     contents_[getContent(index)],
603                     sample,
605                     nearestDistSqr,
606                     nearestShapeI,
607                     nearestPoint
608                 );
609             }
610         }
611     }
615 // Find nearest point to line.
616 template <class Type>
617 void Foam::indexedOctree<Type>::findNearest
619     const label nodeI,
620     const linePointRef& ln,
622     treeBoundBox& tightest,
623     label& nearestShapeI,
624     point& linePoint,
625     point& nearestPoint
626 ) const
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++)
637     {
638         direction octant = octantOrder[i];
640         labelBits index = nod.subNodes_[octant];
642         if (isNode(index))
643         {
644             const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
646             if (subBb.overlaps(tightest))
647             {
648                 findNearest
649                 (
650                     getNode(index),
651                     ln,
653                     tightest,
654                     nearestShapeI,
655                     linePoint,
656                     nearestPoint
657                 );
658             }
659         }
660         else if (isContent(index))
661         {
662             const treeBoundBox subBb(nodeBb.subBbox(octant));
664             if (subBb.overlaps(tightest))
665             {
666                 shapes_.findNearest
667                 (
668                     contents_[getContent(index)],
669                     ln,
671                     tightest,
672                     nearestShapeI,
673                     linePoint,
674                     nearestPoint
675                 );
676             }
677         }
678     }
682 template <class Type>
683 Foam::treeBoundBox Foam::indexedOctree<Type>::subBbox
685     const label parentNodeI,
686     const direction octant
687 ) const
689     // Get type of node at octant
690     const node& nod = nodes_[parentNodeI];
691     labelBits index = nod.subNodes_[octant];
693     if (isNode(index))
694     {
695         // Use stored bb
696         return nodes_[getNode(index)].bb_;
697     }
698     else
699     {
700         // Calculate subBb
701         return nod.bb_.subBbox(octant);
702     }
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,
712     const point& pt,
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.
724     if (pushInside)
725     {
726         for (direction dir = 0; dir < vector::nComponents; dir++)
727         {
728             if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
729             {
730                 // Close to 'left' side. Push well beyond left side.
731                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
732                 perturbedPt[dir] = bb.min()[dir] + perturbDist;
733             }
734             else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
735             {
736                 // Close to 'right' side. Push well beyond right side.
737                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
738                 perturbedPt[dir] = bb.max()[dir] - perturbDist;
739             }
740         }
741     }
742     else
743     {
744         for (direction dir = 0; dir < vector::nComponents; dir++)
745         {
746             if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
747             {
748                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
749                 perturbedPt[dir] = bb.min()[dir] - perturbDist;
750             }
751             else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
752             {
753                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
754                 perturbedPt[dir] = bb.max()[dir] + perturbDist;
755             }
756         }
757     }
759     if (debug)
760     {
761         if (pushInside != bb.contains(perturbedPt))
762         {
763             FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
764                 << "pushed point:" << pt
765                 << " to:" << perturbedPt
766                 << " wanted side:" << pushInside
767                 << " obtained side:" << bb.contains(perturbedPt)
768                 << " of bb:" << bb
769                 << abort(FatalError);
770         }
771     }
773     return perturbedPt;
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,
784     const point& pt,
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.
796     if (faceID == 0)
797     {
798         FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
799             << abort(FatalError);
800     }
802     if (faceID & treeBoundBox::LEFTBIT)
803     {
804         if (pushInside)
805         {
806             perturbedPt[0] = bb.min()[0] + (perturbVec[0] + ROOTVSMALL);
807         }
808         else
809         {
810             perturbedPt[0] = bb.min()[0] - (perturbVec[0] + ROOTVSMALL);
811         }
812     }
813     else if (faceID & treeBoundBox::RIGHTBIT)
814     {
815         if (pushInside)
816         {
817             perturbedPt[0] = bb.max()[0] - (perturbVec[0] + ROOTVSMALL);
818         }
819         else
820         {
821             perturbedPt[0] = bb.max()[0] + (perturbVec[0] + ROOTVSMALL);
822         }
823     }
825     if (faceID & treeBoundBox::BOTTOMBIT)
826     {
827         if (pushInside)
828         {
829             perturbedPt[1] = bb.min()[1] + (perturbVec[1] + ROOTVSMALL);
830         }
831         else
832         {
833             perturbedPt[1] = bb.min()[1] - (perturbVec[1] + ROOTVSMALL);
834         }
835     }
836     else if (faceID & treeBoundBox::TOPBIT)
837     {
838         if (pushInside)
839         {
840             perturbedPt[1] = bb.max()[1] - (perturbVec[1] + ROOTVSMALL);
841         }
842         else
843         {
844             perturbedPt[1] = bb.max()[1] + (perturbVec[1] + ROOTVSMALL);
845         }
846     }
848     if (faceID & treeBoundBox::BACKBIT)
849     {
850         if (pushInside)
851         {
852             perturbedPt[2] = bb.min()[2] + (perturbVec[2] + ROOTVSMALL);
853         }
854         else
855         {
856             perturbedPt[2] = bb.min()[2] - (perturbVec[2] + ROOTVSMALL);
857         }
858     }
859     else if (faceID & treeBoundBox::FRONTBIT)
860     {
861         if (pushInside)
862         {
863             perturbedPt[2] = bb.max()[2] - (perturbVec[2] + ROOTVSMALL);
864         }
865         else
866         {
867             perturbedPt[2] = bb.max()[2] + (perturbVec[2] + ROOTVSMALL);
868         }
869     }
871     if (debug)
872     {
873         if (pushInside != bb.contains(perturbedPt))
874         {
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)
880                 << " of bb:" << bb
881                 << abort(FatalError);
882         }
883     }
885     return perturbedPt;
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
897     const point& pt
900     if (debug)
901     {
902         if (bb.posBits(pt) != 0)
903         {
904             FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
905                 << " bb:" << bb << endl
906                 << "does not contain point " << pt << abort(FatalError);
907         }
908     }
911     // Handle two cases:
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)
921     {
922         faceIndices[nFaces++] = treeBoundBox::LEFT;
923     }
924     else if (ptFaceID & treeBoundBox::RIGHTBIT)
925     {
926         faceIndices[nFaces++] = treeBoundBox::RIGHT;
927     }
929     if (ptFaceID & treeBoundBox::BOTTOMBIT)
930     {
931         faceIndices[nFaces++] = treeBoundBox::BOTTOM;
932     }
933     else if (ptFaceID & treeBoundBox::TOPBIT)
934     {
935         faceIndices[nFaces++] = treeBoundBox::TOP;
936     }
938     if (ptFaceID & treeBoundBox::BACKBIT)
939     {
940         faceIndices[nFaces++] = treeBoundBox::BACK;
941     }
942     else if (ptFaceID & treeBoundBox::FRONTBIT)
943     {
944         faceIndices[nFaces++] = treeBoundBox::FRONT;
945     }
948     // Determine the face we want to keep the point on
950     direction keepFaceID;
952     if (nFaces == 0)
953     {
954         // Return original point
955         return pt;
956     }
957     else if (nFaces == 1)
958     {
959         // Point is on a single face
960         keepFaceID = faceIndices[0];
961     }
962     else
963     {
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++)
971         {
972             direction face = faceIndices[i];
973             scalar s = mag(treeBoundBox::faceNormals[face] & dir);
974             if (s > maxInproduct)
975             {
976                 maxInproduct = s;
977                 keepFaceID = face;
978             }
979         }
980     }
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)
991     {
992         facePoint.x() = bb.min().x();
993         faceID = treeBoundBox::LEFTBIT;
994     }
995     else if (keepFaceID == treeBoundBox::RIGHT)
996     {
997         facePoint.x() = bb.max().x();
998         faceID = treeBoundBox::RIGHTBIT;
999     }
1000     else if (keepFaceID == treeBoundBox::BOTTOM)
1001     {
1002         facePoint.y() = bb.min().y();
1003         faceID = treeBoundBox::BOTTOMBIT;
1004     }
1005     else if (keepFaceID == treeBoundBox::TOP)
1006     {
1007         facePoint.y() = bb.max().y();
1008         faceID = treeBoundBox::TOPBIT;
1009     }
1010     else if (keepFaceID == treeBoundBox::BACK)
1011     {
1012         facePoint.z() = bb.min().z();
1013         faceID = treeBoundBox::BACKBIT;
1014     }
1015     else if (keepFaceID == treeBoundBox::FRONT)
1016     {
1017         facePoint.z() = bb.max().z();
1018         faceID = treeBoundBox::FRONTBIT;
1019     }
1022     if (debug)
1023     {
1024         if (faceID != bb.faceBits(facePoint))
1025         {
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);
1034         }
1035         if (bb.posBits(facePoint) != 0)
1036         {
1037             FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
1038                 << " bb:" << bb << endl
1039                 << "does not contain perturbed point "
1040                 << facePoint << abort(FatalError);
1041         }
1042     }
1045     return facePoint;
1049 //// Takes a bb and a point on the outside of the bb. Checks if on multiple
1050 // 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.
1062 //    if
1063 //    (
1064 //        (faceID == 0)
1065 //     || (faceID == treeBoundBox::LEFTBIT)
1066 //     || (faceID == treeBoundBox::RIGHTBIT)
1067 //     || (faceID == treeBoundBox::BOTTOMBIT)
1068 //     || (faceID == treeBoundBox::TOPBIT)
1069 //     || (faceID == treeBoundBox::BACKBIT)
1070 //     || (faceID == treeBoundBox::FRONTBIT)
1071 //    )
1072 //    {
1073 //        return;
1074 //    }
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)
1083 //    {
1084 //        inproducts[treeBoundBox::LEFT] = mag
1085 //        (
1086 //            treeBoundBox::faceNormals[treeBoundBox::LEFT]
1087 //          & dir
1088 //        );
1089 //        nFaces++;
1090 //    }
1091 //    if (faceID & treeBoundBox::RIGHTBIT)
1092 //    {
1093 //        inproducts[treeBoundBox::RIGHT] = mag
1094 //        (
1095 //            treeBoundBox::faceNormals[treeBoundBox::RIGHT]
1096 //          & dir
1097 //        );
1098 //        nFaces++;
1099 //    }
1101 //    if (faceID & treeBoundBox::BOTTOMBIT)
1102 //    {
1103 //        inproducts[treeBoundBox::BOTTOM] = mag
1104 //        (
1105 //            treeBoundBox::faceNormals[treeBoundBox::BOTTOM]
1106 //          & dir
1107 //        );
1108 //        nFaces++;
1109 //    }
1110 //    if (faceID & treeBoundBox::TOPBIT)
1111 //    {
1112 //        inproducts[treeBoundBox::TOP] = mag
1113 //        (
1114 //            treeBoundBox::faceNormals[treeBoundBox::TOP]
1115 //          & dir
1116 //        );
1117 //        nFaces++;
1118 //    }
1120 //    if (faceID & treeBoundBox::BACKBIT)
1121 //    {
1122 //        inproducts[treeBoundBox::BACK] = mag
1123 //        (
1124 //            treeBoundBox::faceNormals[treeBoundBox::BACK]
1125 //          & dir
1126 //        );
1127 //        nFaces++;
1128 //    }
1129 //    if (faceID & treeBoundBox::FRONTBIT)
1130 //    {
1131 //        inproducts[treeBoundBox::FRONT] = mag
1132 //        (
1133 //            treeBoundBox::faceNormals[treeBoundBox::FRONT]
1134 //          & dir
1135 //        );
1136 //        nFaces++;
1137 //    }
1139 //    if (nFaces == 0 || nFaces == 1 || nFaces > 3)
1140 //    {
1141 //        FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)")
1142 //            << "Problem : nFaces:" << nFaces << abort(FatalError);
1143 //    }
1145 //    // Keep point on most perpendicular face; shift it away from the aligned
1146 //    // ones.
1147 //    // E.g. line hits top and left face:
1148 //    //     a
1149 //    // ----+----+
1150 //    //     |    |
1151 //    //     |    |
1152 //    //     +----+
1153 //    // Shift point down (away from top):
1154 //    //
1155 //    //    a+----+
1156 //    // ----|    |
1157 //    //     |    |
1158 //    //     +----+
1160 //    label maxIndex = -1;
1161 //    scalar maxInproduct = -GREAT;
1163 //    for (direction i = 0; i < 6; i++)
1164 //    {
1165 //        if (inproducts[i] > maxInproduct)
1166 //        {
1167 //            maxInproduct = inproducts[i];
1168 //            maxIndex = i;
1169 //        }
1170 //    }
1172 //    if (maxIndex == -1)
1173 //    {
1174 //        FatalErrorIn("indexedOctree<Type>::checkMultipleFaces(..)")
1175 //            << "Problem maxIndex:" << maxIndex << " inproducts:" << inproducts
1176 //            << abort(FatalError);
1177 //    }
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)
1189 //    {
1190 //        faceHitInfo.rawPoint().x() = bb.min().x();
1191 //        faceID = treeBoundBox::LEFTBIT;
1192 //    }
1193 //    else if (maxIndex == treeBoundBox::RIGHT)
1194 //    {
1195 //        faceHitInfo.rawPoint().x() = bb.max().x();
1196 //        faceID = treeBoundBox::RIGHTBIT;
1197 //    }
1198 //    else if (maxIndex == treeBoundBox::BOTTOM)
1199 //    {
1200 //        faceHitInfo.rawPoint().y() = bb.min().y();
1201 //        faceID = treeBoundBox::BOTTOMBIT;
1202 //    }
1203 //    else if (maxIndex == treeBoundBox::TOP)
1204 //    {
1205 //        faceHitInfo.rawPoint().y() = bb.max().y();
1206 //        faceID = treeBoundBox::TOPBIT;
1207 //    }
1208 //    else if (maxIndex == treeBoundBox::BACK)
1209 //    {
1210 //        faceHitInfo.rawPoint().z() = bb.min().z();
1211 //        faceID = treeBoundBox::BACKBIT;
1212 //    }
1213 //    else if (maxIndex == treeBoundBox::FRONT)
1214 //    {
1215 //        faceHitInfo.rawPoint().z() = bb.max().z();
1216 //        faceID = treeBoundBox::FRONTBIT;
1217 //    }
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)
1227 //        << endl;
1230 //    if (debug)
1231 //    {
1232 //        if (faceID != bb.faceBits(faceHitInfo.rawPoint()))
1233 //        {
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);
1242 //        }
1243 //    }
1247 // Get parent node and octant. Return false if top of tree reached.
1248 template <class Type>
1249 bool Foam::indexedOctree<Type>::walkToParent
1251     const label nodeI,
1252     const direction octant,
1254     label& parentNodeI,
1255     label& parentOctant
1256 ) const
1258     parentNodeI = nodes_[nodeI].parent_;
1260     if (parentNodeI == -1)
1261     {
1262         // Reached edge of tree
1263         return false;
1264     }
1266     const node& parentNode = nodes_[parentNodeI];
1268     // Find octant nodeI is in.
1269     parentOctant = 255;
1271     for (direction i = 0; i < parentNode.subNodes_.size(); i++)
1272     {
1273         labelBits index = parentNode.subNodes_[i];
1275         if (isNode(index) && getNode(index) == nodeI)
1276         {
1277             parentOctant = i;
1278             break;
1279         }
1280     }
1282     if (parentOctant == 255)
1283     {
1284         FatalErrorIn("walkToParent(..)")
1285             << "Problem: no parent found for octant:" << octant
1286             << " node:" << nodeI
1287             << abort(FatalError);
1288     }
1290     return true;
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
1303     label& nodeI,
1304     direction& octant
1305 ) const
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
1312     // on the right.
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)
1323     {
1324         // We want to go left so check if in right octant (i.e. x-bit is set)
1325         octantMask |= X;
1326         wantedValue |= X;
1327     }
1328     else if ((faceID & treeBoundBox::RIGHTBIT) != 0)
1329     {
1330         octantMask |= X;  // wantedValue already 0
1331     }
1333     if ((faceID & treeBoundBox::BOTTOMBIT) != 0)
1334     {
1335         // Want to go down so check for y-bit set.
1336         octantMask |= Y;
1337         wantedValue |= Y;
1338     }
1339     else if ((faceID & treeBoundBox::TOPBIT) != 0)
1340     {
1341         // Want to go up so check for y-bit not set.
1342         octantMask |= Y;
1343     }
1345     if ((faceID & treeBoundBox::BACKBIT) != 0)
1346     {
1347         octantMask |= Z;
1348         wantedValue |= Z;
1349     }
1350     else if ((faceID & treeBoundBox::FRONTBIT) != 0)
1351     {
1352         octantMask |= Z;
1353     }
1355     // So now we have the coordinate directions in the octant we need to check
1356     // and the resulting value.
1358     /*
1359     // +---+---+
1360     // |   |   |
1361     // |   |   |
1362     // |   |   |
1363     // +---+-+-+
1364     // |   | | |
1365     // |  a+-+-+
1366     // |   |\| |
1367     // +---+-+-+
1368     //        \
1369     //
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
1377     */
1379     //Pout<< "For point " << facePoint << endl;
1381     // Go up until we have chance to cross to the wanted direction
1382     while (wantedValue != (octant & octantMask))
1383     {
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
1389         {
1390             // Looking for right octant.
1391             if (octant & X)
1392             {
1393                 // My octant is one of the left ones so punch out the x check
1394                 octantMask &= ~X;
1395                 wantedValue &= ~X;
1396             }
1397         }
1398         else
1399         {
1400             if (!(octant & X))
1401             {
1402                 // My octant is right but I want to go left.
1403                 octantMask &= ~X;
1404                 wantedValue &= ~X;
1405             }
1406         }
1408         if (wantedValue & Y)
1409         {
1410             if (octant & Y)
1411             {
1412                 octantMask &= ~Y;
1413                 wantedValue &= ~Y;
1414             }
1415         }
1416         else
1417         {
1418             if (!(octant & Y))
1419             {
1420                 octantMask &= ~Y;
1421                 wantedValue &= ~Y;
1422             }
1423         }
1425         if (wantedValue & Z)
1426         {
1427             if (octant & Z)
1428             {
1429                 octantMask &= ~Z;
1430                 wantedValue &= ~Z;
1431             }
1432         }
1433         else
1434         {
1435             if (!(octant & Z))
1436             {
1437                 octantMask &= ~Z;
1438                 wantedValue &= ~Z;
1439             }
1440         }
1443         label parentNodeI;
1444         label parentOctant;
1445         walkToParent(nodeI, octant, parentNodeI, parentOctant);
1447         if (parentNodeI == -1)
1448         {
1449             // Reached edge of tree
1450             return false;
1451         }
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)
1457         //    << endl;
1458         //
1459         //Pout<< "    octantMask:" << octantMask
1460         //    << " wantedValue:" << wantedValue << endl;
1462         nodeI = parentNodeI;
1463         octant = parentOctant;
1464     }
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;
1475     if (debug)
1476     {
1477         const treeBoundBox subBb(subBbox(nodeI, octant));
1479         if (!subBb.contains(facePoint))
1480         {
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);
1487         }
1488     }
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];
1495     if (isNode(index))
1496     {
1497         labelBits node = findNode(getNode(index), facePoint);
1499         nodeI = getNode(node);
1500         octant = getOctant(node);
1501     }
1504     if (debug)
1505     {
1506         const treeBoundBox subBb(subBbox(nodeI, octant));
1508         if (nodeI == oldNodeI && octant == oldOctant)
1509         {
1510             FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
1511                 << "Did not go to neighbour when searching for " << facePoint
1512                 << endl
1513                 << "    starting from face:" << faceString(faceID)
1514                 << " node:" << nodeI
1515                 << " octant:" << octant
1516                 << " bb:" << subBb
1517                 << abort(FatalError);
1518         }
1520         if (!subBb.contains(facePoint))
1521         {
1522             FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
1523                 << "When searching for " << facePoint
1524                 << " ended up in node:" << nodeI
1525                 << " octant:" << octant
1526                 << " bb:" << subBb
1527                 << abort(FatalError);
1528         }
1529     }
1532     return true;
1536 template <class Type>
1537 Foam::word Foam::indexedOctree<Type>::faceString
1539     const direction faceID
1542     word desc;
1544     if (faceID == 0)
1545     {
1546         desc = "noFace";
1547     }
1548     if (faceID & treeBoundBox::LEFTBIT)
1549     {
1550         if (!desc.empty()) desc += "+";
1551         desc += "left";
1552     }
1553     if (faceID & treeBoundBox::RIGHTBIT)
1554     {
1555         if (!desc.empty()) desc += "+";
1556         desc += "right";
1557     }
1558     if (faceID & treeBoundBox::BOTTOMBIT)
1559     {
1560         if (!desc.empty()) desc += "+";
1561         desc += "bottom";
1562     }
1563     if (faceID & treeBoundBox::TOPBIT)
1564     {
1565         if (!desc.empty()) desc += "+";
1566         desc += "top";
1567     }
1568     if (faceID & treeBoundBox::BACKBIT)
1569     {
1570         if (!desc.empty()) desc += "+";
1571         desc += "back";
1572     }
1573     if (faceID & treeBoundBox::FRONTBIT)
1574     {
1575         if (!desc.empty()) desc += "+";
1576         desc += "front";
1577     }
1578     return 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
1591     const bool findAny,
1592     const point& treeStart,
1593     const vector& treeVec,
1595     const point& start,
1596     const point& end,
1597     const label nodeI,
1598     const direction octant,
1600     pointIndexHit& hitInfo,
1601     direction& hitBits
1602 ) const
1604     if (debug)
1605     {
1606         const treeBoundBox octantBb(subBbox(nodeI, octant));
1608         if (octantBb.posBits(start) != 0)
1609         {
1610             FatalErrorIn("indexedOctree<Type>::traverseNode(..)")
1611                 << "Node:" << nodeI << " octant:" << octant
1612                 << " bb:" << octantBb << endl
1613                 << "does not contain point " << start << abort(FatalError);
1614         }
1615     }
1618     const node& nod = nodes_[nodeI];
1620     labelBits index = nod.subNodes_[octant];
1622     if (isContent(index))
1623     {
1624         const labelList& indices = contents_[getContent(index)];
1626         if (indices.size())
1627         {
1628             if (findAny)
1629             {
1630                 // Find any intersection
1632                 forAll(indices, elemI)
1633                 {
1634                     label shapeI = indices[elemI];
1636                     point pt;
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.
1641                     if (hit)
1642                     {
1643                         // Hit so pt is nearer than nearestPoint.
1644                         // Update hit info
1645                         hitInfo.setHit();
1646                         hitInfo.setIndex(shapeI);
1647                         hitInfo.setPoint(pt);
1648                         return;
1649                     }
1650                 }
1651             }
1652             else
1653             {
1654                 // Find nearest intersection
1656                 const treeBoundBox octantBb(subBbox(nodeI, octant));
1658                 point nearestPoint(end);
1660                 forAll(indices, elemI)
1661                 {
1662                     label shapeI = indices[elemI];
1664                     point pt;
1665                     bool hit = shapes_.intersects
1666                     (
1667                         shapeI,
1668                         start,
1669                         nearestPoint,
1670                         pt
1671                     );
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))
1679                     {
1680                         // Hit so pt is nearer than nearestPoint.
1681                         nearestPoint = pt;
1682                         // Update hit info
1683                         hitInfo.setHit();
1684                         hitInfo.setIndex(shapeI);
1685                         hitInfo.setPoint(pt);
1686                     }
1687                 }
1689                 if (hitInfo.hit())
1690                 {
1691                     // Found intersected shape.
1692                     return;
1693                 }
1694             }
1695         }
1696     }
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));
1705     point pt;
1706     bool intersected = octantBb.intersects
1707     (
1708         end,            //treeStart,
1709         (start-end),    //treeVec,
1711         end,
1712         start,
1714         pt,
1715         hitBits
1716     );
1719     if (intersected)
1720     {
1721         // Return miss. Set misspoint to face.
1722         hitInfo.setPoint(pt);
1723     }
1724     else
1725     {
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
1729         // of bounding box)
1731         point perturbedEnd(pushPoint(octantBb, end, false));
1733         traverseNode
1734         (
1735             findAny,
1736             treeStart,
1737             treeVec,
1738             start,
1739             perturbedEnd,
1740             nodeI,
1741             octant,
1743             hitInfo,
1744             hitBits
1745         );
1746     }
1750 // Find first intersection
1751 template <class Type>
1752 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1754     const bool findAny,
1755     const point& treeStart,
1756     const point& treeEnd,
1757     const label startNodeI,
1758     const direction startOctant,
1759     const bool verbose
1760 ) const
1762     const vector treeVec(treeEnd - treeStart);
1764     // Current node as parent+octant
1765     label nodeI = startNodeI;
1766     direction octant = startOctant;
1768     if (verbose)
1769     {
1770         Pout<< "findLine : treeStart:" << treeStart
1771             << " treeEnd:" << treeEnd << endl
1772             << "node:" << nodeI
1773             << " octant:" << octant
1774             << " bb:" << subBbox(nodeI, octant) << endl;
1775     }
1777     // Current position. Initialize to miss
1778     pointIndexHit hitInfo(false, treeStart, -1);
1780     //while (true)
1781     label i = 0;
1782     for (; i < 100000; i++)
1783     {
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
1790         point startPoint
1791         (
1792             pushPointIntoFace
1793             (
1794                 octantBb,
1795                 treeVec,
1796                 hitInfo.rawPoint()
1797             )
1798         );
1800         if (verbose)
1801         {
1802             Pout<< "iter:" << i
1803                 << " at current:" << hitInfo.rawPoint()
1804                 << " (perturbed:" << startPoint << ")" << endl
1805                 << "    node:" << nodeI
1806                 << " octant:" << octant
1807                 << " bb:" << subBbox(nodeI, octant) << endl;
1808         }
1813         // Faces of current bounding box current point is on
1814         direction hitFaceID = 0;
1816         traverseNode
1817         (
1818             findAny,
1819             treeStart,
1820             treeVec,
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
1825             nodeI,
1826             octant,
1828             hitInfo,
1829             hitFaceID
1830         );
1832         // Did we hit a triangle?
1833         if (hitInfo.hit())
1834         {
1835             break;
1836         }
1838         if (hitFaceID == 0 || hitInfo.rawPoint() == treeEnd)
1839         {
1840             // endpoint inside the tree. Return miss.
1841             break;
1842         }
1844         // Create a point on other side of face.
1845         point perturbedPoint
1846         (
1847             pushPoint
1848             (
1849                 octantBb,
1850                 hitFaceID,
1851                 hitInfo.rawPoint(),
1852                 false                   // push outside of octantBb
1853             )
1854         );
1856         if (verbose)
1857         {
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
1865                 << endl;
1866         }
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
1871         // point.
1873         bool ok = walkToNeighbour
1874         (
1875             perturbedPoint,
1876             hitFaceID,  // face(s) that hitInfo is on
1878             nodeI,
1879             octant
1880         );
1882         if (!ok)
1883         {
1884             // Hit the edge of the tree. Return miss.
1885             break;
1886         }
1888         if (verbose)
1889         {
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
1896                 << endl;
1897         }
1898     }
1900     if (i == 100000)
1901     {
1902         // Probably in loop.
1903         if (!verbose)
1904         {
1905             // Redo intersection but now with verbose flag switched on.
1906             return findLine
1907             (
1908                 findAny,
1909                 treeStart,
1910                 treeEnd,
1911                 startNodeI,
1912                 startOctant,
1913                 true            //verbose
1914             );
1915         }
1916         if (debug)
1917         {
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);
1923         }
1924         else
1925         {
1926             WarningIn("indexedOctree<Type>::findLine(..)")
1927                 << "Got stuck in loop raytracing from:" << treeStart
1928                 << " to:" << treeEnd << endl
1929                 << "inside top box:" << subBbox(startNodeI, startOctant)
1930                 << endl;
1931         }
1932     }
1934     return hitInfo;
1938 // Find first intersection
1939 template <class Type>
1940 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1942     const bool findAny,
1943     const point& start,
1944     const point& end
1945 ) const
1947     pointIndexHit hitInfo;
1949     if (nodes_.size())
1950     {
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)
1960         {
1961             // Both start and end outside domain and in same block.
1962             return pointIndexHit(false, vector::zero, -1);
1963         }
1966         // Trim segment to treeBb
1968         point trackStart(start);
1969         point trackEnd(end);
1971         if (startBit != 0)
1972         {
1973             // Track start to inside domain.
1974             if (!treeBb.intersects(start, end, trackStart))
1975             {
1976                 return pointIndexHit(false, vector::zero, -1);
1977             }
1978         }
1980         if (endBit != 0)
1981         {
1982             // Track end to inside domain.
1983             if (!treeBb.intersects(end, trackStart, trackEnd))
1984             {
1985                 return pointIndexHit(false, vector::zero, -1);
1986             }
1987         }
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);
1996         hitInfo = findLine
1997         (
1998             findAny,
1999             trackStart,
2000             trackEnd,
2001             parentNodeI,
2002             octant
2003         );
2004     }
2006     return hitInfo;
2010 template <class Type>
2011 void Foam::indexedOctree<Type>::findBox
2013     const label nodeI,
2014     const treeBoundBox& searchBox,
2015     labelHashSet& elements
2016 ) const
2018     const node& nod = nodes_[nodeI];
2019     const treeBoundBox& nodeBb = nod.bb_;
2021     for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2022     {
2023         labelBits index = nod.subNodes_[octant];
2025         if (isNode(index))
2026         {
2027             const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
2029             if (subBb.overlaps(searchBox))
2030             {
2031                 findBox(getNode(index), searchBox, elements);
2032             }
2033         }
2034         else if (isContent(index))
2035         {
2036             const treeBoundBox subBb(nodeBb.subBbox(octant));
2038             if (subBb.overlaps(searchBox))
2039             {
2040                 const labelList& indices = contents_[getContent(index)];
2042                 forAll(indices, i)
2043                 {
2044                     label shapeI = indices[i];
2046                     if (shapes_.overlaps(shapeI, searchBox))
2047                     {
2048                         elements.insert(shapeI);
2049                     }
2050                 }
2051             }
2052         }
2053     }
2057 template <class Type>
2058 template <class CompareOp>
2059 void Foam::indexedOctree<Type>::findNear
2061     const scalar nearDist,
2062     const bool okOrder,
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,
2069     CompareOp& cop
2072     const vector nearSpan(nearDist, nearDist, nearDist);
2074     if (tree1.isNode(index1))
2075     {
2076         const node& nod1 = tree1.nodes()[tree1.getNode(index1)];
2077         const treeBoundBox searchBox
2078         (
2079             bb1.min()-nearSpan,
2080             bb1.max()+nearSpan
2081         );
2083         if (tree2.isNode(index2))
2084         {
2085             if (bb2.overlaps(searchBox))
2086             {
2087                 const node& nod2 = tree2.nodes()[tree2.getNode(index2)];
2089                 for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++)
2090                 {
2091                     labelBits subIndex2 = nod2.subNodes_[i2];
2092                     const treeBoundBox subBb2
2093                     (
2094                         tree2.isNode(subIndex2)
2095                       ? tree2.nodes()[tree2.getNode(subIndex2)].bb_
2096                       : bb2.subBbox(i2)
2097                     );
2099                     findNear
2100                     (
2101                         nearDist,
2102                         !okOrder,
2103                         tree2,
2104                         subIndex2,
2105                         subBb2,
2106                         tree1,
2107                         index1,
2108                         bb1,
2109                         cop
2110                     );
2111                 }
2112             }
2113         }
2114         else if (tree2.isContent(index2))
2115         {
2116             // index2 is leaf, index1 not yet.
2117             for (direction i1 = 0; i1 < nod1.subNodes_.size(); i1++)
2118             {
2119                 labelBits subIndex1 = nod1.subNodes_[i1];
2120                 const treeBoundBox subBb1
2121                 (
2122                     tree1.isNode(subIndex1)
2123                   ? tree1.nodes()[tree1.getNode(subIndex1)].bb_
2124                   : bb1.subBbox(i1)
2125                 );
2127                 findNear
2128                 (
2129                     nearDist,
2130                     !okOrder,
2131                     tree2,
2132                     index2,
2133                     bb2,
2134                     tree1,
2135                     subIndex1,
2136                     subBb1,
2137                     cop
2138                 );
2139             }
2140         }
2141     }
2142     else if (tree1.isContent(index1))
2143     {
2144         const treeBoundBox searchBox
2145         (
2146             bb1.min()-nearSpan,
2147             bb1.max()+nearSpan
2148         );
2150         if (tree2.isNode(index2))
2151         {
2152             const node& nod2 =
2153                 tree2.nodes()[tree2.getNode(index2)];
2155             if (bb2.overlaps(searchBox))
2156             {
2157                 for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++)
2158                 {
2159                     labelBits subIndex2 = nod2.subNodes_[i2];
2160                     const treeBoundBox subBb2
2161                     (
2162                         tree2.isNode(subIndex2)
2163                       ? tree2.nodes()[tree2.getNode(subIndex2)].bb_
2164                       : bb2.subBbox(i2)
2165                     );
2167                     findNear
2168                     (
2169                         nearDist,
2170                         !okOrder,
2171                         tree2,
2172                         subIndex2,
2173                         subBb2,
2174                         tree1,
2175                         index1,
2176                         bb1,
2177                         cop
2178                     );
2179                 }
2180             }
2181         }
2182         else if (tree2.isContent(index2))
2183         {
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)];
2191             forAll(indices1, i)
2192             {
2193                 label shape1 = indices1[i];
2195                 forAll(indices2, j)
2196                 {
2197                     label shape2 = indices2[j];
2199                     if ((&tree1 != &tree2) || (shape1 != shape2))
2200                     {
2201                         if (okOrder)
2202                         {
2203                             cop
2204                             (
2205                                 nearDist,
2206                                 tree1.shapes(),
2207                                 shape1,
2208                                 tree2.shapes(),
2209                                 shape2
2210                             );
2211                         }
2212                         else
2213                         {
2214                             cop
2215                             (
2216                                 nearDist,
2217                                 tree2.shapes(),
2218                                 shape2,
2219                                 tree1.shapes(),
2220                                 shape1
2221                             );
2222                         }
2223                     }
2224                 }
2225             }
2226         }
2227     }
2231 // Number of elements in node.
2232 template <class Type>
2233 Foam::label Foam::indexedOctree<Type>::countElements
2235     const labelBits index
2236 ) const
2238     label nElems = 0;
2240     if (isNode(index))
2241     {
2242         // tree node.
2243         label nodeI = getNode(index);
2245         const node& nod = nodes_[nodeI];
2247         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2248         {
2249             nElems += countElements(nod.subNodes_[octant]);
2250         }
2251     }
2252     else if (isContent(index))
2253     {
2254         nElems += contents_[getContent(index)].size();
2255     }
2256     else
2257     {
2258         // empty node
2259     }
2261     return nElems;
2265 template <class Type>
2266 void Foam::indexedOctree<Type>::writeOBJ
2268     const label nodeI,
2269     const direction octant
2270 ) const
2272     OFstream str
2273     (
2274         "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
2275     );
2277     labelBits index = nodes_[nodeI].subNodes_[octant];
2279     treeBoundBox subBb;
2281     if (isNode(index))
2282     {
2283         subBb = nodes_[getNode(index)].bb_;
2284     }
2285     else if (isContent(index) || isEmpty(index))
2286     {
2287         subBb = nodes_[nodeI].bb_.subBbox(octant);
2288     }
2290     Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
2291         << " to " << str.name() << endl;
2293     // Dump bounding box
2294     pointField bbPoints(subBb.points());
2296     forAll(bbPoints, i)
2297     {
2298         const point& pt = bbPoints[i];
2300         str<< "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
2301     }
2303     forAll(treeBoundBox::edges, i)
2304     {
2305         const edge& e = treeBoundBox::edges[i];
2307         str<< "l " << e[0] + 1 << ' ' << e[1] + 1 << nl;
2308     }
2312 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
2314 template <class Type>
2315 Foam::indexedOctree<Type>::indexedOctree(const Type& shapes)
2317     shapes_(shapes),
2318     nodes_(0),
2319     contents_(0),
2320     nodeTypes_(0)
2324 template <class Type>
2325 Foam::indexedOctree<Type>::indexedOctree
2327     const Type& shapes,
2328     const List<node>& nodes,
2329     const labelListList& contents
2332     shapes_(shapes),
2333     nodes_(nodes),
2334     contents_(contents),
2335     nodeTypes_(0)
2339 template <class Type>
2340 Foam::indexedOctree<Type>::indexedOctree
2342     const Type& shapes,
2343     const treeBoundBox& bb,
2344     const label maxLevels,          // maximum number of levels
2345     const scalar maxLeafRatio,
2346     const scalar maxDuplicity
2349     shapes_(shapes),
2350     nodes_(0),
2351     contents_(0),
2352     nodeTypes_(0)
2354     if (debug)
2355     {
2356         Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2357             << "    shapes:" << shapes.size() << nl
2358             << "    bb:" << bb << nl
2359             << endl;
2360     }
2362     if (shapes.size() == 0)
2363     {
2364         return;
2365     }
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()));
2372     // Create topnode.
2373     node topNode(divide(bb, contents, 0));
2374     nodes.append(topNode);
2377     // Now have all contents at level 1. Create levels by splitting levels
2378     // above.
2380     label nLevels = 1;
2382     for (; nLevels < maxLevels; nLevels++)
2383     {
2384         // Count number of references into shapes (i.e. contents)
2385         label nEntries = 0;
2386         forAll(contents, i)
2387         {
2388             nEntries += contents[i].size();
2389         }
2391         if (debug)
2392         {
2393             Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2394                 << "    nLevels:" << nLevels << nl
2395                 << "    nEntries per treeLeaf:" << nEntries/contents.size()
2396                 << nl
2397                 << "    nEntries per shape (duplicity):"
2398                 << nEntries/shapes.size()
2399                 << nl
2400                 << endl;
2401         }
2403         if
2404         (
2405             //nEntries < maxLeafRatio*contents.size()
2406          // ||
2407             nEntries > maxDuplicity*shapes.size()
2408         )
2409         {
2410             break;
2411         }
2414         // Split nodes with more than maxLeafRatio elements
2415         label nOldNodes = nodes.size();
2416         splitNodes
2417         (
2418             label(maxLeafRatio),
2419             nodes,
2420             contents
2421         );
2423         if (nOldNodes == nodes.size())
2424         {
2425             break;
2426         }
2427     }
2429     // Shrink
2430     nodes.shrink();
2431     contents.shrink();
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
2436     // off the tree.
2437     contents_.setSize(contents.size());
2438     label compactI = 0;
2440     label level = 0;
2442     while (true)
2443     {
2444         compactContents
2445         (
2446             nodes,
2447             contents,
2448             level,
2449             0,
2450             0,
2451             contents_,
2452             compactI
2453         );
2455         if (compactI == contents_.size())
2456         {
2457             // Transferred all contents to contents_ (in order breadth first)
2458             break;
2459         }
2461         level++;
2462     }
2463     nodes_.transfer(nodes);
2464     nodes.clear();
2466     if (debug)
2467     {
2468         label nEntries = 0;
2469         forAll(contents_, i)
2470         {
2471             nEntries += contents_[i].size();
2472         }
2474         Pout<< "indexedOctree<Type>::indexedOctree"
2475             << " : finished construction of tree of:" << shapes.typeName
2476             << nl
2477             << "    bb:" << this->bb() << nl
2478             << "    shapes:" << shapes.size() << nl
2479             << "    nLevels:" << nLevels << nl
2480             << "    treeNodes:" << nodes_.size() << nl
2481             << "    nEntries:" << nEntries << nl
2482             << "        per treeLeaf:"
2483             << scalar(nEntries)/contents.size() << nl
2484             << "        per shape (duplicity):"
2485             << scalar(nEntries)/shapes.size() << nl
2486             << endl;
2487     }
2491 template <class Type>
2492 Foam::indexedOctree<Type>::indexedOctree
2494     const Type& shapes,
2495     Istream& is
2498     shapes_(shapes),
2499     nodes_(is),
2500     contents_(is),
2501     nodeTypes_(0)
2505 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
2507 template <class Type>
2508 Foam::scalar& Foam::indexedOctree<Type>::perturbTol()
2510     return perturbTol_;
2514 template <class Type>
2515 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
2517     const point& sample,
2518     const scalar startDistSqr
2519 ) const
2521     scalar nearestDistSqr = startDistSqr;
2522     label nearestShapeI = -1;
2523     point nearestPoint = vector::zero;
2525     if (nodes_.size())
2526     {
2527         findNearest
2528         (
2529             0,
2530             sample,
2532             nearestDistSqr,
2533             nearestShapeI,
2534             nearestPoint
2535         );
2536     }
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,
2547     point& linePoint
2548 ) const
2550     label nearestShapeI = -1;
2551     point nearestPoint;
2553     if (nodes_.size())
2554     {
2555         findNearest
2556         (
2557             0,
2558             ln,
2560             tightest,
2561             nearestShapeI,
2562             linePoint,
2563             nearestPoint
2564         );
2565     }
2566     else
2567     {
2568         nearestPoint = vector::zero;
2569     }
2571     return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2575 // Find nearest intersection
2576 template <class Type>
2577 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
2579     const point& start,
2580     const point& end
2581 ) const
2583     return findLine(false, start, end);
2587 // Find nearest intersection
2588 template <class Type>
2589 Foam::pointIndexHit Foam::indexedOctree<Type>::findLineAny
2591     const point& start,
2592     const point& end
2593 ) const
2595     return findLine(true, start, end);
2599 template <class Type>
2600 Foam::labelList Foam::indexedOctree<Type>::findBox
2602     const treeBoundBox& searchBox
2603 ) const
2605     // Storage for labels of shapes inside bb. Size estimate.
2606     labelHashSet elements(shapes_.size() / 100);
2608     if (nodes_.size())
2609     {
2610         findBox(0, searchBox, elements);
2611     }
2613     return elements.toc();
2617 // Find node (as parent+octant) containing point
2618 template <class Type>
2619 Foam::labelBits Foam::indexedOctree<Type>::findNode
2621     const label nodeI,
2622     const point& sample
2623 ) const
2625     if (nodes_.empty())
2626     {
2627         // Empty tree. Return what?
2628         return nodePlusOctant(nodeI, 0);
2629     }
2631     const node& nod = nodes_[nodeI];
2633     if (debug)
2634     {
2635         if (!nod.bb_.contains(sample))
2636         {
2637             FatalErrorIn("findNode(..)")
2638                 << "Cannot find " << sample << " in node " << nodeI
2639                 << abort(FatalError);
2640         }
2641     }
2643     direction octant = nod.bb_.subOctant(sample);
2645     labelBits index = nod.subNodes_[octant];
2647     if (isNode(index))
2648     {
2649         // Recurse
2650         return findNode(getNode(index), sample);
2651     }
2652     else if (isContent(index))
2653     {
2654         // Content. Return treenode+octant
2655         return nodePlusOctant(nodeI, octant);
2656     }
2657     else
2658     {
2659         // Empty. Return treenode+octant
2660         return nodePlusOctant(nodeI, octant);
2661     }
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))
2676     {
2677         labelList indices = contents_[getContent(contentIndex)];
2679         forAll(indices, elemI)
2680         {
2681             label shapeI = indices[elemI];
2683             if (shapes_.contains(shapeI, sample))
2684             {
2685                 return shapeI;
2686             }
2687         }
2688     }
2690     return -1;
2694 template <class Type>
2695 const Foam::labelList& Foam::indexedOctree<Type>::findIndices
2697     const point& sample
2698 ) const
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))
2708     {
2709         return contents_[getContent(contentIndex)];
2710     }
2711     else
2712     {
2713         return emptyList<label>();
2714     }
2718 // Determine type (inside/outside/mixed) per node.
2719 template <class Type>
2720 typename Foam::indexedOctree<Type>::volumeType
2721 Foam::indexedOctree<Type>::getVolumeType
2723     const point& sample
2724 ) const
2726     if (nodes_.empty())
2727     {
2728         return UNKNOWN;
2729     }
2731     if (nodeTypes_.size() != 8*nodes_.size())
2732     {
2733         // Calculate type for every octant of node.
2735         nodeTypes_.setSize(8*nodes_.size());
2736         nodeTypes_ = UNKNOWN;
2738         calcVolumeType(0);
2740         if (debug)
2741         {
2742             label nUNKNOWN = 0;
2743             label nMIXED = 0;
2744             label nINSIDE = 0;
2745             label nOUTSIDE = 0;
2747             forAll(nodeTypes_, i)
2748             {
2749                 volumeType type = volumeType(nodeTypes_.get(i));
2751                 if (type == UNKNOWN)
2752                 {
2753                     nUNKNOWN++;
2754                 }
2755                 else if (type == MIXED)
2756                 {
2757                     nMIXED++;
2758                 }
2759                 else if (type == INSIDE)
2760                 {
2761                     nINSIDE++;
2762                 }
2763                 else if (type == OUTSIDE)
2764                 {
2765                     nOUTSIDE++;
2766                 }
2767                 else
2768                 {
2769                     FatalErrorIn("getVolumeType") << abort(FatalError);
2770                 }
2771             }
2773             Pout<< "indexedOctree<Type>::getVolumeType : "
2774                 << " bb:" << bb()
2775                 << " nodes_:" << nodes_.size()
2776                 << " nodeTypes_:" << nodeTypes_.size()
2777                 << " nUNKNOWN:" << nUNKNOWN
2778                 << " nMIXED:" << nMIXED
2779                 << " nINSIDE:" << nINSIDE
2780                 << " nOUTSIDE:" << nOUTSIDE
2781                 << endl;
2782         }
2783     }
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,
2795     CompareOp& cop
2796 ) const
2798     findNear
2799     (
2800         nearDist,
2801         true,
2802         *this,
2803         nodePlusOctant(0, 0),
2804         bb(),
2805         tree2,
2806         nodePlusOctant(0, 0),
2807         tree2.bb(),
2808         cop
2809     );
2813 // Print contents of nodeI
2814 template <class Type>
2815 void Foam::indexedOctree<Type>::print
2817     prefixOSstream& os,
2818     const bool printContents,
2819     const label nodeI
2820 ) const
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++)
2830     {
2831         const treeBoundBox subBb(bb.subBbox(octant));
2833         labelBits index = nod.subNodes_[octant];
2835         if (isNode(index))
2836         {
2837             // tree node.
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;
2850         }
2851         else if (isContent(index))
2852         {
2853             const labelList& indices = contents_[getContent(index)];
2855             if (debug)
2856             {
2857                 writeOBJ(nodeI, octant);
2858             }
2860             os  << "octant:" << octant
2861                 << " content: n:" << indices.size()
2862                 << " bb:" << subBb;
2864             if (printContents)
2865             {
2866                 os << " contents:";
2867                 forAll(indices, j)
2868                 {
2869                     os  << ' ' << indices[j];
2870                 }
2871             }
2872             os  << endl;
2873         }
2874         else
2875         {
2876             if (debug)
2877             {
2878                 writeOBJ(nodeI, octant);
2879             }
2881             os  << "octant:" << octant << " empty:" << subBb << endl;
2882         }
2883     }
2887 // Print contents of nodeI
2888 template <class Type>
2889 bool Foam::indexedOctree<Type>::write(Ostream& os) const
2891     os << *this;
2893     return os.good();
2897 template <class Type>
2898 Foam::Ostream& Foam::operator<<(Ostream& os, const indexedOctree<Type>& t)
2900     return
2901         os  << t.bb() << token::SPACE << t.nodes()
2902             << token::SPACE << t.contents();
2906 // ************************************************************************* //