Fix tutorials: coupled/conjugateHeatFoam/conjugateCavity: fix Allrun file
[OpenFOAM-1.6-ext.git] / src / meshTools / indexedOctree / indexedOctree.C
blob5b0ac55522abae61d81bdf12959dc20e1e490504
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright held by original author
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 the
13     Free Software Foundation; either version 2 of the License, or (at your
14     option) any later version.
16     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19     for more details.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "indexedOctree.H"
28 #include "linePointRef.H"
29 #include "meshTools.H"
30 #include "OFstream.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 template <class Type>
35 Foam::scalar Foam::indexedOctree<Type>::perturbTol_ = 10*SMALL;
38 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
40 // Does bb intersect a sphere around sample? Or is any corner point of bb
41 // closer than nearestDistSqr to sample.
42 template <class Type>
43 bool Foam::indexedOctree<Type>::overlaps
45     const point& p0,
46     const point& p1,
47     const scalar nearestDistSqr,
48     const point& sample
51     // Find out where sample is in relation to bb.
52     // Find nearest point on bb.
53     scalar distSqr = 0;
55     for (direction dir = 0; dir < vector::nComponents; dir++)
56     {
57         scalar d0 = p0[dir] - sample[dir];
58         scalar d1 = p1[dir] - sample[dir];
60         if ((d0 > 0) != (d1 > 0))
61         {
62             // sample inside both extrema. This component does not add any
63             // distance.
64         }
65         else if (mag(d0) < mag(d1))
66         {
67             distSqr += d0*d0;
68         }
69         else
70         {
71             distSqr += d1*d1;
72         }
74         if (distSqr > nearestDistSqr)
75         {
76             return false;
77         }
78     }
80     return true;
84 // Does bb intersect a sphere around sample? Or is any corner point of bb
85 // closer than nearestDistSqr to sample.
86 template <class Type>
87 bool Foam::indexedOctree<Type>::overlaps
89     const treeBoundBox& parentBb,
90     const direction octant,
91     const scalar nearestDistSqr,
92     const point& sample
95     //- Accelerated version of
96     //     treeBoundBox subBb(parentBb.subBbox(mid, octant))
97     //     overlaps
98     //     (
99     //          subBb.min(),
100     //          subBb.max(),
101     //          nearestDistSqr,
102     //          sample
103     //     )
105     const point& min = parentBb.min();
106     const point& max = parentBb.max();
108     point other;
110     if (octant & treeBoundBox::RIGHTHALF)
111     {
112         other.x() = max.x();
113     }
114     else
115     {
116         other.x() = min.x();
117     }
119     if (octant & treeBoundBox::TOPHALF)
120     {
121         other.y() = max.y();
122     }
123     else
124     {
125         other.y() = min.y();
126     }
128     if (octant & treeBoundBox::FRONTHALF)
129     {
130         other.z() = max.z();
131     }
132     else
133     {
134         other.z() = min.z();
135     }
137     const point mid(0.5*(min+max));
139     return overlaps(mid, other, nearestDistSqr, sample);
144 // Construction helper routines
145 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148 // Split list of indices into 8 bins
149 template <class Type>
150 void Foam::indexedOctree<Type>::divide
152     const labelList& indices,
153     const treeBoundBox& bb,
154     labelListList& result
155 ) const
157     List<DynamicList<label> > subIndices(8);
158     for (direction octant = 0; octant < subIndices.size(); octant++)
159     {
160         subIndices[octant].setCapacity(indices.size()/8);
161     }
163     // Precalculate bounding boxes.
164     FixedList<treeBoundBox, 8> subBbs;
165     for (direction octant = 0; octant < subBbs.size(); octant++)
166     {
167         subBbs[octant] = bb.subBbox(octant);
168     }
170     forAll(indices, i)
171     {
172         label shapeI = indices[i];
174         for (direction octant = 0; octant < 8; octant++)
175         {
176             if (shapes_.overlaps(shapeI, subBbs[octant]))
177             {
178                 subIndices[octant].append(shapeI);
179             }
180         }
181     }
183     result.setSize(8);
184     for (direction octant = 0; octant < subIndices.size(); octant++)
185     {
186         result[octant].transfer(subIndices[octant]);
187     }
191 // Subdivide the (content) node.
192 template <class Type>
193 typename Foam::indexedOctree<Type>::node
194 Foam::indexedOctree<Type>::divide
196     const treeBoundBox& bb,
197     DynamicList<labelList>& contents,
198     const label contentI
199 ) const
201     const labelList& indices = contents[contentI];
203     node nod;
205     if
206     (
207         bb.min()[0] >= bb.max()[0]
208      || bb.min()[1] >= bb.max()[1]
209      || bb.min()[2] >= bb.max()[2]
210     )
211     {
212         FatalErrorIn("indexedOctree<Type>::divide(..)")
213             << "Badly formed bounding box:" << bb
214             << abort(FatalError);
215     }
217     nod.bb_ = bb;
218     nod.parent_ = -1;
220     labelListList dividedIndices(8);
221     divide(indices, bb, dividedIndices);
223     // Have now divided the indices into 8 (possibly empty) subsets.
224     // Replace current contentI with the first (non-empty) subset.
225     // Append the rest.
226     bool replaced = false;
228     for (direction octant = 0; octant < dividedIndices.size(); octant++)
229     {
230         labelList& subIndices = dividedIndices[octant];
232         if (subIndices.size())
233         {
234             if (!replaced)
235             {
236                 contents[contentI].transfer(subIndices);
237                 nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
238                 replaced = true;
239             }
240             else
241             {
242                 // Store at end of contents.
243                 // note dummy append + transfer trick
244                 label sz = contents.size();
245                 contents.append(labelList(0));
246                 contents[sz].transfer(subIndices);
247                 nod.subNodes_[octant] = contentPlusOctant(sz, octant);
248             }
249         }
250         else
251         {
252             // Mark node as empty
253             nod.subNodes_[octant] = emptyPlusOctant(octant);
254         }
255     }
257     return nod;
261 // Split any contents node with more than minSize elements.
262 template <class Type>
263 void Foam::indexedOctree<Type>::splitNodes
265     const label minSize,
266     DynamicList<indexedOctree<Type>::node>& nodes,
267     DynamicList<labelList>& contents
268 ) const
270     label currentSize = nodes.size();
272     // Take care to loop only over old nodes.
273     // Also we loop over the same DynamicList which gets modified and
274     // moved so make sure not to keep any references!
275     for (label nodeI = 0; nodeI < currentSize; nodeI++)
276     {
277         for
278         (
279             direction octant = 0;
280             octant < nodes[nodeI].subNodes_.size();
281             octant++
282         )
283         {
284             labelBits index = nodes[nodeI].subNodes_[octant];
286             if (isNode(index))
287             {
288                 // tree node. Leave intact.
289             }
290             else if (isContent(index))
291             {
292                 label contentI = getContent(index);
294                 if (contents[contentI].size() > minSize)
295                 {
296                     // Create node for content.
298                     // Find the bounding box for the subnode
299                     const node& nod = nodes[nodeI];
300                     const treeBoundBox bb(nod.bb_.subBbox(octant));
302                     node subNode(divide(bb, contents, contentI));
303                     subNode.parent_ = nodeI;
304                     label sz = nodes.size();
305                     nodes.append(subNode);
306                     nodes[nodeI].subNodes_[octant] = nodePlusOctant(sz, octant);
307                 }
308             }
309         }
310     }
314 // Reorder contents to be in same order as nodes. Returns number of nodes on
315 // the compactLevel.
316 template <class Type>
317 Foam::label Foam::indexedOctree<Type>::compactContents
319     DynamicList<node>& nodes,
320     DynamicList<labelList>& contents,
321     const label compactLevel,
322     const label nodeI,
323     const label level,
325     List<labelList>& compactedContents,
326     label& compactI
329     const node& nod = nodes[nodeI];
331     label nNodes = 0;
333     if (level < compactLevel)
334     {
335         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
336         {
337             labelBits index = nod.subNodes_[octant];
339             if (isNode(index))
340             {
341                 nNodes += compactContents
342                 (
343                     nodes,
344                     contents,
345                     compactLevel,
346                     getNode(index),
347                     level+1,
348                     compactedContents,
349                     compactI
350                 );
351             }
352         }
353     }
354     else if (level == compactLevel)
355     {
356         // Compact all content on this level
357         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
358         {
359             labelBits index = nod.subNodes_[octant];
361             if (isContent(index))
362             {
363                 label contentI = getContent(index);
365                 compactedContents[compactI].transfer(contents[contentI]);
367                 // Subnode is at compactI. Adapt nodeI to point to it
368                 nodes[nodeI].subNodes_[octant] =
369                     contentPlusOctant(compactI, octant);
371                 compactI++;
372             }
373             else if (isNode(index))
374             {
375                 nNodes++;
376             }
377         }
378     }
379     return nNodes;
383 // Pre-calculates wherever possible the volume status per node/subnode.
384 // Recurses to determine status of lowest level boxes. Level above is
385 // combination of octants below.
386 template <class Type>
387 typename Foam::indexedOctree<Type>::volumeType
388 Foam::indexedOctree<Type>::calcVolumeType
390     const label nodeI
391 ) const
393     const node& nod = nodes_[nodeI];
395     volumeType myType = UNKNOWN;
397     for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
398     {
399         volumeType subType;
401         labelBits index = nod.subNodes_[octant];
403         if (isNode(index))
404         {
405             // tree node. Recurse.
406             subType = calcVolumeType(getNode(index));
407         }
408         else if (isContent(index))
409         {
410             // Contents. Depending on position in box might be on either
411             // side.
412             subType = MIXED;
413         }
414         else
415         {
416             // No data in this octant. Set type for octant acc. to the mid
417             // of its bounding box.
418             const treeBoundBox subBb = nod.bb_.subBbox(octant);
420             subType = volumeType
421             (
422                 shapes_.getVolumeType(*this, subBb.midpoint())
423             );
424         }
426         // Store octant type
427         nodeTypes_.set((nodeI<<3)+octant, subType);
429         // Combine sub node types into type for treeNode. Result is 'mixed' if
430         // types differ among subnodes.
431         if (myType == UNKNOWN)
432         {
433             myType = subType;
434         }
435         else if (subType != myType)
436         {
437             myType = MIXED;
438         }
439     }
440     return myType;
444 template <class Type>
445 typename Foam::indexedOctree<Type>::volumeType
446 Foam::indexedOctree<Type>::getVolumeType
448     const label nodeI,
449     const point& sample
450 ) const
452     const node& nod = nodes_[nodeI];
454     direction octant = nod.bb_.subOctant(sample);
456     volumeType octantType = volumeType(nodeTypes_.get((nodeI<<3)+octant));
458     if (octantType == INSIDE)
459     {
460         return octantType;
461     }
462     else if (octantType == OUTSIDE)
463     {
464         return octantType;
465     }
466     else if (octantType == UNKNOWN)
467     {
468         // Can happen for e.g. non-manifold surfaces.
469         return octantType;
470     }
471     else if (octantType == MIXED)
472     {
473         labelBits index = nod.subNodes_[octant];
475         if (isNode(index))
476         {
477             // Recurse
478             volumeType subType = getVolumeType(getNode(index), sample);
480             return subType;
481         }
482         else if (isContent(index))
483         {
484             // Content. Defer to shapes.
485             return volumeType(shapes_.getVolumeType(*this, sample));
486         }
487         else
488         {
489             // Empty node. Cannot have 'mixed' as its type since not divided
490             // up and has no items inside it.
491             FatalErrorIn
492             (
493                 "indexedOctree<Type>::getVolumeType"
494                 "(const label, const point&)"
495             )   << "Sample:" << sample << " node:" << nodeI
496                 << " with bb:" << nodes_[nodeI].bb_ << nl
497                 << "Empty subnode has invalid volume type MIXED."
498                 << abort(FatalError);
500             return UNKNOWN;
501         }
502     }
503     else
504     {
505         FatalErrorIn
506         (
507             "indexedOctree<Type>::getVolumeType"
508             "(const label, const point&)"
509         )   << "Sample:" << sample << " at node:" << nodeI
510             << " octant:" << octant
511             << " with bb:" << nod.bb_.subBbox(octant) << nl
512             << "Node has invalid volume type " << octantType
513             << abort(FatalError);
515         return UNKNOWN;
516     }
520 template <class Type>
521 typename Foam::indexedOctree<Type>::volumeType
522 Foam::indexedOctree<Type>::getSide
524     const vector& outsideNormal,
525     const vector& vec
528     if ((outsideNormal&vec) >= 0)
529     {
530         return OUTSIDE;
531     }
532     else
533     {
534         return INSIDE;
535     }
540 // Query routines
541 // ~~~~~~~~~~~~~~
544 // Find nearest point starting from nodeI
545 template <class Type>
546 void Foam::indexedOctree<Type>::findNearest
548     const label nodeI,
549     const point& sample,
551     scalar& nearestDistSqr,
552     label& nearestShapeI,
553     point& nearestPoint
554 ) const
556     const node& nod = nodes_[nodeI];
558     // Determine order to walk through octants
559     FixedList<direction, 8> octantOrder;
560     nod.bb_.searchOrder(sample, octantOrder);
562     // Go into all suboctants (one containing sample first) and update nearest.
563     for (direction i = 0; i < 8; i++)
564     {
565         direction octant = octantOrder[i];
567         labelBits index = nod.subNodes_[octant];
569         if (isNode(index))
570         {
571             label subNodeI = getNode(index);
573             const treeBoundBox& subBb = nodes_[subNodeI].bb_;
575             if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
576             {
577                 findNearest
578                 (
579                     subNodeI,
580                     sample,
582                     nearestDistSqr,
583                     nearestShapeI,
584                     nearestPoint
585                 );
586             }
587         }
588         else if (isContent(index))
589         {
590             if
591             (
592                 overlaps
593                 (
594                     nod.bb_,
595                     octant,
596                     nearestDistSqr,
597                     sample
598                 )
599             )
600             {
601                 shapes_.findNearest
602                 (
603                     contents_[getContent(index)],
604                     sample,
606                     nearestDistSqr,
607                     nearestShapeI,
608                     nearestPoint
609                 );
610             }
611         }
612     }
616 // Find nearest point to line.
617 template <class Type>
618 void Foam::indexedOctree<Type>::findNearest
620     const label nodeI,
621     const linePointRef& ln,
623     treeBoundBox& tightest,
624     label& nearestShapeI,
625     point& linePoint,
626     point& nearestPoint
627 ) const
629     const node& nod = nodes_[nodeI];
630     const treeBoundBox& nodeBb = nod.bb_;
632     // Determine order to walk through octants
633     FixedList<direction, 8> octantOrder;
634     nod.bb_.searchOrder(ln.centre(), octantOrder);
636     // Go into all suboctants (one containing sample first) and update nearest.
637     for (direction i = 0; i < 8; i++)
638     {
639         direction octant = octantOrder[i];
641         labelBits index = nod.subNodes_[octant];
643         if (isNode(index))
644         {
645             const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
647             if (subBb.overlaps(tightest))
648             {
649                 findNearest
650                 (
651                     getNode(index),
652                     ln,
654                     tightest,
655                     nearestShapeI,
656                     linePoint,
657                     nearestPoint
658                 );
659             }
660         }
661         else if (isContent(index))
662         {
663             const treeBoundBox subBb(nodeBb.subBbox(octant));
665             if (subBb.overlaps(tightest))
666             {
667                 shapes_.findNearest
668                 (
669                     contents_[getContent(index)],
670                     ln,
672                     tightest,
673                     nearestShapeI,
674                     linePoint,
675                     nearestPoint
676                 );
677             }
678         }
679     }
683 template <class Type>
684 Foam::treeBoundBox Foam::indexedOctree<Type>::subBbox
686     const label parentNodeI,
687     const direction octant
688 ) const
690     // Get type of node at octant
691     const node& nod = nodes_[parentNodeI];
692     labelBits index = nod.subNodes_[octant];
694     if (isNode(index))
695     {
696         // Use stored bb
697         return nodes_[getNode(index)].bb_;
698     }
699     else
700     {
701         // Calculate subBb
702         return nod.bb_.subBbox(octant);
703     }
707 // Takes a bb and a point on/close to the edge of the bb and pushes the point
708 // inside by a small fraction.
709 template <class Type>
710 Foam::point Foam::indexedOctree<Type>::pushPoint
712     const treeBoundBox& bb,
713     const point& pt,
714     const bool pushInside
717     // Get local length scale.
718     const vector perturbVec = perturbTol_*(bb.span());
720     point perturbedPt(pt);
722     // Modify all components which are close to any face of the bb to be
723     // well inside/outside them.
725     if (pushInside)
726     {
727         for (direction dir = 0; dir < vector::nComponents; dir++)
728         {
729             if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
730             {
731                 // Close to 'left' side. Push well beyond left side.
732                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
733                 perturbedPt[dir] = bb.min()[dir] + perturbDist;
734             }
735             else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
736             {
737                 // Close to 'right' side. Push well beyond right side.
738                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
739                 perturbedPt[dir] = bb.max()[dir] - perturbDist;
740             }
741         }
742     }
743     else
744     {
745         for (direction dir = 0; dir < vector::nComponents; dir++)
746         {
747             if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
748             {
749                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
750                 perturbedPt[dir] = bb.min()[dir] - perturbDist;
751             }
752             else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
753             {
754                 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
755                 perturbedPt[dir] = bb.max()[dir] + perturbDist;
756             }
757         }
758     }
760     if (debug)
761     {
762         if (pushInside != bb.contains(perturbedPt))
763         {
764             FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
765                 << "pushed point:" << pt
766                 << " to:" << perturbedPt
767                 << " wanted side:" << pushInside
768                 << " obtained side:" << bb.contains(perturbedPt)
769                 << " of bb:" << bb
770                 << abort(FatalError);
771         }
772     }
774     return perturbedPt;
778 // Takes a bb and a point on the edge of the bb and pushes the point
779 // outside by a small fraction.
780 template <class Type>
781 Foam::point Foam::indexedOctree<Type>::pushPoint
783     const treeBoundBox& bb,
784     const direction faceID,
785     const point& pt,
786     const bool pushInside
789     // Get local length scale.
790     const vector perturbVec = perturbTol_*bb.span();
792     point perturbedPt(pt);
794     // Modify all components which are close to any face of the bb to be
795     // well outside them.
797     if (faceID == 0)
798     {
799         FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
800             << abort(FatalError);
801     }
803     if (faceID & treeBoundBox::LEFTBIT)
804     {
805         if (pushInside)
806         {
807             perturbedPt[0] = bb.min()[0] + (perturbVec[0] + ROOTVSMALL);
808         }
809         else
810         {
811             perturbedPt[0] = bb.min()[0] - (perturbVec[0] + ROOTVSMALL);
812         }
813     }
814     else if (faceID & treeBoundBox::RIGHTBIT)
815     {
816         if (pushInside)
817         {
818             perturbedPt[0] = bb.max()[0] - (perturbVec[0] + ROOTVSMALL);
819         }
820         else
821         {
822             perturbedPt[0] = bb.max()[0] + (perturbVec[0] + ROOTVSMALL);
823         }
824     }
826     if (faceID & treeBoundBox::BOTTOMBIT)
827     {
828         if (pushInside)
829         {
830             perturbedPt[1] = bb.min()[1] + (perturbVec[1] + ROOTVSMALL);
831         }
832         else
833         {
834             perturbedPt[1] = bb.min()[1] - (perturbVec[1] + ROOTVSMALL);
835         }
836     }
837     else if (faceID & treeBoundBox::TOPBIT)
838     {
839         if (pushInside)
840         {
841             perturbedPt[1] = bb.max()[1] - (perturbVec[1] + ROOTVSMALL);
842         }
843         else
844         {
845             perturbedPt[1] = bb.max()[1] + (perturbVec[1] + ROOTVSMALL);
846         }
847     }
849     if (faceID & treeBoundBox::BACKBIT)
850     {
851         if (pushInside)
852         {
853             perturbedPt[2] = bb.min()[2] + (perturbVec[2] + ROOTVSMALL);
854         }
855         else
856         {
857             perturbedPt[2] = bb.min()[2] - (perturbVec[2] + ROOTVSMALL);
858         }
859     }
860     else if (faceID & treeBoundBox::FRONTBIT)
861     {
862         if (pushInside)
863         {
864             perturbedPt[2] = bb.max()[2] - (perturbVec[2] + ROOTVSMALL);
865         }
866         else
867         {
868             perturbedPt[2] = bb.max()[2] + (perturbVec[2] + ROOTVSMALL);
869         }
870     }
872     if (debug)
873     {
874         if (pushInside != bb.contains(perturbedPt))
875         {
876             FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
877                 << "pushed point:" << pt << " on face:" << faceString(faceID)
878                 << " to:" << perturbedPt
879                 << " wanted side:" << pushInside
880                 << " obtained side:" << bb.contains(perturbedPt)
881                 << " of bb:" << bb
882                 << abort(FatalError);
883         }
884     }
886     return perturbedPt;
890 // Guarantees that if pt is on a face it gets perturbed so it is away
891 // from the face edges.
892 // If pt is not on a face does nothing.
893 template <class Type>
894 Foam::point Foam::indexedOctree<Type>::pushPointIntoFace
896     const treeBoundBox& bb,
897     const vector& dir,          // end-start
898     const point& pt
901     if (debug)
902     {
903         if (bb.posBits(pt) != 0)
904         {
905             FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
906                 << " bb:" << bb << endl
907                 << "does not contain point " << pt << abort(FatalError);
908         }
909     }
912     // Handle two cases:
913     // - point exactly on multiple faces. Push away from all but one.
914     // - point on a single face. Push away from edges of face.
916     direction ptFaceID = bb.faceBits(pt);
918     direction nFaces = 0;
919     FixedList<direction, 3> faceIndices;
921     if (ptFaceID & treeBoundBox::LEFTBIT)
922     {
923         faceIndices[nFaces++] = treeBoundBox::LEFT;
924     }
925     else if (ptFaceID & treeBoundBox::RIGHTBIT)
926     {
927         faceIndices[nFaces++] = treeBoundBox::RIGHT;
928     }
930     if (ptFaceID & treeBoundBox::BOTTOMBIT)
931     {
932         faceIndices[nFaces++] = treeBoundBox::BOTTOM;
933     }
934     else if (ptFaceID & treeBoundBox::TOPBIT)
935     {
936         faceIndices[nFaces++] = treeBoundBox::TOP;
937     }
939     if (ptFaceID & treeBoundBox::BACKBIT)
940     {
941         faceIndices[nFaces++] = treeBoundBox::BACK;
942     }
943     else if (ptFaceID & treeBoundBox::FRONTBIT)
944     {
945         faceIndices[nFaces++] = treeBoundBox::FRONT;
946     }
949     // Determine the face we want to keep the point on
951     direction keepFaceID;
953     if (nFaces == 0)
954     {
955         // Return original point
956         return pt;
957     }
958     else if (nFaces == 1)
959     {
960         // Point is on a single face
961         keepFaceID = faceIndices[0];
962     }
963     else
964     {
965         // Determine best face out of faceIndices[0 .. nFaces-1].
966         // The best face is the one most perpendicular to the ray direction.
968         keepFaceID = faceIndices[0];
969         scalar maxInproduct = mag(treeBoundBox::faceNormals[keepFaceID] & dir);
971         for (direction i = 1; i < nFaces; i++)
972         {
973             direction face = faceIndices[i];
974             scalar s = mag(treeBoundBox::faceNormals[face] & dir);
975             if (s > maxInproduct)
976             {
977                 maxInproduct = s;
978                 keepFaceID = face;
979             }
980         }
981     }
984     // 1. Push point into bb, away from all corners
986     point facePoint(pushPoint(bb, pt, true));
987     direction faceID = 0;
989     // 2. Snap it back onto the preferred face
991     if (keepFaceID == treeBoundBox::LEFT)
992     {
993         facePoint.x() = bb.min().x();
994         faceID = treeBoundBox::LEFTBIT;
995     }
996     else if (keepFaceID == treeBoundBox::RIGHT)
997     {
998         facePoint.x() = bb.max().x();
999         faceID = treeBoundBox::RIGHTBIT;
1000     }
1001     else if (keepFaceID == treeBoundBox::BOTTOM)
1002     {
1003         facePoint.y() = bb.min().y();
1004         faceID = treeBoundBox::BOTTOMBIT;
1005     }
1006     else if (keepFaceID == treeBoundBox::TOP)
1007     {
1008         facePoint.y() = bb.max().y();
1009         faceID = treeBoundBox::TOPBIT;
1010     }
1011     else if (keepFaceID == treeBoundBox::BACK)
1012     {
1013         facePoint.z() = bb.min().z();
1014         faceID = treeBoundBox::BACKBIT;
1015     }
1016     else if (keepFaceID == treeBoundBox::FRONT)
1017     {
1018         facePoint.z() = bb.max().z();
1019         faceID = treeBoundBox::FRONTBIT;
1020     }
1023     if (debug)
1024     {
1025         if (faceID != bb.faceBits(facePoint))
1026         {
1027             FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
1028                 << "Pushed point from " << pt
1029                 << " on face:" << ptFaceID << " of bb:" << bb << endl
1030                 << "onto " << facePoint
1031                 << " on face:" << faceID
1032                 << " which is not consistent with geometric face "
1033                 << bb.faceBits(facePoint)
1034                 << abort(FatalError);
1035         }
1036         if (bb.posBits(facePoint) != 0)
1037         {
1038             FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
1039                 << " bb:" << bb << endl
1040                 << "does not contain perturbed point "
1041                 << facePoint << abort(FatalError);
1042         }
1043     }
1046     return facePoint;
1050 //// Takes a bb and a point on the outside of the bb. Checks if on multiple faces
1051 //// and if so perturbs point so it is only on one face.
1052 //template <class Type>
1053 //void Foam::indexedOctree<Type>::checkMultipleFaces
1055 //    const treeBoundBox& bb,
1056 //    const vector& dir,          // end-start
1057 //    pointIndexHit& faceHitInfo,
1058 //    direction& faceID
1061 //    // Do the quick elimination of no or one face.
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 (findAny)
1627         {
1628             // Find any intersection
1630             forAll(indices, elemI)
1631             {
1632                 label shapeI = indices[elemI];
1634                 point pt;
1635                 bool hit = shapes_.intersects(shapeI, start, end, pt);
1637                 if (hit)
1638                 {
1639                     // Hit so pt is nearer than nearestPoint.
1640                     // Update hit info
1641                     hitInfo.setHit();
1642                     hitInfo.setIndex(shapeI);
1643                     hitInfo.setPoint(pt);
1644                     return;
1645                 }
1646             }
1647         }
1648         else
1649         {
1650             // Find nearest intersection.
1652             point nearestPoint(end);
1654             forAll(indices, elemI)
1655             {
1656                 label shapeI = indices[elemI];
1658                 point pt;
1659                 bool hit = shapes_.intersects(shapeI, start, nearestPoint, pt);
1661                 if (hit)
1662                 {
1663                     // Hit so pt is nearer than nearestPoint.
1664                     nearestPoint = pt;
1665                     // Update hit info
1666                     hitInfo.setHit();
1667                     hitInfo.setIndex(shapeI);
1668                     hitInfo.setPoint(pt);
1669                 }
1670             }
1672             if (hitInfo.hit())
1673             {
1674                 // Found intersected shape.
1675                 return;
1676             }
1677         }
1678     }
1680     // Nothing intersected in this node
1681     // Traverse to end of node. Do by ray tracing back from end and finding
1682     // intersection with bounding box of node.
1683     // start point is now considered to be inside bounding box.
1685     const treeBoundBox octantBb(subBbox(nodeI, octant));
1687     point pt;
1688     bool intersected = octantBb.intersects
1689     (
1690         end,            //treeStart,
1691         (start-end),    //treeVec,
1693         end,
1694         start,
1696         pt,
1697         hitBits
1698     );
1701     if (intersected)
1702     {
1703         // Return miss. Set misspoint to face.
1704         hitInfo.setPoint(pt);
1705     }
1706     else
1707     {
1708         // Rare case: did not find intersection of ray with octantBb. Can
1709         // happen if end is on face/edge of octantBb. Do like
1710         // lagrangian and re-track with perturbed vector (slightly pushed out
1711         // of bounding box)
1713         point perturbedEnd(pushPoint(octantBb, end, false));
1716         //if (debug)
1717         {
1718             // Dump octantBb to obj
1719             writeOBJ(nodeI, octant);
1720             // Dump ray to obj as well
1721             {
1722                 OFstream str("ray.obj");
1723                 meshTools::writeOBJ(str, start);
1724                 meshTools::writeOBJ(str, end);
1725                 str << "l 1 2" << nl;
1726             }
1727             WarningIn("indexedOctree<Type>::traverseNode(..)")
1728                 << "Did not intersect ray from endpoint:" << end
1729                 << " to startpoint:" << start
1730                 << " with bounding box:" << octantBb << nl
1731                 << "Re-intersecting with perturbed endpoint:" << perturbedEnd
1732                 << endl;
1733         }
1735         traverseNode
1736         (
1737             findAny,
1738             treeStart,
1739             treeVec,
1740             start,
1741             perturbedEnd,
1742             nodeI,
1743             octant,
1745             hitInfo,
1746             hitBits
1747         );
1748     }
1752 // Find first intersection
1753 template <class Type>
1754 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1756     const bool findAny,
1757     const point& treeStart,
1758     const point& treeEnd,
1759     const label startNodeI,
1760     const direction startOctant,
1761     const bool verbose
1762 ) const
1764     const vector treeVec(treeEnd - treeStart);
1766     // Current node as parent+octant
1767     label nodeI = startNodeI;
1768     direction octant = startOctant;
1770     if (verbose)
1771     {
1772         Pout<< "findLine : treeStart:" << treeStart
1773             << " treeEnd:" << treeEnd << endl
1774             << "node:" << nodeI
1775             << " octant:" << octant
1776             << " bb:" << subBbox(nodeI, octant) << endl;
1777     }
1779     // Current position. Initialize to miss
1780     pointIndexHit hitInfo(false, treeStart, -1);
1782     //while (true)
1783     label i = 0;
1784     for (; i < 100000; i++)
1785     {
1786         // Ray-trace to end of current node. Updates point (either on triangle
1787         // in case of hit or on node bounding box in case of miss)
1789         const treeBoundBox octantBb(subBbox(nodeI, octant));
1791         // Make sure point is away from any edges/corners
1792         point startPoint
1793         (
1794             pushPointIntoFace
1795             (
1796                 octantBb,
1797                 treeVec,
1798                 hitInfo.rawPoint()
1799             )
1800         );
1802         if (verbose)
1803         {
1804             Pout<< "iter:" << i
1805                 << " at current:" << hitInfo.rawPoint()
1806                 << " (perturbed:" << startPoint << ")" << endl
1807                 << "    node:" << nodeI
1808                 << " octant:" << octant
1809                 << " bb:" << subBbox(nodeI, octant) << endl;
1810         }
1815         // Faces of current bounding box current point is on
1816         direction hitFaceID = 0;
1818         traverseNode
1819         (
1820             findAny,
1821             treeStart,
1822             treeVec,
1824             startPoint,     // Note: pass in copy since hitInfo
1825                             // also used in return value.
1826             treeEnd,        // pass in overall end so is nicely outside bb
1827             nodeI,
1828             octant,
1830             hitInfo,
1831             hitFaceID
1832         );
1834         // Did we hit a triangle?
1835         if (hitInfo.hit())
1836         {
1837             break;
1838         }
1840         if (hitFaceID == 0 || hitInfo.rawPoint() == treeEnd)
1841         {
1842             // endpoint inside the tree. Return miss.
1843             break;
1844         }
1846         // Create a point on other side of face.
1847         point perturbedPoint
1848         (
1849             pushPoint
1850             (
1851                 octantBb,
1852                 hitFaceID,
1853                 hitInfo.rawPoint(),
1854                 false                   // push outside of octantBb
1855             )
1856         );
1858         if (verbose)
1859         {
1860             Pout<< "    iter:" << i
1861                 << " hit face:" << faceString(hitFaceID)
1862                 << " at:" << hitInfo.rawPoint() << nl
1863                 << "    node:" << nodeI
1864                 << " octant:" << octant
1865                 << " bb:" << subBbox(nodeI, octant) << nl
1866                 << "    walking to neighbour containing:" << perturbedPoint
1867                 << endl;
1868         }
1871         // Nothing hit so we are on face of bounding box (given as node+octant+
1872         // position bits). Traverse to neighbouring node. Use slightly perturbed
1873         // point.
1875         bool ok = walkToNeighbour
1876         (
1877             perturbedPoint,
1878             hitFaceID,  // face(s) that hitInfo is on
1880             nodeI,
1881             octant
1882         );
1884         if (!ok)
1885         {
1886             // Hit the edge of the tree. Return miss.
1887             break;
1888         }
1890         if (verbose)
1891         {
1892             const treeBoundBox octantBb(subBbox(nodeI, octant));
1893             Pout<< "    walked for point:" << hitInfo.rawPoint() << endl
1894                 << "    to neighbour node:" << nodeI
1895                 << " octant:" << octant
1896                 << " face:" << faceString(octantBb.faceBits(hitInfo.rawPoint()))
1897                 << " of octantBb:" << octantBb << endl
1898                 << endl;
1899         }
1900     }
1902     if (i == 100000)
1903     {
1904         // Probably in loop.
1905         if (!verbose)
1906         {
1907             // Redo intersection but now with verbose flag switched on.
1908             return findLine
1909             (
1910                 findAny,
1911                 treeStart,
1912                 treeEnd,
1913                 startNodeI,
1914                 startOctant,
1915                 true            //verbose
1916             );
1917         }
1918         if (debug)
1919         {
1920             FatalErrorIn("indexedOctree<Type>::findLine(..)")
1921                 << "Got stuck in loop raytracing from:" << treeStart
1922                 << " to:" << treeEnd << endl
1923                 << "inside top box:" << subBbox(startNodeI, startOctant)
1924                 << abort(FatalError);
1925         }
1926         else
1927         {
1928             WarningIn("indexedOctree<Type>::findLine(..)")
1929                 << "Got stuck in loop raytracing from:" << treeStart
1930                 << " to:" << treeEnd << endl
1931                 << "inside top box:" << subBbox(startNodeI, startOctant)
1932                 << endl;
1933         }
1934     }
1936     return hitInfo;
1940 // Find first intersection
1941 template <class Type>
1942 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
1944     const bool findAny,
1945     const point& start,
1946     const point& end
1947 ) const
1949     pointIndexHit hitInfo;
1951     if (nodes_.size())
1952     {
1953         const treeBoundBox& treeBb = nodes_[0].bb_;
1955         // No effort is made to deal with points which are on edge of tree
1956         // bounding box for now.
1958         direction startBit = treeBb.posBits(start);
1959         direction endBit = treeBb.posBits(end);
1961         if ((startBit & endBit) != 0)
1962         {
1963             // Both start and end outside domain and in same block.
1964             return pointIndexHit(false, vector::zero, -1);
1965         }
1968         // Trim segment to treeBb
1970         point trackStart(start);
1971         point trackEnd(end);
1973         if (startBit != 0)
1974         {
1975             // Track start to inside domain.
1976             if (!treeBb.intersects(start, end, trackStart))
1977             {
1978                 return pointIndexHit(false, vector::zero, -1);
1979             }
1980         }
1982         if (endBit != 0)
1983         {
1984             // Track end to inside domain.
1985             if (!treeBb.intersects(end, trackStart, trackEnd))
1986             {
1987                 return pointIndexHit(false, vector::zero, -1);
1988             }
1989         }
1992         // Find lowest level tree node that start is in.
1993         labelBits index = findNode(0, trackStart);
1995         label parentNodeI = getNode(index);
1996         direction octant = getOctant(index);
1998         hitInfo = findLine
1999         (
2000             findAny,
2001             trackStart,
2002             trackEnd,
2003             parentNodeI,
2004             octant
2005         );
2006     }
2008     return hitInfo;
2012 template <class Type>
2013 void Foam::indexedOctree<Type>::findBox
2015     const label nodeI,
2016     const treeBoundBox& searchBox,
2017     labelHashSet& elements
2018 ) const
2020     const node& nod = nodes_[nodeI];
2021     const treeBoundBox& nodeBb = nod.bb_;
2023     for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2024     {
2025         labelBits index = nod.subNodes_[octant];
2027         if (isNode(index))
2028         {
2029             const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
2031             if (subBb.overlaps(searchBox))
2032             {
2033                 findBox(getNode(index), searchBox, elements);
2034             }
2035         }
2036         else if (isContent(index))
2037         {
2038             const treeBoundBox subBb(nodeBb.subBbox(octant));
2040             if (subBb.overlaps(searchBox))
2041             {
2042                 const labelList& indices = contents_[getContent(index)];
2044                 forAll(indices, i)
2045                 {
2046                     label shapeI = indices[i];
2048                     if (shapes_.overlaps(shapeI, searchBox))
2049                     {
2050                         elements.insert(shapeI);
2051                     }
2052                 }
2053             }
2054         }
2055     }
2059 // Number of elements in node.
2060 template <class Type>
2061 Foam::label Foam::indexedOctree<Type>::countElements
2063     const labelBits index
2064 ) const
2066     label nElems = 0;
2068     if (isNode(index))
2069     {
2070         // tree node.
2071         label nodeI = getNode(index);
2073         const node& nod = nodes_[nodeI];
2075         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2076         {
2077             nElems += countElements(nod.subNodes_[octant]);
2078         }
2079     }
2080     else if (isContent(index))
2081     {
2082         nElems += contents_[getContent(index)].size();
2083     }
2084     else
2085     {
2086         // empty node
2087     }
2089     return nElems;
2093 template <class Type>
2094 void Foam::indexedOctree<Type>::writeOBJ
2096     const label nodeI,
2097     const direction octant
2098 ) const
2100     OFstream str
2101     (
2102         "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
2103     );
2105     labelBits index = nodes_[nodeI].subNodes_[octant];
2107     treeBoundBox subBb;
2109     if (isNode(index))
2110     {
2111         subBb = nodes_[getNode(index)].bb_;
2112     }
2113     else if (isContent(index))
2114     {
2115         subBb = nodes_[nodeI].bb_.subBbox(octant);
2116     }
2118     Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
2119         << " to " << str.name() << endl;
2121     label vertI = 0;
2123     // Dump bounding box
2124     pointField bbPoints(subBb.points());
2126     label pointVertI = vertI;
2127     forAll(bbPoints, i)
2128     {
2129         meshTools::writeOBJ(str, bbPoints[i]);
2130         vertI++;
2131     }
2133     forAll(treeBoundBox::edges, i)
2134     {
2135         const edge& e = treeBoundBox::edges[i];
2137         str<< "l " << e[0]+pointVertI+1 << ' ' << e[1]+pointVertI+1 << nl;
2138     }
2142 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
2144 template <class Type>
2145 Foam::indexedOctree<Type>::indexedOctree(const Type& shapes)
2147     shapes_(shapes),
2148     nodes_(0),
2149     contents_(0),
2150     nodeTypes_(0)
2154 template <class Type>
2155 Foam::indexedOctree<Type>::indexedOctree
2157     const Type& shapes,
2158     const List<node>& nodes,
2159     const labelListList& contents
2162     shapes_(shapes),
2163     nodes_(nodes),
2164     contents_(contents),
2165     nodeTypes_(0)
2169 template <class Type>
2170 Foam::indexedOctree<Type>::indexedOctree
2172     const Type& shapes,
2173     const treeBoundBox& bb,
2174     const label maxLevels,          // maximum number of levels
2175     const scalar maxLeafRatio,
2176     const scalar maxDuplicity
2179     shapes_(shapes),
2180     nodes_(0),
2181     contents_(0),
2182     nodeTypes_(0)
2184     if (debug)
2185     {
2186         Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2187             << "    shapes:" << shapes.size() << nl
2188             << "    bb:" << bb << nl
2189             << endl;
2190     }
2192     if (shapes.size() == 0)
2193     {
2194         return;
2195     }
2197     // Start off with one node with all shapes in it.
2198     DynamicList<node> nodes(label(shapes.size() / maxLeafRatio));
2199     DynamicList<labelList> contents(label(shapes.size() / maxLeafRatio));
2200     contents.append(identity(shapes.size()));
2202     // Create topnode.
2203     node topNode(divide(bb, contents, 0));
2204     nodes.append(topNode);
2207     // Now have all contents at level 1. Create levels by splitting levels
2208     // above.
2210     label nLevels = 1;
2212     for (; nLevels < maxLevels; nLevels++)
2213     {
2214         // Count number of references into shapes (i.e. contents)
2215         label nEntries = 0;
2216         forAll(contents, i)
2217         {
2218             nEntries += contents[i].size();
2219         }
2221         if (debug)
2222         {
2223             Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2224                 << "    nLevels:" << nLevels << nl
2225                 << "    nEntries per treeLeaf:" << nEntries/contents.size()
2226                 << nl
2227                 << "    nEntries per shape (duplicity):"
2228                 << nEntries/shapes.size()
2229                 << nl
2230                 << endl;
2231         }
2233         if
2234         (
2235             //nEntries < maxLeafRatio*contents.size()
2236          // ||
2237             nEntries > maxDuplicity*shapes.size()
2238         )
2239         {
2240             break;
2241         }
2244         // Split nodes with more than maxLeafRatio elements
2245         label nOldNodes = nodes.size();
2246         splitNodes
2247         (
2248             label(maxLeafRatio),
2249             nodes,
2250             contents
2251         );
2253         if (nOldNodes == nodes.size())
2254         {
2255             break;
2256         }
2257     }
2259     // Shrink
2260     nodes.shrink();
2261     contents.shrink();
2264     // Compact such that deeper level contents are always after the
2265     // ones for a shallower level. This way we can slice a coarser level
2266     // off the tree.
2267     contents_.setSize(contents.size());
2268     label compactI = 0;
2270     label level = 0;
2272     while (true)
2273     {
2274         compactContents
2275         (
2276             nodes,
2277             contents,
2278             level,
2279             0,
2280             0,
2281             contents_,
2282             compactI
2283         );
2285         if (compactI == contents_.size())
2286         {
2287             // Transferred all contents to contents_ (in order breadth first)
2288             break;
2289         }
2291         level++;
2292     }
2293     nodes_.transfer(nodes);
2294     nodes.clear();
2296     if (debug)
2297     {
2298         label nEntries = 0;
2299         forAll(contents_, i)
2300         {
2301             nEntries += contents_[i].size();
2302         }
2304         Pout<< "indexedOctree<Type>::indexedOctree"
2305             << " : finished construction of tree of:" << shapes.typeName
2306             << nl
2307             << "    bb:" << this->bb() << nl
2308             << "    shapes:" << shapes.size() << nl
2309             << "    nLevels:" << nLevels << nl
2310             << "    treeNodes:" << nodes_.size() << nl
2311             << "    nEntries:" << nEntries << nl
2312             << "        per treeLeaf:"
2313             << scalar(nEntries)/contents.size() << nl
2314             << "        per shape (duplicity):"
2315             << scalar(nEntries)/shapes.size() << nl
2316             << endl;
2317     }
2321 template <class Type>
2322 Foam::indexedOctree<Type>::indexedOctree
2324     const Type& shapes,
2325     Istream& is
2328     shapes_(shapes),
2329     nodes_(is),
2330     contents_(is),
2331     nodeTypes_(0)
2335 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
2337 template <class Type>
2338 Foam::scalar& Foam::indexedOctree<Type>::perturbTol()
2340     return perturbTol_;
2344 template <class Type>
2345 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
2347     const point& sample,
2348     const scalar startDistSqr
2349 ) const
2351     scalar nearestDistSqr = startDistSqr;
2352     label nearestShapeI = -1;
2353     point nearestPoint;
2355     if (nodes_.size())
2356     {
2357         findNearest
2358         (
2359             0,
2360             sample,
2362             nearestDistSqr,
2363             nearestShapeI,
2364             nearestPoint
2365         );
2366     }
2367     else
2368     {
2369         nearestPoint = vector::zero;
2370     }
2372     return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2376 template <class Type>
2377 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
2379     const linePointRef& ln,
2380     treeBoundBox& tightest,
2381     point& linePoint
2382 ) const
2384     label nearestShapeI = -1;
2385     point nearestPoint;
2387     if (nodes_.size())
2388     {
2389         findNearest
2390         (
2391             0,
2392             ln,
2394             tightest,
2395             nearestShapeI,
2396             linePoint,
2397             nearestPoint
2398         );
2399     }
2400     else
2401     {
2402         nearestPoint = vector::zero;
2403     }
2405     return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2409 // Find nearest intersection
2410 template <class Type>
2411 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
2413     const point& start,
2414     const point& end
2415 ) const
2417     return findLine(false, start, end);
2421 // Find nearest intersection
2422 template <class Type>
2423 Foam::pointIndexHit Foam::indexedOctree<Type>::findLineAny
2425     const point& start,
2426     const point& end
2427 ) const
2429     return findLine(true, start, end);
2433 template <class Type>
2434 Foam::labelList Foam::indexedOctree<Type>::findBox
2436     const treeBoundBox& searchBox
2437 ) const
2439     // Storage for labels of shapes inside bb. Size estimate.
2440     labelHashSet elements(shapes_.size() / 100);
2442     if (nodes_.size())
2443     {
2444         findBox(0, searchBox, elements);
2445     }
2447     return elements.toc();
2451 // Find node (as parent+octant) containing point
2452 template <class Type>
2453 Foam::labelBits Foam::indexedOctree<Type>::findNode
2455     const label nodeI,
2456     const point& sample
2457 ) const
2459     if (nodes_.empty())
2460     {
2461         // Empty tree. Return what?
2462         return nodePlusOctant(nodeI, 0);
2463     }
2465     const node& nod = nodes_[nodeI];
2467     if (debug)
2468     {
2469         if (!nod.bb_.contains(sample))
2470         {
2471             FatalErrorIn("findNode(..)")
2472                 << "Cannot find " << sample << " in node " << nodeI
2473                 << abort(FatalError);
2474         }
2475     }
2477     direction octant = nod.bb_.subOctant(sample);
2479     labelBits index = nod.subNodes_[octant];
2481     if (isNode(index))
2482     {
2483         // Recurse
2484         return findNode(getNode(index), sample);
2485     }
2486     else if (isContent(index))
2487     {
2488         // Content. Return treenode+octant
2489         return nodePlusOctant(nodeI, octant);
2490     }
2491     else
2492     {
2493         // Empty. Return treenode+octant
2494         return nodePlusOctant(nodeI, octant);
2495     }
2499 // Determine type (inside/outside/mixed) per node.
2500 template <class Type>
2501 typename Foam::indexedOctree<Type>::volumeType
2502 Foam::indexedOctree<Type>::getVolumeType
2504     const point& sample
2505 ) const
2507     if (nodes_.empty())
2508     {
2509         return UNKNOWN;
2510     }
2512     if (nodeTypes_.size() != 8*nodes_.size())
2513     {
2514         // Calculate type for every octant of node.
2516         nodeTypes_.setSize(8*nodes_.size());
2517         nodeTypes_ = UNKNOWN;
2519         calcVolumeType(0);
2521         if (debug)
2522         {
2523             label nUNKNOWN = 0;
2524             label nMIXED = 0;
2525             label nINSIDE = 0;
2526             label nOUTSIDE = 0;
2528             forAll(nodeTypes_, i)
2529             {
2530                 volumeType type = volumeType(nodeTypes_.get(i));
2532                 if (type == UNKNOWN)
2533                 {
2534                     nUNKNOWN++;
2535                 }
2536                 else if (type == MIXED)
2537                 {
2538                     nMIXED++;
2539                 }
2540                 else if (type == INSIDE)
2541                 {
2542                     nINSIDE++;
2543                 }
2544                 else if (type == OUTSIDE)
2545                 {
2546                     nOUTSIDE++;
2547                 }
2548                 else
2549                 {
2550                     FatalErrorIn("getVolumeType") << abort(FatalError);
2551                 }
2552             }
2554             Pout<< "indexedOctree<Type>::getVolumeType : "
2555                 << " bb:" << bb()
2556                 << " nodes_:" << nodes_.size()
2557                 << " nodeTypes_:" << nodeTypes_.size()
2558                 << " nUNKNOWN:" << nUNKNOWN
2559                 << " nMIXED:" << nMIXED
2560                 << " nINSIDE:" << nINSIDE
2561                 << " nOUTSIDE:" << nOUTSIDE
2562                 << endl;
2563         }
2564     }
2566     return getVolumeType(0, sample);
2570 // Print contents of nodeI
2571 template <class Type>
2572 void Foam::indexedOctree<Type>::print
2574     prefixOSstream& os,
2575     const bool printContents,
2576     const label nodeI
2577 ) const
2579     const node& nod = nodes_[nodeI];
2580     const treeBoundBox& bb = nod.bb_;
2582     os  << "nodeI:" << nodeI << " bb:" << bb << nl
2583         << "parent:" << nod.parent_ << nl
2584         << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
2586     for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2587     {
2588         const treeBoundBox subBb(bb.subBbox(octant));
2590         labelBits index = nod.subNodes_[octant];
2592         if (isNode(index))
2593         {
2594             // tree node.
2595             label subNodeI = getNode(index);
2597             os  << "octant:" << octant
2598                 << " node: n:" << countElements(index)
2599                 << " bb:" << subBb << endl;
2601             string oldPrefix = os.prefix();
2602             os.prefix() = "  " + oldPrefix;
2604             print(os, printContents, subNodeI);
2606             os.prefix() = oldPrefix;
2607         }
2608         else if (isContent(index))
2609         {
2610             const labelList& indices = contents_[getContent(index)];
2612             os  << "octant:" << octant
2613                 << " content: n:" << indices.size()
2614                 << " bb:" << subBb;
2616             if (printContents)
2617             {
2618                 os << " contents:";
2619                 forAll(indices, j)
2620                 {
2621                     os  << ' ' << indices[j];
2622                 }
2623             }
2624             os  << endl;
2625         }
2626         else
2627         {
2628             os  << "octant:" << octant << " empty:" << subBb << endl;
2629         }
2630     }
2634 // Print contents of nodeI
2635 template <class Type>
2636 bool Foam::indexedOctree<Type>::write(Ostream& os) const
2638     os << *this;
2640     return os.good();
2644 template <class Type>
2645 Foam::Ostream& Foam::operator<<(Ostream& os, const indexedOctree<Type>& t)
2647     return
2648         os  << t.bb() << token::SPACE << t.nodes()
2649             << token::SPACE << t.contents();
2653 // ************************************************************************* //