initial commit for version 1.5.x patch release
[OpenFOAM-1.5.x.git] / src / meshTools / indexedOctree / indexedOctree.C
blobf0f8bd94d0ae149373799c8012caa2956437c792
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
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 "triSurface.H"
30 #include "meshTools.H"
31 #include "OFstream.H"
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 namespace Foam
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 indexedOctree<Type>::intersects
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 indexedOctree<Type>::intersects
89     const treeBoundBox& parentBb,
90     const direction octant,
91     const scalar nearestDistSqr,
92     const point& sample
95     //- Speeded up version of
96     //     treeBoundBox subBb(parentBb.subBbox(mid, octant))
97     //     intersects
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 intersects(mid, other, nearestDistSqr, sample);
144 // Construction helper routines
145 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148 // Split list of indices into 8 bins
149 template <class Type>
150 void 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].setSize(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         subIndices[octant].shrink();
187         result[octant].transfer(subIndices[octant]);
188         subIndices[octant].clear();
189     }
193 // Subdivide the (content) node.
194 template <class Type>
195 typename indexedOctree<Type>::node indexedOctree<Type>::divide
197     const treeBoundBox& bb,
198     DynamicList<labelList>& contents,
199     const label contentI
200 ) const
202     const labelList& indices = contents[contentI];
204     node nod;
206     if
207     (
208         bb.min()[0] >= bb.max()[0]
209      || bb.min()[1] >= bb.max()[1]
210      || bb.min()[2] >= bb.max()[2]
211     )
212     {
213         FatalErrorIn("indexedOctree<Type>::divide")
214             << "Badly formed bounding box:" << bb
215             << abort(FatalError);
216     }
218     nod.bb_ = bb;
219     nod.parent_ = -1;
221     labelListList dividedIndices(8);
222     divide(indices, bb, dividedIndices);
224     // Have now divided the indices into 8 (possibly empty) subsets.
225     // Replace current contentI with the first (non-empty) subset.
226     // Append the rest.
227     bool replaced = false;
229     for (direction octant = 0; octant < dividedIndices.size(); octant++)
230     {
231         labelList& subIndices = dividedIndices[octant];
233         if (subIndices.size() > 0)
234         {
235             if (!replaced)
236             {
237                 contents[contentI].transfer(subIndices);
238                 nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
239                 replaced = true;
240             }
241             else
242             {
243                 // Store at end of contents.
244                 // note dummy append + transfer trick
245                 label sz = contents.size();
246                 contents.append(labelList(0));
247                 contents[sz].transfer(subIndices);
248                 nod.subNodes_[octant] = contentPlusOctant(sz, octant);
249             }
250         }
251         else
252         {
253             // Mark node as empty
254             nod.subNodes_[octant] = emptyPlusOctant(octant);
255         }
256     }
258     return nod;
262 // Split any contents node with more than minSize elements.
263 template <class Type>
264 void indexedOctree<Type>::splitNodes
266     const label minSize,
267     DynamicList<indexedOctree<Type>::node>& nodes,
268     DynamicList<labelList>& contents
269 ) const
271     label currentSize = nodes.size();
273     // Take care to loop only over old nodes.
274     // Also we loop over the same DynamicList which gets modified and
275     // moved so make sure not to keep any references!
276     for (label nodeI = 0; nodeI < currentSize; nodeI++)
277     {
278         for
279         (
280             direction octant = 0;
281             octant < nodes[nodeI].subNodes_.size();
282             octant++
283         )
284         {
285             labelBits index = nodes[nodeI].subNodes_[octant];
287             if (isNode(index))
288             {
289                 // tree node. Leave intact.
290             }
291             else if (isContent(index))
292             {
293                 label contentI = getContent(index);
295                 if (contents[contentI].size() > minSize)
296                 {
297                     // Create node for content.
299                     // Find the bounding box for the subnode
300                     const node& nod = nodes[nodeI];
301                     const treeBoundBox bb(nod.bb_.subBbox(octant));
303                     node subNode(divide(bb, contents, contentI));
304                     subNode.parent_ = nodeI;
305                     label sz = nodes.size();
306                     nodes.append(subNode);
307                     nodes[nodeI].subNodes_[octant] = nodePlusOctant(sz, octant);
308                 }
309             }
310         }
311     }
315 // Reorder contents to be in same order as nodes. Returns number of nodes on
316 // the compactLevel.
317 template <class Type>
318 label indexedOctree<Type>::compactContents
320     DynamicList<node>& nodes,
321     DynamicList<labelList>& contents,
322     const label compactLevel,
323     const label nodeI,
324     const label level,
326     List<labelList>& compactedContents,
327     label& compactI
330     const node& nod = nodes[nodeI];
332     label nNodes = 0;
334     if (level < compactLevel)
335     {
336         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
337         {
338             labelBits index = nod.subNodes_[octant];
340             if (isNode(index))
341             {
342                 nNodes += compactContents
343                 (
344                     nodes,
345                     contents,
346                     compactLevel,
347                     getNode(index),
348                     level+1,
349                     compactedContents,
350                     compactI
351                 );
352             }
353         }
354     }
355     else if (level == compactLevel)
356     {
357         // Compact all content on this level
358         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
359         {
360             labelBits index = nod.subNodes_[octant];
362             if (isContent(index))
363             {
364                 label contentI = getContent(index);
366                 compactedContents[compactI].transfer(contents[contentI]);
368                 // Subnode is at compactI. Adapt nodeI to point to it
369                 nodes[nodeI].subNodes_[octant] =
370                     contentPlusOctant(compactI, octant);
372                 compactI++;
373             }
374             else if (isNode(index))
375             {
376                 nNodes++;
377             }
378         }
379     }
380     return nNodes;
384 // Pre-calculates wherever possible the volume status per node/subnode.
385 // Recurses to determine status of lowest level boxes. Level above is
386 // combination of octants below.
387 template <class Type>
388 typename indexedOctree<Type>::volumeType 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(shapes_.getVolumeType(*this, subBb.mid()));
421         }
423         // Store octant type
424         nodeTypes_.set((nodeI<<3)+octant, subType);
426         // Combine sub node types into type for treeNode. Result is 'mixed' if
427         // types differ among subnodes.
428         if (myType == UNKNOWN)
429         {
430             myType = subType;
431         }
432         else if (subType != myType)
433         {
434             myType = MIXED;
435         }
436     }
437     return myType;
441 template <class Type>
442 typename indexedOctree<Type>::volumeType indexedOctree<Type>::getVolumeType
444     const label nodeI,
445     const point& sample
446 ) const
448     const node& nod = nodes_[nodeI];
450     direction octant = nod.bb_.subOctant(sample);
452     volumeType octantType = volumeType(nodeTypes_.get((nodeI<<3)+octant));
454     if (octantType == INSIDE)
455     {
456         return octantType;
457     }
458     else if (octantType == OUTSIDE)
459     {
460         return octantType;
461     }
462     else if (octantType == UNKNOWN)
463     {
464         // Can happen for e.g. non-manifold surfaces.
465         return octantType;
466     }
467     else if (octantType == MIXED)
468     {
469         labelBits index = nod.subNodes_[octant];
471         if (isNode(index))
472         {
473             // Recurse
474             volumeType subType = getVolumeType(getNode(index), sample);
476             return subType;
477         }
478         else if (isContent(index))
479         {
480             // Content. Defer to shapes.
481             return volumeType(shapes_.getVolumeType(*this, sample));
482         }
483         else
484         {
485             // Empty node. Cannot have 'mixed' as its type since not divided
486             // up and has no items inside it.
487             FatalErrorIn
488             (
489                 "indexedOctree<Type>::getVolumeType"
490                 "(const label, const point&)"
491             )   << "Sample:" << sample << " node:" << nodeI
492                 << " with bb:" << nodes_[nodeI].bb_ << nl
493                 << "Empty subnode has invalid volume type MIXED."
494                 << abort(FatalError);
496             return UNKNOWN;
497         }
498     }
499     else
500     {
501         FatalErrorIn
502         (
503             "indexedOctree<Type>::getVolumeType"
504             "(const label, const point&)"
505         )   << "Sample:" << sample << " at node:" << nodeI
506             << " octant:" << octant
507             << " with bb:" << nod.bb_.subBbox(octant) << nl
508             << "Node has invalid volume type " << octantType
509             << abort(FatalError);
511         return UNKNOWN;
512     }
516 template <class Type>
517 typename indexedOctree<Type>::volumeType indexedOctree<Type>::getSide
519     const vector& outsideNormal,
520     const vector& vec
523     if ((outsideNormal&vec) >= 0)
524     {
525         return OUTSIDE;
526     }
527     else
528     {
529         return INSIDE;
530     }
535 // Query routines
536 // ~~~~~~~~~~~~~~
539 // Find nearest point starting from nodeI
540 template <class Type>
541 void indexedOctree<Type>::findNearest
543     const label nodeI,
544     const point& sample,
546     scalar& nearestDistSqr,
547     label& nearestShapeI,
548     point& nearestPoint
549 ) const
551     const node& nod = nodes_[nodeI];
553     // Determine order to walk through octants
554     FixedList<direction, 8> octantOrder;
555     nod.bb_.searchOrder(sample, octantOrder);
557     // Go into all suboctants (one containing sample first) and update nearest.
558     for (direction i = 0; i < 8; i++)
559     {
560         direction octant = octantOrder[i];
562         labelBits index = nod.subNodes_[octant];
564         if (isNode(index))
565         {
566             label subNodeI = getNode(index);
568             const treeBoundBox& subBb = nodes_[subNodeI].bb_;
570             if (intersects(subBb.min(), subBb.max(), nearestDistSqr, sample))
571             {
572                 findNearest
573                 (
574                     subNodeI,
575                     sample,
577                     nearestDistSqr,
578                     nearestShapeI,
579                     nearestPoint
580                 );
581             }
582         }
583         else if (isContent(index))
584         {
585             if
586             (
587                 intersects
588                 (
589                     nod.bb_,
590                     octant,
591                     nearestDistSqr,
592                     sample
593                 )
594             )
595             {
596                 shapes_.findNearest
597                 (
598                     contents_[getContent(index)],
599                     sample,
601                     nearestDistSqr,
602                     nearestShapeI,
603                     nearestPoint
604                 );
605             }
606         }
607     }
611 // Find nearest point to line.
612 template <class Type>
613 void indexedOctree<Type>::findNearest
615     const label nodeI,
616     const linePointRef& ln,
618     treeBoundBox& tightest,
619     label& nearestShapeI,
620     point& linePoint,
621     point& nearestPoint
622 ) const
624     const node& nod = nodes_[nodeI];
625     const treeBoundBox& nodeBb = nod.bb_;
627     // Determine order to walk through octants
628     FixedList<direction, 8> octantOrder;
629     nod.bb_.searchOrder(ln.centre(), octantOrder);
631     // Go into all suboctants (one containing sample first) and update nearest.
632     for (direction i = 0; i < 8; i++)
633     {
634         direction octant = octantOrder[i];
636         labelBits index = nod.subNodes_[octant];
638         if (isNode(index))
639         {
640             const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
642             if (subBb.intersects(tightest))
643             {
644                 findNearest
645                 (
646                     getNode(index),
647                     ln,
649                     tightest,
650                     nearestShapeI,
651                     linePoint,
652                     nearestPoint
653                 );
654             }
655         }
656         else if (isContent(index))
657         {
658             const treeBoundBox subBb(nodeBb.subBbox(octant));
660             if (subBb.intersects(tightest))
661             {
662                 shapes_.findNearest
663                 (
664                     contents_[getContent(index)],
665                     ln,
667                     tightest,
668                     nearestShapeI,
669                     linePoint,
670                     nearestPoint
671                 );
672             }
673         }
674     }
678 // Walk tree to neighbouring node. Gets current position as
679 // node and octant in this node and walks in the direction given by
680 // the faceID (one of treeBoundBox::LEFTBIT, RIGHTBIT etc.)
681 // Returns false if edge of tree hit.
682 template <class Type>
683 bool indexedOctree<Type>::walkToNeighbour
685     const point& facePoint,
686     const direction faceID,         // direction to walk in
687     label& nodeI,
688     direction& octant
689 ) const
691     // Find out how to test for octant. Say if we want to go left we need
692     // to traverse up the tree until we hit a node where our octant is
693     // on the right.
695     direction octantMask = 0;
696     direction valueMask = 0;
698     if ((faceID & treeBoundBox::LEFTBIT) != 0)
699     {
700         // We want to go left so check if in right octant.
701         octantMask |= treeBoundBox::RIGHTHALF;
702         valueMask |= treeBoundBox::RIGHTHALF;
703     }
704     else if ((faceID & treeBoundBox::RIGHTBIT) != 0)
705     {
706         octantMask |= treeBoundBox::RIGHTHALF;  // valueMask already 0
707     }
709     if ((faceID & treeBoundBox::BOTTOMBIT) != 0)
710     {
711         octantMask |= treeBoundBox::TOPHALF;
712         valueMask |= treeBoundBox::TOPHALF;
713     }
714     else if ((faceID & treeBoundBox::TOPBIT) != 0)
715     {
716         octantMask |= treeBoundBox::TOPHALF;
717     }
719     if ((faceID & treeBoundBox::BACKBIT) != 0)
720     {
721         octantMask |= treeBoundBox::FRONTHALF;
722         valueMask |= treeBoundBox::FRONTHALF;
723     }
724     else if ((faceID & treeBoundBox::FRONTBIT) != 0)
725     {
726         octantMask |= treeBoundBox::FRONTHALF;
727     }
729     // Go up until we have chance to cross to the wanted direction
730     while (valueMask != (octant & octantMask))
731     {
732         label parentNodeI = nodes_[nodeI].parent_;
734         if (parentNodeI == -1)
735         {
736             // Reached edge of tree
737             return false;
738         }
740         const node& parentNode = nodes_[parentNodeI];
742         // Find octant nodeI is in.
743         direction parentOctant = 255;
745         for (direction i = 0; i < parentNode.subNodes_.size(); i++)
746         {
747             labelBits index = parentNode.subNodes_[i];
749             if (isNode(index) && getNode(index) == nodeI)
750             {
751                 parentOctant = i;
752                 break;
753             }
754         }
756         if (parentOctant == 255)
757         {
758             FatalErrorIn("walkToNeighbour")
759                 << abort(FatalError);
760         }
761         nodeI = parentNodeI;
762         octant = parentOctant;
763     }
765     // So now we hit the correct parent node. Switch to the correct octant
766     octant ^= octantMask;
768     // See if we need to travel down. Note that we already go into the
769     // the first level ourselves (instead of having findNode decide) since
770     // the facePoint is now exactly on the mid of the node so there could
771     // be truncation problems.
772     labelBits index = nodes_[nodeI].subNodes_[octant];
774     if (isNode(index))
775     {
776         labelBits node = findNode(getNode(index), facePoint);
778         nodeI = getNode(node);
779         octant = getOctant(node);
780     }
782     return true;
786 // Return unique number for the face of a bounding box a point is on.
787 // (number is single bit but not really nessecary)
788 // Return 0 if point not on any face of bb.
789 template <class Type>
790 direction indexedOctree<Type>::getFace(const treeBoundBox& bb, const point& pt)
792     direction faceID = 0;
794     if (pt.x() <= bb.min().x())
795     {
796         faceID |= treeBoundBox::LEFTBIT;
797     }
798     if (pt.x() >= bb.max().x())
799     {
800         faceID |= treeBoundBox::RIGHTBIT;
801     }
803     if (pt.y() <= bb.min().y())
804     {
805         faceID |= treeBoundBox::BOTTOMBIT;
806     }
807     if (pt.y() >= bb.max().y())
808     {
809         faceID |= treeBoundBox::TOPBIT;
810     }
812     if (pt.z() <= bb.min().z())
813     {
814         faceID |= treeBoundBox::BACKBIT;
815     }
816     if (pt.z() >= bb.max().z())
817     {
818         faceID |= treeBoundBox::FRONTBIT;
819     }
820     return faceID;
824 // Traverse a node. If intersects a triangle return first intersection point.
825 // Else return the bounxing box face hit:
826 //  hitInfo.point = coordinate of intersection of ray with bounding box
827 //  faceID  = index of bounding box face
828 template <class Type>
829 void indexedOctree<Type>::traverseNode
831     const bool findAny,
832     const point& start,
833     const point& end,
834     const vector& dir,
835     const label nodeI,
836     const direction octant,
838     pointIndexHit& hitInfo,
839     direction& faceID
840 ) const
842     const node& nod = nodes_[nodeI];
844     labelBits index = nod.subNodes_[octant];
846     if (isContent(index))
847     {
848         const labelList& indices = contents_[getContent(index)];
850         if (findAny)
851         {
852             // Find any intersection
854             forAll(indices, elemI)
855             {
856                 label shapeI = indices[elemI];
858                 point pt;
859                 bool hit = shapes_.intersects(shapeI, start, end, pt);
861                 if (hit)
862                 {
863                     // Hit so pt is nearer than nearestPoint.
864                     // Update hit info
865                     hitInfo.setHit();
866                     hitInfo.setIndex(shapeI);
867                     hitInfo.setPoint(pt);
868                     return;
869                 }
870             }
871         }
872         else
873         {
874             // Find nearest intersection.
876             point nearestPoint(end);
878             forAll(indices, elemI)
879             {
880                 label shapeI = indices[elemI];
882                 point pt;
883                 bool hit = shapes_.intersects(shapeI, start, nearestPoint, pt);
885                 if (hit)
886                 {
887                     // Hit so pt is nearer than nearestPoint.
888                     nearestPoint = pt;
889                     // Update hit info
890                     hitInfo.setHit();
891                     hitInfo.setIndex(shapeI);
892                     hitInfo.setPoint(pt);
893                 }
894             }
896             if (hitInfo.hit())
897             {
898                 // Found intersected shape.
899                 return;
900             }
901         }
902     }
904     // Nothing intersected in this node
905     // Traverse to end of node. Do by ray tracing back from end and finding
906     // intersection with bounding box of node.
908     point pt;
910     if (isNode(index))
911     {
912         const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
914         if (!subBb.intersects(end, start, pt))
915         {
916             faceID = 0;
918             WarningIn("indexedOctree<Type>::traverseNode")
919                 << "Did not hit side of box " << subBb
920                 << " with ray from " << start << " to " << end
921                 << endl;
922         }
923         else
924         {
925             faceID = getFace(subBb, pt);
926         }
927     }
928     else
929     {
930         const treeBoundBox subBb(nod.bb_.subBbox(octant));
932         if (!subBb.intersects(end, start, pt))
933         {
934             faceID = 0;
936             WarningIn("indexedOctree<Type>::traverseNode")
937                 << "Did not hit side of box " << subBb
938                 << " with ray from " << start << " to " << end
939                 << endl;
940         }
941         else
942         {
943             faceID = getFace(subBb, pt);
944         }
945     }
948     // Return miss. Set misspoint to face.
949     hitInfo.setPoint(pt);
953 // Find first intersection
954 template <class Type>
955 pointIndexHit indexedOctree<Type>::findLine
957     const bool findAny,
958     const point& treeStart,
959     const point& treeEnd,
960     const label startNodeI,
961     const direction startOctant
962 ) const
964     const vector dir(treeEnd - treeStart);
966     // Current node as parent+octant
967     label nodeI = startNodeI;
968     direction octant = startOctant;
970     // Current position. Initialize to miss
971     pointIndexHit hitInfo(false, treeStart, -1);
973     // Side of current bounding box current point is on
974     direction faceID = 0;
976     while (true)
977     {
978         // Ray-trace to end of current node. Updates point (either on triangle
979         // in case of hit or on node bounding box in case of miss)
981         point startPoint(hitInfo.rawPoint());
983         traverseNode
984         (
985             findAny,
986             startPoint,     // Note: pass in copy since hitInfo
987                             // also used in return value.
988             treeEnd,
989             dir,
990             nodeI,
991             octant,
993             hitInfo,
994             faceID
995         );
997         // Did we hit a triangle?
998         if (hitInfo.hit())
999         {
1000             break;
1001         }
1003         if (faceID == 0)
1004         {
1005             // Was never inside the tree. Return miss.
1006             break;
1007         }
1009         //Pout<< "findLine : treeStart:" << treeStart
1010         //    << " treeEnd:" << treeEnd
1011         //    << " tracked from " << startPoint << " to edge of nodeBb:"
1012         //    << hitInfo.missPoint()
1013         //    << " node:" << nodeI << " octant:" << octant
1014         //    << " subBb:"
1015         //    << nodes_[nodeI].bb_.subBbox(octant)
1016         //    << endl;
1019         // Nothing hit so we are on face of bounding box (given as node+octant+
1020         // faceID). Traverse to neighbouring node.
1022         bool ok = walkToNeighbour
1023         (
1024             hitInfo.rawPoint(), // point on face
1025             faceID,             // direction to walk in
1026             nodeI,
1027             octant
1028         );
1030         if (!ok)
1031         {
1032             // Hit the edge of the tree. Return miss.
1033             break;
1034         }
1035     }
1036     return hitInfo;
1040 // Find first intersection
1041 template <class Type>
1042 pointIndexHit indexedOctree<Type>::findLine
1044     const bool findAny,
1045     const point& start,
1046     const point& end
1047 ) const
1049     pointIndexHit hitInfo;
1051     if (nodes_.size() > 0)
1052     {
1053         const treeBoundBox& treeBb = nodes_[0].bb_;
1055         direction startBit = treeBb.posBits(start);
1056         direction endBit = treeBb.posBits(end);
1058         if ((startBit & endBit) != 0)
1059         {
1060             // Both start and end outside domain and in same block.
1061             return pointIndexHit(false, vector::zero, -1);
1062         }
1064         point trackStart(start);
1065         point trackEnd(end);
1067         if (startBit != 0)
1068         {
1069             // Track start to inside domain.
1070             if (!treeBb.intersects(start, end, trackStart))
1071             {
1072                 return pointIndexHit(false, vector::zero, -1);
1073             }
1074         }
1076         if (endBit != 0)
1077         {
1078             // Track end to inside domain.
1079             if (!treeBb.intersects(end, trackStart, trackEnd))
1080             {
1081                 return pointIndexHit(false, vector::zero, -1);
1082             }
1083         }
1085         // Find lowest level tree node that start is in.
1086         labelBits index = findNode(0, trackStart);
1088         label parentNodeI = getNode(index);
1089         direction octant = getOctant(index);
1091         hitInfo = findLine
1092         (
1093             findAny,
1094             trackStart,
1095             trackEnd,
1096             parentNodeI,
1097             octant
1098         );
1099     }
1101     return hitInfo;
1105 template <class Type>
1106 void indexedOctree<Type>::findBox
1108     const label nodeI,
1109     const treeBoundBox& searchBox,
1110     labelHashSet& elements
1111 ) const
1113     const node& nod = nodes_[nodeI];
1114     const treeBoundBox& nodeBb = nod.bb_;
1116     for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
1117     {
1118         labelBits index = nod.subNodes_[octant];
1120         if (isNode(index))
1121         {
1122             const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
1124             if (subBb.intersects(searchBox))
1125             {
1126                 findBox(getNode(index), searchBox, elements);
1127             }
1128         }
1129         else if (isContent(index))
1130         {
1131             const treeBoundBox subBb(nodeBb.subBbox(octant));
1133             if (subBb.intersects(searchBox))
1134             {
1135                 const labelList& indices = contents_[getContent(index)];
1137                 forAll(indices, i)
1138                 {
1139                     label shapeI = indices[i];
1141                     if (shapes_.overlaps(shapeI, searchBox))
1142                     {
1143                         elements.insert(shapeI);
1144                     }
1145                 }
1146             }
1147         }
1148     }
1152 // Number of elements in node.
1153 template <class Type>
1154 label indexedOctree<Type>::countElements(const labelBits index) const
1156     label nElems = 0;
1158     if (isNode(index))
1159     {
1160         // tree node.
1161         label nodeI = getNode(index);
1163         const node& nod = nodes_[nodeI];
1165         for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
1166         {
1167             nElems += countElements(nod.subNodes_[octant]);
1168         }
1169     }
1170     else if (isContent(index))
1171     {
1172         nElems += contents_[getContent(index)].size();
1173     }
1174     else
1175     {
1176         // empty node
1177     }
1179     return nElems;
1183 template <class Type>
1184 void indexedOctree<Type>::writeOBJ
1186     const label nodeI,
1187     const direction octant
1188 ) const
1190     OFstream str
1191     (
1192         "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
1193     );
1195     labelBits index = nodes_[nodeI].subNodes_[octant];
1197     treeBoundBox subBb;
1199     if (isNode(index))
1200     {
1201         subBb = nodes_[getNode(index)].bb_;
1202     }
1203     else if (isContent(index))
1204     {
1205         subBb = nodes_[nodeI].bb_.subBbox(octant);
1206     }
1208     Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
1209         << " to " << str.name() << endl;
1211     label vertI = 0;
1213     // Dump bounding box
1214     pointField bbPoints(subBb.points());
1216     label pointVertI = vertI;
1217     forAll(bbPoints, i)
1218     {
1219         meshTools::writeOBJ(str, bbPoints[i]);
1220         vertI++;
1221     }
1223     forAll(treeBoundBox::edges, i)
1224     {
1225         const edge& e = treeBoundBox::edges[i];
1227         str<< "l " << e[0]+pointVertI+1 << ' ' << e[1]+pointVertI+1 << nl;
1228     }
1231     //// Dump triangles
1232     //if (isContent(index))
1233     //{
1234     //    const labelList& indices = contents_[getContent(index)];
1235     //    const triSurface& surf = shapes_.surface();
1236     //    const pointField& points = surf.points();
1237     //
1238     //    forAll(indices, i)
1239     //    {
1240     //        label shapeI = indices[i];
1241     //
1242     //        const labelledTri& f = surf[shapeI];
1243     //
1244     //        meshTools::writeOBJ(str, points[f[0]]);
1245     //        vertI++;
1246     //        meshTools::writeOBJ(str, points[f[1]]);
1247     //        vertI++;
1248     //        meshTools::writeOBJ(str, points[f[2]]);
1249     //        vertI++;
1250     //
1251     //        str<< "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI << ' '
1252     //            << vertI-2 << nl;
1253     //    }
1254     //}
1258 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
1260 template <class Type>
1261 indexedOctree<Type>::indexedOctree(const Type& shapes)
1263     shapes_(shapes),
1264     nodes_(0),
1265     contents_(0),
1266     nodeTypes_(0)
1270 template <class Type>
1271 indexedOctree<Type>::indexedOctree
1273     const Type& shapes,
1274     const List<node>& nodes,
1275     const labelListList& contents
1278     shapes_(shapes),
1279     nodes_(nodes),
1280     contents_(contents),
1281     nodeTypes_(0)
1285 template <class Type>
1286 indexedOctree<Type>::indexedOctree
1288     const Type& shapes,
1289     const treeBoundBox& bb,
1290     const label maxLevels,          // maximum number of levels
1291     const scalar maxLeafRatio,
1292     const scalar maxDuplicity
1295     shapes_(shapes),
1296     nodes_(0),
1297     contents_(0),
1298     nodeTypes_(0)
1300     if (shapes.size() == 0)
1301     {
1302         return;
1303     }
1305     // Start off with one node with all shapes in it.
1306     DynamicList<node> nodes(label(shapes.size() / maxLeafRatio));
1307     DynamicList<labelList> contents(label(shapes.size() / maxLeafRatio));
1308     contents.append(identity(shapes.size()));
1310     // Create topnode.
1311     node topNode(divide(bb, contents, 0));
1312     nodes.append(topNode);
1315     // Now have all contents at level 1. Create levels by splitting levels
1316     // above.
1318     label nLevels = 1;
1320     for (; nLevels < maxLevels; nLevels++)
1321     {
1322         // Count number of references into shapes (i.e. contents)
1323         label nEntries = 0;
1324         forAll(contents, i)
1325         {
1326             nEntries += contents[i].size();
1327         }
1329         if (debug)
1330         {
1331             Pout<< "indexedOctree<Type>::indexedOctree:" << nl
1332                 << "    nLevels:" << nLevels << nl
1333                 << "    nEntries per treeLeaf:" << nEntries/contents.size()
1334                 << nl
1335                 << "    nEntries per shape (duplicity):"
1336                 << nEntries/shapes.size()
1337                 << nl
1338                 << endl;
1339         }
1341         if
1342         (
1343             //nEntries < maxLeafRatio*contents.size()
1344          // ||
1345             nEntries > maxDuplicity*shapes.size()
1346         )
1347         {
1348             break;
1349         }
1352         // Split nodes with more than maxLeafRatio elements
1353         label nOldNodes = nodes.size();
1354         splitNodes
1355         (
1356             label(maxLeafRatio),
1357             nodes,
1358             contents
1359         );
1361         if (nOldNodes == nodes.size())
1362         {
1363             break;
1364         }
1365     }
1367     // Shrink
1368     nodes.shrink();
1369     contents.shrink();
1372     // Compact such that deeper level contents are always after the
1373     // ones for a shallower level. This way we can slice a coarser level
1374     // off the tree.
1375     contents_.setSize(contents.size());
1376     label compactI = 0;
1378     label level = 0;
1380     while (true)
1381     {
1382         compactContents
1383         (
1384             nodes,
1385             contents,
1386             level,
1387             0,
1388             0,
1389             contents_,
1390             compactI
1391         );
1393         if (compactI == contents_.size())
1394         {
1395             // Transferred all contents to contents_ (in order breadth first)
1396             break;
1397         }
1399         level++;
1400     }
1401     nodes_.transfer(nodes);
1402     nodes.clear();
1405     if (debug)
1406     {
1407         label nEntries = 0;
1408         forAll(contents_, i)
1409         {
1410             nEntries += contents_[i].size();
1411         }
1413         Pout<< "indexedOctree<Type>::indexedOctree : finished construction:"
1414             << nl
1415             << "    shapes:" << shapes.size() << nl
1416             << "    nLevels:" << nLevels << nl
1417             << "    treeNodes:" << nodes_.size() << nl
1418             << "    nEntries:" << nEntries << nl
1419             << "        per treeLeaf:" << nEntries/contents.size() << nl
1420             << "        per shape (duplicity):" << nEntries/shapes.size() << nl
1421             << endl;
1422     }
1426 template <class Type>
1427 indexedOctree<Type>::indexedOctree
1429     const Type& shapes,
1430     Istream& is
1433     shapes_(shapes),
1434     nodes_(is),
1435     contents_(is),
1436     nodeTypes_(0)
1440 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
1442 template <class Type>
1443 pointIndexHit indexedOctree<Type>::findNearest
1445     const point& sample,
1446     const scalar startDistSqr
1447 ) const
1449     scalar nearestDistSqr = startDistSqr;
1450     label nearestShapeI = -1;
1451     point nearestPoint;
1453     if (nodes_.size() == 0)
1454     {
1455         nearestPoint = vector::zero;
1456     }
1457     else
1458     {
1459         findNearest
1460         (
1461             0,
1462             sample,
1464             nearestDistSqr,
1465             nearestShapeI,
1466             nearestPoint
1467         );
1468     }
1470     return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
1474 template <class Type>
1475 pointIndexHit indexedOctree<Type>::findNearest
1477     const linePointRef& ln,
1478     treeBoundBox& tightest,
1479     point& linePoint
1480 ) const
1482     label nearestShapeI = -1;
1483     point nearestPoint;
1485     if (nodes_.size() == 0)
1486     {
1487         nearestPoint = vector::zero;
1488     }
1489     else
1490     {
1491         findNearest
1492         (
1493             0,
1494             ln,
1496             tightest,
1497             nearestShapeI,
1498             linePoint,
1499             nearestPoint
1500         );
1501     }
1503     return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
1507 // Find nearest intersection
1508 template <class Type>
1509 pointIndexHit indexedOctree<Type>::findLine
1511     const point& start,
1512     const point& end
1513 ) const
1515     return findLine(false, start, end);
1519 // Find nearest intersection
1520 template <class Type>
1521 pointIndexHit indexedOctree<Type>::findLineAny
1523     const point& start,
1524     const point& end
1525 ) const
1527     return findLine(true, start, end);
1531 template <class Type>
1532 labelList indexedOctree<Type>::findBox(const boundBox& searchBox) const
1534     // Storage for labels of shapes inside bb. Size estimate.
1535     labelHashSet elements(shapes_.size() / 100);
1537     if (nodes_.size() > 0)
1538     {
1539         findBox(0, searchBox, elements);
1540     }
1542     return elements.toc();
1546 // Find node (as parent+octant) containing point
1547 template <class Type>
1548 labelBits indexedOctree<Type>::findNode
1550     const label nodeI,
1551     const point& sample
1552 ) const
1554     if (nodes_.size() == 0)
1555     {
1556         // Empty tree. Return what?
1557         return nodePlusOctant(nodeI, 0);
1558     }
1560     const node& nod = nodes_[nodeI];
1562     direction octant = nod.bb_.subOctant(sample);
1564     labelBits index = nod.subNodes_[octant];
1566     if (isNode(index))
1567     {
1568         // Recurse
1569         return findNode(getNode(index), sample);
1570     }
1571     else if (isContent(index))
1572     {
1573         // Content. Return treenode+octant
1574         return nodePlusOctant(nodeI, octant);
1575     }
1576     else
1577     {
1578         // Empty. Return treenode+octant
1579         return nodePlusOctant(nodeI, octant);
1580     }
1584 // Determine type (inside/outside/mixed) per node.
1585 template <class Type>
1586 typename indexedOctree<Type>::volumeType indexedOctree<Type>::getVolumeType
1588     const point& sample
1589 ) const
1591     if (nodes_.size() == 0)
1592     {
1593         return UNKNOWN;
1594     }
1596     if (nodeTypes_.size() != 8*nodes_.size())
1597     {
1598         // Calculate type for every octant of node.
1600         nodeTypes_.setSize(8*nodes_.size());
1601         nodeTypes_ = UNKNOWN;
1603         calcVolumeType(0);
1605         if (debug)
1606         {
1607             label nUNKNOWN = 0;
1608             label nMIXED = 0;
1609             label nINSIDE = 0;
1610             label nOUTSIDE = 0;
1612             forAll(nodeTypes_, i)
1613             {
1614                 volumeType type = volumeType(nodeTypes_.get(i));
1616                 if (type == UNKNOWN)
1617                 {
1618                     nUNKNOWN++;
1619                 }
1620                 else if (type == MIXED)
1621                 {
1622                     nMIXED++;
1623                 }
1624                 else if (type == INSIDE)
1625                 {
1626                     nINSIDE++;
1627                 }
1628                 else if (type == OUTSIDE)
1629                 {
1630                     nOUTSIDE++;
1631                 }
1632                 else
1633                 {
1634                     FatalErrorIn("getVolumeType") << abort(FatalError);
1635                 }
1636             }
1638             Pout<< "indexedOctree<Type>::getVolumeType : "
1639                 << " bb:" << bb()
1640                 << " nodes_:" << nodes_.size()
1641                 << " nodeTypes_:" << nodeTypes_.size()
1642                 << " nUNKNOWN:" << nUNKNOWN
1643                 << " nMIXED:" << nMIXED
1644                 << " nINSIDE:" << nINSIDE
1645                 << " nOUTSIDE:" << nOUTSIDE
1646                 << endl;
1647         }
1648     }
1650     return getVolumeType(0, sample);
1654 // Print contents of nodeI
1655 template <class Type>
1656 void indexedOctree<Type>::print
1658     prefixOSstream& os,
1659     const bool printContents,
1660     const label nodeI
1661 ) const
1663     const node& nod = nodes_[nodeI];
1664     const treeBoundBox& bb = nod.bb_;
1666     os  << "nodeI:" << nodeI << " bb:" << bb << nl
1667         << "parent:" << nod.parent_ << nl
1668         << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
1670     for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
1671     {
1672         const treeBoundBox subBb(bb.subBbox(octant));
1674         labelBits index = nod.subNodes_[octant];
1676         if (isNode(index))
1677         {
1678             // tree node.
1679             label subNodeI = getNode(index);
1681             os  << "octant:" << octant
1682                 << " node: n:" << countElements(index)
1683                 << " bb:" << subBb << endl;
1685             string oldPrefix = os.prefix();
1686             os.prefix() = "  " + oldPrefix;
1688             print(os, printContents, subNodeI);
1690             os.prefix() = oldPrefix;
1691         }
1692         else if (isContent(index))
1693         {
1694             const labelList& indices = contents_[getContent(index)];
1696             os  << "octant:" << octant
1697                 << " content: n:" << indices.size()
1698                 << " bb:" << subBb;
1700             if (printContents)
1701             {
1702                 os << " contents:";
1703                 forAll(indices, j)
1704                 {
1705                     os  << ' ' << indices[j];
1706                 }
1707             }
1708             os  << endl;
1709         }
1710         else
1711         {
1712             os  << "octant:" << octant << " empty:" << subBb << endl;
1713         }
1714     }
1718 // Print contents of nodeI
1719 template <class Type>
1720 bool indexedOctree<Type>::write(Ostream& os) const
1722     os << *this;
1724     return os.good();
1728 template <class Type>
1729 Ostream& operator<<(Ostream& os, const indexedOctree<Type>& t)
1731     return
1732         os  << t.bb() << token::SPACE << t.nodes()
1733             << token::SPACE << t.contents();
1737 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1739 } // End namespace Foam
1741 // ************************************************************************* //