indexedOctree.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
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.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "indexedOctree.H"
27 #include "linePointRef.H"
28 #include "OFstream.H"
29 #include "ListOps.H"
30 #include "memInfo.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 template<class Type>
35 Foam::scalar Foam::indexedOctree<Type>::perturbTol_ = 10*SMALL;
36 
37 
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 
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>
44 (
45  const point& p0,
46  const point& p1,
47  const scalar nearestDistSqr,
48  const point& sample
49 )
50 {
51  boundBox bb(p0, p1);
52 
53  return bb.overlaps(sample, nearestDistSqr);
54 }
55 
56 
57 // Does bb intersect a sphere around sample? Or is any corner point of bb
58 // closer than nearestDistSqr to sample.
59 template<class Type>
61 (
62  const treeBoundBox& parentBb,
63  const direction octant,
64  const scalar nearestDistSqr,
65  const point& sample
66 )
67 {
68  //- Accelerated version of
69  // treeBoundBox subBb(parentBb.subBbox(mid, octant))
70  // overlaps
71  // (
72  // subBb.min(),
73  // subBb.max(),
74  // nearestDistSqr,
75  // sample
76  // )
77 
78  const point& min = parentBb.min();
79  const point& max = parentBb.max();
80 
81  point other;
82 
83  if (octant & treeBoundBox::RIGHTHALF)
84  {
85  other.x() = max.x();
86  }
87  else
88  {
89  other.x() = min.x();
90  }
91 
92  if (octant & treeBoundBox::TOPHALF)
93  {
94  other.y() = max.y();
95  }
96  else
97  {
98  other.y() = min.y();
99  }
100 
101  if (octant & treeBoundBox::FRONTHALF)
102  {
103  other.z() = max.z();
104  }
105  else
106  {
107  other.z() = min.z();
108  }
109 
110  const point mid(0.5*(min+max));
111 
112  return overlaps(mid, other, nearestDistSqr, sample);
113 }
114 
115 
116 //
117 // Construction helper routines
118 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
119 //
120 
121 // Split list of indices into 8 bins
122 template<class Type>
124 (
125  const labelList& indices,
126  const treeBoundBox& bb,
127  labelListList& result
128 ) const
129 {
130  List<DynamicList<label> > subIndices(8);
131  for (direction octant = 0; octant < subIndices.size(); octant++)
132  {
133  subIndices[octant].setCapacity(indices.size()/8);
134  }
135 
136  // Precalculate bounding boxes.
138  for (direction octant = 0; octant < subBbs.size(); octant++)
139  {
140  subBbs[octant] = bb.subBbox(octant);
141  }
142 
143  forAll(indices, i)
144  {
145  label shapeI = indices[i];
146 
147  for (direction octant = 0; octant < 8; octant++)
148  {
149  if (shapes_.overlaps(shapeI, subBbs[octant]))
150  {
151  subIndices[octant].append(shapeI);
152  }
153  }
154  }
155 
156  result.setSize(8);
157  for (direction octant = 0; octant < subIndices.size(); octant++)
158  {
159  result[octant].transfer(subIndices[octant]);
160  }
161 }
162 
163 
164 // Subdivide the (content) node.
165 template<class Type>
168 (
169  const treeBoundBox& bb,
170  DynamicList<labelList>& contents,
171  const label contentI
172 ) const
173 {
174  const labelList& indices = contents[contentI];
175 
176  node nod;
177 
178  vector const diag = bb.max() - bb.min();
179  scalar const tol = std::max(SMALL, mag(diag) * SMALL);
180 
181  if
182  (
183  bb.min()[0] >= bb.max()[0] + tol
184  || bb.min()[1] >= bb.max()[1] + tol
185  || bb.min()[2] >= bb.max()[2] + tol
186  )
187  {
189  << "Badly formed bounding box:" << bb
190  << abort(FatalError);
191  }
192 
193  nod.bb_ = bb;
194  nod.parent_ = -1;
195 
196  labelListList dividedIndices(8);
197  divide(indices, bb, dividedIndices);
198 
199  // Have now divided the indices into 8 (possibly empty) subsets.
200  // Replace current contentI with the first (non-empty) subset.
201  // Append the rest.
202  bool replaced = false;
203 
204  for (direction octant = 0; octant < dividedIndices.size(); octant++)
205  {
206  labelList& subIndices = dividedIndices[octant];
207 
208  if (subIndices.size())
209  {
210  if (!replaced)
211  {
212  contents[contentI].transfer(subIndices);
213  nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
214  replaced = true;
215  }
216  else
217  {
218  // Store at end of contents.
219  // note dummy append + transfer trick
220  label sz = contents.size();
221  contents.append(labelList(0));
222  contents[sz].transfer(subIndices);
223  nod.subNodes_[octant] = contentPlusOctant(sz, octant);
224  }
225  }
226  else
227  {
228  // Mark node as empty
229  nod.subNodes_[octant] = emptyPlusOctant(octant);
230  }
231  }
232 
233  return nod;
234 }
235 
236 
237 // Split any contents node with more than minSize elements.
238 template<class Type>
240 (
241  const label minSize,
243  DynamicList<labelList>& contents
244 ) const
245 {
246  label currentSize = nodes.size();
247 
248  // Take care to loop only over old nodes.
249  // Also we loop over the same DynamicList which gets modified and
250  // moved so make sure not to keep any references!
251  for (label nodeI = 0; nodeI < currentSize; nodeI++)
252  {
253  for
254  (
255  direction octant = 0;
256  octant < nodes[nodeI].subNodes_.size();
257  octant++
258  )
259  {
260  labelBits index = nodes[nodeI].subNodes_[octant];
261 
262  if (isNode(index))
263  {
264  // tree node. Leave intact.
265  }
266  else if (isContent(index))
267  {
268  label contentI = getContent(index);
269 
270  if (contents[contentI].size() > minSize)
271  {
272  // Create node for content.
273 
274  // Find the bounding box for the subnode
275  const node& nod = nodes[nodeI];
276  const treeBoundBox bb(nod.bb_.subBbox(octant));
277 
278  node subNode(divide(bb, contents, contentI));
279  subNode.parent_ = nodeI;
280  label sz = nodes.size();
281  nodes.append(subNode);
282  nodes[nodeI].subNodes_[octant] = nodePlusOctant(sz, octant);
283  }
284  }
285  }
286  }
287 }
288 
289 
290 // Reorder contents to be in same order as nodes. Returns number of nodes on
291 // the compactLevel.
292 template<class Type>
294 (
295  DynamicList<node>& nodes,
296  DynamicList<labelList>& contents,
297  const label compactLevel,
298  const label nodeI,
299  const label level,
300 
301  List<labelList>& compactedContents,
302  label& compactI
303 )
304 {
305  const node& nod = nodes[nodeI];
306 
307  label nNodes = 0;
308 
309  if (level < compactLevel)
310  {
311  for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
312  {
313  labelBits index = nod.subNodes_[octant];
314 
315  if (isNode(index))
316  {
317  nNodes += compactContents
318  (
319  nodes,
320  contents,
321  compactLevel,
322  getNode(index),
323  level+1,
324  compactedContents,
325  compactI
326  );
327  }
328  }
329  }
330  else if (level == compactLevel)
331  {
332  // Compact all content on this level
333  for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
334  {
335  labelBits index = nod.subNodes_[octant];
336 
337  if (isContent(index))
338  {
339  label contentI = getContent(index);
340 
341  compactedContents[compactI].transfer(contents[contentI]);
342 
343  // Subnode is at compactI. Adapt nodeI to point to it
344  nodes[nodeI].subNodes_[octant] =
345  contentPlusOctant(compactI, octant);
346 
347  compactI++;
348  }
349  else if (isNode(index))
350  {
351  nNodes++;
352  }
353  }
354  }
355  return nNodes;
356 }
357 
358 
359 // Pre-calculates wherever possible the volume status per node/subnode.
360 // Recurses to determine status of lowest level boxes. Level above is
361 // combination of octants below.
362 template<class Type>
364 (
365  const label nodeI
366 ) const
367 {
368  const node& nod = nodes_[nodeI];
369 
370  volumeType myType = volumeType::UNKNOWN;
371 
372  for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
373  {
374  volumeType subType;
375 
376  labelBits index = nod.subNodes_[octant];
377 
378  if (isNode(index))
379  {
380  // tree node. Recurse.
381  subType = calcVolumeType(getNode(index));
382  }
383  else if (isContent(index))
384  {
385  // Contents. Depending on position in box might be on either
386  // side.
387  subType = volumeType::MIXED;
388  }
389  else
390  {
391  // No data in this octant. Set type for octant acc. to the mid
392  // of its bounding box.
393  const treeBoundBox subBb = nod.bb_.subBbox(octant);
394 
395  subType = shapes_.getVolumeType(*this, subBb.midpoint());
396  }
397 
398  // Store octant type
399  nodeTypes_.set((nodeI<<3)+octant, subType);
400 
401  // Combine sub node types into type for treeNode. Result is 'mixed' if
402  // types differ among subnodes.
403  if (myType == volumeType::UNKNOWN)
404  {
405  myType = subType;
406  }
407  else if (subType != myType)
408  {
409  myType = volumeType::MIXED;
410  }
411  }
412  return myType;
413 }
414 
415 
416 template<class Type>
418 (
419  const label nodeI,
420  const point& sample
421 ) const
422 {
423  const node& nod = nodes_[nodeI];
424 
425  direction octant = nod.bb_.subOctant(sample);
426 
427  volumeType octantType = volumeType::type(nodeTypes_.get((nodeI<<3)+octant));
428 
429  if (octantType == volumeType::INSIDE)
430  {
431  return octantType;
432  }
433  else if (octantType == volumeType::OUTSIDE)
434  {
435  return octantType;
436  }
437  else if (octantType == volumeType::UNKNOWN)
438  {
439  // Can happen for e.g. non-manifold surfaces.
440  return octantType;
441  }
442  else if (octantType == volumeType::MIXED)
443  {
444  labelBits index = nod.subNodes_[octant];
445 
446  if (isNode(index))
447  {
448  // Recurse
449  volumeType subType = getVolumeType(getNode(index), sample);
450 
451  return subType;
452  }
453  else if (isContent(index))
454  {
455  // Content. Defer to shapes.
456  return volumeType(shapes_.getVolumeType(*this, sample));
457  }
458  else
459  {
460  // Empty node. Cannot have 'mixed' as its type since not divided
461  // up and has no items inside it.
463  << "Sample:" << sample << " node:" << nodeI
464  << " with bb:" << nodes_[nodeI].bb_ << nl
465  << "Empty subnode has invalid volume type MIXED."
466  << abort(FatalError);
467 
468  return volumeType::UNKNOWN;
469  }
470  }
471  else
472  {
474  << "Sample:" << sample << " at node:" << nodeI
475  << " octant:" << octant
476  << " with bb:" << nod.bb_.subBbox(octant) << nl
477  << "Node has invalid volume type " << octantType
478  << abort(FatalError);
479 
480  return volumeType::UNKNOWN;
481  }
482 }
483 
484 
485 template<class Type>
487 (
488  const vector& outsideNormal,
489  const vector& vec
490 )
491 {
492  if ((outsideNormal&vec) >= 0)
493  {
494  return volumeType::OUTSIDE;
495  }
496  else
497  {
498  return volumeType::INSIDE;
499  }
500 }
501 
502 
503 //
504 // Query routines
505 // ~~~~~~~~~~~~~~
506 //
507 
508 
509 // Find nearest point starting from nodeI
510 template<class Type>
511 template<class FindNearestOp>
513 (
514  const label nodeI,
515  const point& sample,
516 
517  scalar& nearestDistSqr,
518  label& nearestShapeI,
519  point& nearestPoint,
520 
521  const FindNearestOp& fnOp
522 ) const
523 {
524  const node& nod = nodes_[nodeI];
525 
526  // Determine order to walk through octants
527  FixedList<direction, 8> octantOrder;
528  nod.bb_.searchOrder(sample, octantOrder);
529 
530  // Go into all suboctants (one containing sample first) and update nearest.
531  for (direction i = 0; i < 8; i++)
532  {
533  direction octant = octantOrder[i];
534 
535  labelBits index = nod.subNodes_[octant];
536 
537  if (isNode(index))
538  {
539  label subNodeI = getNode(index);
540 
541  const treeBoundBox& subBb = nodes_[subNodeI].bb_;
542 
543  if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
544  {
545  findNearest
546  (
547  subNodeI,
548  sample,
549 
550  nearestDistSqr,
551  nearestShapeI,
552  nearestPoint,
553 
554  fnOp
555  );
556  }
557  }
558  else if (isContent(index))
559  {
560  if
561  (
562  overlaps
563  (
564  nod.bb_,
565  octant,
566  nearestDistSqr,
567  sample
568  )
569  )
570  {
571  fnOp
572  (
573  contents_[getContent(index)],
574  sample,
575 
576  nearestDistSqr,
577  nearestShapeI,
578  nearestPoint
579  );
580  }
581  }
582  }
583 }
584 
585 
586 // Find nearest point to line.
587 template<class Type>
588 template<class FindNearestOp>
590 (
591  const label nodeI,
592  const linePointRef& ln,
593 
594  treeBoundBox& tightest,
595  label& nearestShapeI,
596  point& linePoint,
597  point& nearestPoint,
598 
599  const FindNearestOp& fnOp
600 ) const
601 {
602  const node& nod = nodes_[nodeI];
603  const treeBoundBox& nodeBb = nod.bb_;
604 
605  // Determine order to walk through octants
606  FixedList<direction, 8> octantOrder;
607  nod.bb_.searchOrder(ln.centre(), octantOrder);
608 
609  // Go into all suboctants (one containing sample first) and update nearest.
610  for (direction i = 0; i < 8; i++)
611  {
612  direction octant = octantOrder[i];
613 
614  labelBits index = nod.subNodes_[octant];
615 
616  if (isNode(index))
617  {
618  const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
619 
620  if (subBb.overlaps(tightest))
621  {
622  findNearest
623  (
624  getNode(index),
625  ln,
626 
627  tightest,
628  nearestShapeI,
629  linePoint,
630  nearestPoint,
631 
632  fnOp
633  );
634  }
635  }
636  else if (isContent(index))
637  {
638  const treeBoundBox subBb(nodeBb.subBbox(octant));
639 
640  if (subBb.overlaps(tightest))
641  {
642  fnOp
643  (
644  contents_[getContent(index)],
645  ln,
646 
647  tightest,
648  nearestShapeI,
649  linePoint,
650  nearestPoint
651  );
652  }
653  }
654  }
655 }
656 
657 
658 template<class Type>
660 (
661  const label parentNodeI,
662  const direction octant
663 ) const
664 {
665  // Get type of node at octant
666  const node& nod = nodes_[parentNodeI];
667  labelBits index = nod.subNodes_[octant];
668 
669  if (isNode(index))
670  {
671  // Use stored bb
672  return nodes_[getNode(index)].bb_;
673  }
674  else
675  {
676  // Calculate subBb
677  return nod.bb_.subBbox(octant);
678  }
679 }
680 
681 
682 // Takes a bb and a point on/close to the edge of the bb and pushes the point
683 // inside by a small fraction.
684 template<class Type>
686 (
687  const treeBoundBox& bb,
688  const point& pt,
689  const bool pushInside
690 )
691 {
692  // Get local length scale.
693  const vector perturbVec = perturbTol_*bb.span();
694 
695  point perturbedPt(pt);
696 
697  // Modify all components which are close to any face of the bb to be
698  // well inside/outside them.
699 
700  if (pushInside)
701  {
702  for (direction dir = 0; dir < vector::nComponents; dir++)
703  {
704  if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
705  {
706  // Close to 'left' side. Push well beyond left side.
707  scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
708  perturbedPt[dir] = bb.min()[dir] + perturbDist;
709  }
710  else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
711  {
712  // Close to 'right' side. Push well beyond right side.
713  scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
714  perturbedPt[dir] = bb.max()[dir] - perturbDist;
715  }
716  }
717  }
718  else
719  {
720  for (direction dir = 0; dir < vector::nComponents; dir++)
721  {
722  if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
723  {
724  scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
725  perturbedPt[dir] = bb.min()[dir] - perturbDist;
726  }
727  else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
728  {
729  scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
730  perturbedPt[dir] = bb.max()[dir] + perturbDist;
731  }
732  }
733  }
734 
735  if (debug)
736  {
737  if (pushInside != bb.contains(perturbedPt))
738  {
740  << "pushed point:" << pt
741  << " to:" << perturbedPt
742  << " wanted side:" << pushInside
743  << " obtained side:" << bb.contains(perturbedPt)
744  << " of bb:" << bb
745  << abort(FatalError);
746  }
747  }
748 
749  return perturbedPt;
750 }
751 
752 
753 // Takes a bb and a point on the edge of the bb and pushes the point
754 // outside by a small fraction.
755 template<class Type>
757 (
758  const treeBoundBox& bb,
759  const direction faceID,
760  const point& pt,
761  const bool pushInside
762 )
763 {
764  // Get local length scale.
765  const vector perturbVec = perturbTol_*bb.span();
766 
767  point perturbedPt(pt);
768 
769  // Modify all components which are close to any face of the bb to be
770  // well outside them.
771 
772  if (faceID == 0)
773  {
775  << abort(FatalError);
776  }
777 
778  if (faceID & treeBoundBox::LEFTBIT)
779  {
780  if (pushInside)
781  {
782  perturbedPt[0] = bb.min()[0] + (perturbVec[0] + ROOTVSMALL);
783  }
784  else
785  {
786  perturbedPt[0] = bb.min()[0] - (perturbVec[0] + ROOTVSMALL);
787  }
788  }
789  else if (faceID & treeBoundBox::RIGHTBIT)
790  {
791  if (pushInside)
792  {
793  perturbedPt[0] = bb.max()[0] - (perturbVec[0] + ROOTVSMALL);
794  }
795  else
796  {
797  perturbedPt[0] = bb.max()[0] + (perturbVec[0] + ROOTVSMALL);
798  }
799  }
800 
801  if (faceID & treeBoundBox::BOTTOMBIT)
802  {
803  if (pushInside)
804  {
805  perturbedPt[1] = bb.min()[1] + (perturbVec[1] + ROOTVSMALL);
806  }
807  else
808  {
809  perturbedPt[1] = bb.min()[1] - (perturbVec[1] + ROOTVSMALL);
810  }
811  }
812  else if (faceID & treeBoundBox::TOPBIT)
813  {
814  if (pushInside)
815  {
816  perturbedPt[1] = bb.max()[1] - (perturbVec[1] + ROOTVSMALL);
817  }
818  else
819  {
820  perturbedPt[1] = bb.max()[1] + (perturbVec[1] + ROOTVSMALL);
821  }
822  }
823 
824  if (faceID & treeBoundBox::BACKBIT)
825  {
826  if (pushInside)
827  {
828  perturbedPt[2] = bb.min()[2] + (perturbVec[2] + ROOTVSMALL);
829  }
830  else
831  {
832  perturbedPt[2] = bb.min()[2] - (perturbVec[2] + ROOTVSMALL);
833  }
834  }
835  else if (faceID & treeBoundBox::FRONTBIT)
836  {
837  if (pushInside)
838  {
839  perturbedPt[2] = bb.max()[2] - (perturbVec[2] + ROOTVSMALL);
840  }
841  else
842  {
843  perturbedPt[2] = bb.max()[2] + (perturbVec[2] + ROOTVSMALL);
844  }
845  }
846 
847  if (debug)
848  {
849  if (pushInside != bb.contains(perturbedPt))
850  {
852  << "pushed point:" << pt << " on face:" << faceString(faceID)
853  << " to:" << perturbedPt
854  << " wanted side:" << pushInside
855  << " obtained side:" << bb.contains(perturbedPt)
856  << " of bb:" << bb
857  << abort(FatalError);
858  }
859  }
860 
861  return perturbedPt;
862 }
863 
864 
865 // Guarantees that if pt is on a face it gets perturbed so it is away
866 // from the face edges.
867 // If pt is not on a face does nothing.
868 template<class Type>
870 (
871  const treeBoundBox& bb,
872  const vector& dir, // end-start
873  const point& pt
874 )
875 {
876  if (debug)
877  {
878  if (bb.posBits(pt) != 0)
879  {
881  << " bb:" << bb << endl
882  << "does not contain point " << pt << abort(FatalError);
883  }
884  }
885 
886 
887  // Handle two cases:
888  // - point exactly on multiple faces. Push away from all but one.
889  // - point on a single face. Push away from edges of face.
890 
891  direction ptFaceID = bb.faceBits(pt);
892 
893  direction nFaces = 0;
894  FixedList<direction, 3> faceIndices;
895 
896  if (ptFaceID & treeBoundBox::LEFTBIT)
897  {
898  faceIndices[nFaces++] = treeBoundBox::LEFT;
899  }
900  else if (ptFaceID & treeBoundBox::RIGHTBIT)
901  {
902  faceIndices[nFaces++] = treeBoundBox::RIGHT;
903  }
904 
905  if (ptFaceID & treeBoundBox::BOTTOMBIT)
906  {
907  faceIndices[nFaces++] = treeBoundBox::BOTTOM;
908  }
909  else if (ptFaceID & treeBoundBox::TOPBIT)
910  {
911  faceIndices[nFaces++] = treeBoundBox::TOP;
912  }
913 
914  if (ptFaceID & treeBoundBox::BACKBIT)
915  {
916  faceIndices[nFaces++] = treeBoundBox::BACK;
917  }
918  else if (ptFaceID & treeBoundBox::FRONTBIT)
919  {
920  faceIndices[nFaces++] = treeBoundBox::FRONT;
921  }
922 
923 
924  // Determine the face we want to keep the point on
925 
926  direction keepFaceID;
927 
928  if (nFaces == 0)
929  {
930  // Return original point
931  return pt;
932  }
933  else if (nFaces == 1)
934  {
935  // Point is on a single face
936  keepFaceID = faceIndices[0];
937  }
938  else
939  {
940  // Determine best face out of faceIndices[0 .. nFaces-1].
941  // The best face is the one most perpendicular to the ray direction.
942 
943  keepFaceID = faceIndices[0];
944  scalar maxInproduct = mag(treeBoundBox::faceNormals[keepFaceID] & dir);
945 
946  for (direction i = 1; i < nFaces; i++)
947  {
948  direction face = faceIndices[i];
949  scalar s = mag(treeBoundBox::faceNormals[face] & dir);
950  if (s > maxInproduct)
951  {
952  maxInproduct = s;
953  keepFaceID = face;
954  }
955  }
956  }
957 
958 
959  // 1. Push point into bb, away from all corners
960 
961  point facePoint(pushPoint(bb, pt, true));
962  direction faceID = 0;
963 
964  // 2. Snap it back onto the preferred face
965 
966  if (keepFaceID == treeBoundBox::LEFT)
967  {
968  facePoint.x() = bb.min().x();
969  faceID = treeBoundBox::LEFTBIT;
970  }
971  else if (keepFaceID == treeBoundBox::RIGHT)
972  {
973  facePoint.x() = bb.max().x();
974  faceID = treeBoundBox::RIGHTBIT;
975  }
976  else if (keepFaceID == treeBoundBox::BOTTOM)
977  {
978  facePoint.y() = bb.min().y();
979  faceID = treeBoundBox::BOTTOMBIT;
980  }
981  else if (keepFaceID == treeBoundBox::TOP)
982  {
983  facePoint.y() = bb.max().y();
984  faceID = treeBoundBox::TOPBIT;
985  }
986  else if (keepFaceID == treeBoundBox::BACK)
987  {
988  facePoint.z() = bb.min().z();
989  faceID = treeBoundBox::BACKBIT;
990  }
991  else if (keepFaceID == treeBoundBox::FRONT)
992  {
993  facePoint.z() = bb.max().z();
994  faceID = treeBoundBox::FRONTBIT;
995  }
996 
997 
998  if (debug)
999  {
1000  if (faceID != bb.faceBits(facePoint))
1001  {
1003  << "Pushed point from " << pt
1004  << " on face:" << ptFaceID << " of bb:" << bb << endl
1005  << "onto " << facePoint
1006  << " on face:" << faceID
1007  << " which is not consistent with geometric face "
1008  << bb.faceBits(facePoint)
1009  << abort(FatalError);
1010  }
1011  if (bb.posBits(facePoint) != 0)
1012  {
1014  << " bb:" << bb << endl
1015  << "does not contain perturbed point "
1016  << facePoint << abort(FatalError);
1017  }
1018  }
1019 
1020 
1021  return facePoint;
1022 }
1023 
1024 
1026 // faces
1028 //template<class Type>
1029 //void Foam::indexedOctree<Type>::checkMultipleFaces
1030 //(
1031 // const treeBoundBox& bb,
1032 // const vector& dir, // end-start
1033 // pointIndexHit& faceHitInfo,
1034 // direction& faceID
1035 //)
1036 //{
1037 // // Do the quick elimination of no or one face.
1038 // if
1039 // (
1040 // (faceID == 0)
1041 // || (faceID == treeBoundBox::LEFTBIT)
1042 // || (faceID == treeBoundBox::RIGHTBIT)
1043 // || (faceID == treeBoundBox::BOTTOMBIT)
1044 // || (faceID == treeBoundBox::TOPBIT)
1045 // || (faceID == treeBoundBox::BACKBIT)
1046 // || (faceID == treeBoundBox::FRONTBIT)
1047 // )
1048 // {
1049 // return;
1050 // }
1051 //
1052 //
1053 // // Check the direction of vector w.r.t. faces being intersected.
1054 // FixedList<scalar, 6> inproducts(-GREAT);
1055 //
1056 // direction nFaces = 0;
1057 //
1058 // if (faceID & treeBoundBox::LEFTBIT)
1059 // {
1060 // inproducts[treeBoundBox::LEFT] = mag
1061 // (
1062 // treeBoundBox::faceNormals[treeBoundBox::LEFT]
1063 // & dir
1064 // );
1065 // nFaces++;
1066 // }
1067 // if (faceID & treeBoundBox::RIGHTBIT)
1068 // {
1069 // inproducts[treeBoundBox::RIGHT] = mag
1070 // (
1071 // treeBoundBox::faceNormals[treeBoundBox::RIGHT]
1072 // & dir
1073 // );
1074 // nFaces++;
1075 // }
1076 //
1077 // if (faceID & treeBoundBox::BOTTOMBIT)
1078 // {
1079 // inproducts[treeBoundBox::BOTTOM] = mag
1080 // (
1081 // treeBoundBox::faceNormals[treeBoundBox::BOTTOM]
1082 // & dir
1083 // );
1084 // nFaces++;
1085 // }
1086 // if (faceID & treeBoundBox::TOPBIT)
1087 // {
1088 // inproducts[treeBoundBox::TOP] = mag
1089 // (
1090 // treeBoundBox::faceNormals[treeBoundBox::TOP]
1091 // & dir
1092 // );
1093 // nFaces++;
1094 // }
1095 //
1096 // if (faceID & treeBoundBox::BACKBIT)
1097 // {
1098 // inproducts[treeBoundBox::BACK] = mag
1099 // (
1100 // treeBoundBox::faceNormals[treeBoundBox::BACK]
1101 // & dir
1102 // );
1103 // nFaces++;
1104 // }
1105 // if (faceID & treeBoundBox::FRONTBIT)
1106 // {
1107 // inproducts[treeBoundBox::FRONT] = mag
1108 // (
1109 // treeBoundBox::faceNormals[treeBoundBox::FRONT]
1110 // & dir
1111 // );
1112 // nFaces++;
1113 // }
1114 //
1115 // if (nFaces == 0 || nFaces == 1 || nFaces > 3)
1116 // {
1117 // FatalErrorInFunction
1118 // << "Problem : nFaces:" << nFaces << abort(FatalError);
1119 // }
1120 //
1121 // // Keep point on most perpendicular face; shift it away from the aligned
1122 // // ones.
1123 // // E.g. line hits top and left face:
1124 // // a
1125 // // ----+----+
1126 // // | |
1127 // // | |
1128 // // +----+
1129 // // Shift point down (away from top):
1130 // //
1131 // // a+----+
1132 // // ----| |
1133 // // | |
1134 // // +----+
1135 //
1136 // label maxIndex = -1;
1137 // scalar maxInproduct = -GREAT;
1138 //
1139 // for (direction i = 0; i < 6; i++)
1140 // {
1141 // if (inproducts[i] > maxInproduct)
1142 // {
1143 // maxInproduct = inproducts[i];
1144 // maxIndex = i;
1145 // }
1146 // }
1147 //
1148 // if (maxIndex == -1)
1149 // {
1150 // FatalErrorInFunction
1151 // << "Problem maxIndex:" << maxIndex << " inproducts:" << inproducts
1152 // << abort(FatalError);
1153 // }
1154 //
1155 // const point oldPoint(faceHitInfo.rawPoint());
1156 // const direction oldFaceID = faceID;
1157 //
1158 // // 1. Push point into bb, away from all corners
1159 //
1160 // faceHitInfo.rawPoint() = pushPoint(bb, oldFaceID, oldPoint, true);
1161 //
1162 // // 2. Snap it back onto the preferred face
1163 //
1164 // if (maxIndex == treeBoundBox::LEFT)
1165 // {
1166 // faceHitInfo.rawPoint().x() = bb.min().x();
1167 // faceID = treeBoundBox::LEFTBIT;
1168 // }
1169 // else if (maxIndex == treeBoundBox::RIGHT)
1170 // {
1171 // faceHitInfo.rawPoint().x() = bb.max().x();
1172 // faceID = treeBoundBox::RIGHTBIT;
1173 // }
1174 // else if (maxIndex == treeBoundBox::BOTTOM)
1175 // {
1176 // faceHitInfo.rawPoint().y() = bb.min().y();
1177 // faceID = treeBoundBox::BOTTOMBIT;
1178 // }
1179 // else if (maxIndex == treeBoundBox::TOP)
1180 // {
1181 // faceHitInfo.rawPoint().y() = bb.max().y();
1182 // faceID = treeBoundBox::TOPBIT;
1183 // }
1184 // else if (maxIndex == treeBoundBox::BACK)
1185 // {
1186 // faceHitInfo.rawPoint().z() = bb.min().z();
1187 // faceID = treeBoundBox::BACKBIT;
1188 // }
1189 // else if (maxIndex == treeBoundBox::FRONT)
1190 // {
1191 // faceHitInfo.rawPoint().z() = bb.max().z();
1192 // faceID = treeBoundBox::FRONTBIT;
1193 // }
1194 //
1195 // Pout<< "From ray:" << dir
1196 // << " from point:" << oldPoint
1197 // << " on faces:" << faceString(oldFaceID)
1198 // << " of bb:" << bb
1199 // << " with inprods:" << inproducts
1200 // << " maxIndex:" << maxIndex << endl
1201 // << "perturbed to point:" << faceHitInfo.rawPoint()
1202 // << " on face:" << faceString(faceID)
1203 // << endl;
1204 //
1205 //
1206 // if (debug)
1207 // {
1208 // if (faceID != bb.faceBits(faceHitInfo.rawPoint()))
1209 // {
1210 // FatalErrorInFunction
1211 // << "Pushed point from " << oldPoint
1212 // << " on face:" << oldFaceID << " of bb:" << bb << endl
1213 // << "onto " << faceHitInfo.rawPoint()
1214 // << " on face:" << faceID
1215 // << " which is not consistent with geometric face "
1216 // << bb.faceBits(faceHitInfo.rawPoint())
1217 // << abort(FatalError);
1218 // }
1219 // }
1220 //}
1221 
1222 
1223 // Get parent node and octant. Return false if top of tree reached.
1224 template<class Type>
1227  const label nodeI,
1228  const direction octant,
1229 
1230  label& parentNodeI,
1231  label& parentOctant
1232 ) const
1233 {
1234  parentNodeI = nodes_[nodeI].parent_;
1235 
1236  if (parentNodeI == -1)
1237  {
1238  // Reached edge of tree
1239  return false;
1240  }
1241 
1242  const node& parentNode = nodes_[parentNodeI];
1243 
1244  // Find octant nodeI is in.
1245  parentOctant = 255;
1246 
1247  for (direction i = 0; i < parentNode.subNodes_.size(); i++)
1248  {
1249  labelBits index = parentNode.subNodes_[i];
1250 
1251  if (isNode(index) && getNode(index) == nodeI)
1252  {
1253  parentOctant = i;
1254  break;
1255  }
1256  }
1257 
1258  if (parentOctant == 255)
1259  {
1261  << "Problem: no parent found for octant:" << octant
1262  << " node:" << nodeI
1263  << abort(FatalError);
1264  }
1265 
1266  return true;
1267 }
1268 
1269 
1270 // Walk tree to neighbouring node. Gets current position as
1271 // node and octant in this node and walks in the direction given by
1272 // the facePointBits (combination of treeBoundBox::LEFTBIT, TOPBIT etc.)
1273 // Returns false if edge of tree hit.
1274 template<class Type>
1277  const point& facePoint,
1278  const direction faceID, // face(s) that facePoint is on
1279  label& nodeI,
1280  direction& octant
1281 ) const
1282 {
1283  label oldNodeI = nodeI;
1284  direction oldOctant = octant;
1285 
1286  // Find out how to test for octant. Say if we want to go left we need
1287  // to traverse up the tree until we hit a node where our octant is
1288  // on the right.
1289 
1290  // Coordinate direction to test
1291  const direction X = treeBoundBox::RIGHTHALF;
1292  const direction Y = treeBoundBox::TOPHALF;
1293  const direction Z = treeBoundBox::FRONTHALF;
1294 
1295  direction octantMask = 0;
1296  direction wantedValue = 0;
1297 
1298  if ((faceID & treeBoundBox::LEFTBIT) != 0)
1299  {
1300  // We want to go left so check if in right octant (i.e. x-bit is set)
1301  octantMask |= X;
1302  wantedValue |= X;
1303  }
1304  else if ((faceID & treeBoundBox::RIGHTBIT) != 0)
1305  {
1306  octantMask |= X; // wantedValue already 0
1307  }
1308 
1309  if ((faceID & treeBoundBox::BOTTOMBIT) != 0)
1310  {
1311  // Want to go down so check for y-bit set.
1312  octantMask |= Y;
1313  wantedValue |= Y;
1314  }
1315  else if ((faceID & treeBoundBox::TOPBIT) != 0)
1316  {
1317  // Want to go up so check for y-bit not set.
1318  octantMask |= Y;
1319  }
1320 
1321  if ((faceID & treeBoundBox::BACKBIT) != 0)
1322  {
1323  octantMask |= Z;
1324  wantedValue |= Z;
1325  }
1326  else if ((faceID & treeBoundBox::FRONTBIT) != 0)
1327  {
1328  octantMask |= Z;
1329  }
1330 
1331  // So now we have the coordinate directions in the octant we need to check
1332  // and the resulting value.
1333 
1334  /*
1335  // +---+---+
1336  // | | |
1337  // | | |
1338  // | | |
1339  // +---+-+-+
1340  // | | | |
1341  // | a+-+-+
1342  // | |\| |
1343  // +---+-+-+
1344  // \
1345  //
1346  // e.g. ray is at (a) in octant 0(or 4) with faceIDs : LEFTBIT+TOPBIT.
1347  // If we would be in octant 1(or 5) we could go to the correct octant
1348  // in the same node by just flipping the x and y bits (exoring).
1349  // But if we are not in octant 1/5 we have to go up until we are.
1350  // In general for leftbit+topbit:
1351  // - we have to check for x and y : octantMask = 011
1352  // - the checked bits have to be : wantedValue = ?01
1353  */
1354 
1355  //Pout<< "For point " << facePoint << endl;
1356 
1357  // Go up until we have chance to cross to the wanted direction
1358  while (wantedValue != (octant & octantMask))
1359  {
1360  // Go up to the parent.
1361 
1362  // Remove the directions that are not on the boundary of the parent.
1363  // See diagram above
1364  if (wantedValue & X) // && octantMask&X
1365  {
1366  // Looking for right octant.
1367  if (octant & X)
1368  {
1369  // My octant is one of the left ones so punch out the x check
1370  octantMask &= ~X;
1371  wantedValue &= ~X;
1372  }
1373  }
1374  else
1375  {
1376  if (!(octant & X))
1377  {
1378  // My octant is right but I want to go left.
1379  octantMask &= ~X;
1380  wantedValue &= ~X;
1381  }
1382  }
1383 
1384  if (wantedValue & Y)
1385  {
1386  if (octant & Y)
1387  {
1388  octantMask &= ~Y;
1389  wantedValue &= ~Y;
1390  }
1391  }
1392  else
1393  {
1394  if (!(octant & Y))
1395  {
1396  octantMask &= ~Y;
1397  wantedValue &= ~Y;
1398  }
1399  }
1400 
1401  if (wantedValue & Z)
1402  {
1403  if (octant & Z)
1404  {
1405  octantMask &= ~Z;
1406  wantedValue &= ~Z;
1407  }
1408  }
1409  else
1410  {
1411  if (!(octant & Z))
1412  {
1413  octantMask &= ~Z;
1414  wantedValue &= ~Z;
1415  }
1416  }
1417 
1418 
1419  label parentNodeI;
1420  label parentOctant;
1421  walkToParent(nodeI, octant, parentNodeI, parentOctant);
1422 
1423  if (parentNodeI == -1)
1424  {
1425  // Reached edge of tree
1426  return false;
1427  }
1428 
1429  //Pout<< " walked from node:" << nodeI << " octant:" << octant
1430  // << " bb:" << nodes_[nodeI].bb_.subBbox(octant) << endl
1431  // << " to:" << parentNodeI << " octant:" << parentOctant
1432  // << " bb:" << nodes_[parentNodeI].bb_.subBbox(parentOctant)
1433  // << endl;
1434  //
1435  //Pout<< " octantMask:" << octantMask
1436  // << " wantedValue:" << wantedValue << endl;
1437 
1438  nodeI = parentNodeI;
1439  octant = parentOctant;
1440  }
1441 
1442  // So now we hit the correct parent node. Switch to the correct octant.
1443  // Is done by jumping to the 'other half' so if e.g. in x direction in
1444  // right half we now jump to the left half.
1445  octant ^= octantMask;
1446 
1447  //Pout<< " to node:" << nodeI << " octant:" << octant
1448  // << " subBb:" <<subBbox(nodeI, octant) << endl;
1449 
1450 
1451  if (debug)
1452  {
1453  const treeBoundBox subBb(subBbox(nodeI, octant));
1454 
1455  if (!subBb.contains(facePoint))
1456  {
1458  << "When searching for " << facePoint
1459  << " ended up in node:" << nodeI
1460  << " octant:" << octant
1461  << " with bb:" << subBb
1462  << abort(FatalError);
1463  }
1464  }
1465 
1466 
1467  // See if we need to travel down. Note that we already go into the
1468  // the first level ourselves (instead of having findNode decide)
1469  labelBits index = nodes_[nodeI].subNodes_[octant];
1470 
1471  if (isNode(index))
1472  {
1473  labelBits node = findNode(getNode(index), facePoint);
1474 
1475  nodeI = getNode(node);
1476  octant = getOctant(node);
1477  }
1478 
1479 
1480  if (debug)
1481  {
1482  const treeBoundBox subBb(subBbox(nodeI, octant));
1483 
1484  if (nodeI == oldNodeI && octant == oldOctant)
1485  {
1487  << "Did not go to neighbour when searching for " << facePoint
1488  << endl
1489  << " starting from face:" << faceString(faceID)
1490  << " node:" << nodeI
1491  << " octant:" << octant
1492  << " bb:" << subBb
1493  << abort(FatalError);
1494  }
1495 
1496  if (!subBb.contains(facePoint))
1497  {
1499  << "When searching for " << facePoint
1500  << " ended up in node:" << nodeI
1501  << " octant:" << octant
1502  << " bb:" << subBb
1503  << abort(FatalError);
1504  }
1505  }
1506 
1507 
1508  return true;
1509 }
1510 
1511 
1512 template<class Type>
1515  const direction faceID
1516 )
1517 {
1518  word desc;
1519 
1520  if (faceID == 0)
1521  {
1522  desc = "noFace";
1523  }
1524  if (faceID & treeBoundBox::LEFTBIT)
1525  {
1526  if (!desc.empty()) desc += "+";
1527  desc += "left";
1528  }
1529  if (faceID & treeBoundBox::RIGHTBIT)
1530  {
1531  if (!desc.empty()) desc += "+";
1532  desc += "right";
1533  }
1534  if (faceID & treeBoundBox::BOTTOMBIT)
1535  {
1536  if (!desc.empty()) desc += "+";
1537  desc += "bottom";
1538  }
1539  if (faceID & treeBoundBox::TOPBIT)
1540  {
1541  if (!desc.empty()) desc += "+";
1542  desc += "top";
1543  }
1544  if (faceID & treeBoundBox::BACKBIT)
1545  {
1546  if (!desc.empty()) desc += "+";
1547  desc += "back";
1548  }
1549  if (faceID & treeBoundBox::FRONTBIT)
1550  {
1551  if (!desc.empty()) desc += "+";
1552  desc += "front";
1553  }
1554  return desc;
1555 }
1556 
1557 
1558 // Traverse a node. If intersects a triangle return first intersection point:
1559 // hitInfo.index = index of shape
1560 // hitInfo.point = point on shape
1561 // Else return a miss and the bounding box face hit:
1562 // hitInfo.point = coordinate of intersection of ray with bounding box
1563 // hitBits = posbits of point on bounding box
1564 template<class Type>
1565 template<class FindIntersectOp>
1568  const bool findAny,
1569  const point& treeStart,
1570  const vector& treeVec,
1571 
1572  const point& start,
1573  const point& end,
1574  const label nodeI,
1575  const direction octant,
1576 
1577  pointIndexHit& hitInfo,
1578  direction& hitBits,
1579 
1580  const FindIntersectOp& fiOp
1581 ) const
1582 {
1583  if (debug)
1584  {
1585  const treeBoundBox octantBb(subBbox(nodeI, octant));
1586 
1587  if (octantBb.posBits(start) != 0)
1588  {
1590  << "Node:" << nodeI << " octant:" << octant
1591  << " bb:" << octantBb << endl
1592  << "does not contain point " << start << abort(FatalError);
1593  }
1594  }
1595 
1596  const node& nod = nodes_[nodeI];
1597 
1598  labelBits index = nod.subNodes_[octant];
1599 
1600  if (isContent(index))
1601  {
1602  const labelList& indices = contents_[getContent(index)];
1603 
1604  if (indices.size())
1605  {
1606  if (findAny)
1607  {
1608  // Find any intersection
1609 
1610  forAll(indices, elemI)
1611  {
1612  label shapeI = indices[elemI];
1613 
1614  point pt;
1615  bool hit = fiOp(shapeI, start, end, pt);
1616 
1617  // Note that intersection of shape might actually be
1618  // in a neighbouring box. For findAny this is not important.
1619  if (hit)
1620  {
1621  // Hit so pt is nearer than nearestPoint.
1622  // Update hit info
1623  hitInfo.setHit();
1624  hitInfo.setIndex(shapeI);
1625  hitInfo.setPoint(pt);
1626  return;
1627  }
1628  }
1629  }
1630  else
1631  {
1632  // Find nearest intersection
1633 
1634  const treeBoundBox octantBb(subBbox(nodeI, octant));
1635 
1636  point nearestPoint(end);
1637 
1638  forAll(indices, elemI)
1639  {
1640  label shapeI = indices[elemI];
1641 
1642  point pt;
1643  bool hit = fiOp(shapeI, start, nearestPoint, pt);
1644 
1645  // Note that intersection of shape might actually be
1646  // in a neighbouring box. Since we need to maintain strict
1647  // (findAny=false) ordering skip such an intersection. It
1648  // will be found when we are doing the next box.
1649 
1650  if (hit && octantBb.contains(pt))
1651  {
1652  // Hit so pt is nearer than nearestPoint.
1653  nearestPoint = pt;
1654  // Update hit info
1655  hitInfo.setHit();
1656  hitInfo.setIndex(shapeI);
1657  hitInfo.setPoint(pt);
1658  }
1659  }
1660 
1661  if (hitInfo.hit())
1662  {
1663  // Found intersected shape.
1664  return;
1665  }
1666  }
1667  }
1668  }
1669 
1670  // Nothing intersected in this node
1671  // Traverse to end of node. Do by ray tracing back from end and finding
1672  // intersection with bounding box of node.
1673  // start point is now considered to be inside bounding box.
1674 
1675  const treeBoundBox octantBb(subBbox(nodeI, octant));
1676 
1677  point pt;
1678  bool intersected = octantBb.intersects
1679  (
1680  end, //treeStart,
1681  (start-end), //treeVec,
1682 
1683  end,
1684  start,
1685 
1686  pt,
1687  hitBits
1688  );
1689 
1690 
1691  if (intersected)
1692  {
1693  // Return miss. Set misspoint to face.
1694  hitInfo.setPoint(pt);
1695  }
1696  else
1697  {
1698  // Rare case: did not find intersection of ray with octantBb. Can
1699  // happen if end is on face/edge of octantBb. Do like
1700  // lagrangian and re-track with perturbed vector (slightly pushed out
1701  // of bounding box)
1702 
1703  point perturbedEnd(pushPoint(octantBb, end, false));
1704 
1705  traverseNode
1706  (
1707  findAny,
1708  treeStart,
1709  treeVec,
1710  start,
1711  perturbedEnd,
1712  nodeI,
1713  octant,
1714 
1715  hitInfo,
1716  hitBits,
1717 
1718  fiOp
1719  );
1720  }
1721 }
1722 
1723 
1724 // Find first intersection
1725 template<class Type>
1726 template<class FindIntersectOp>
1729  const bool findAny,
1730  const point& treeStart,
1731  const point& treeEnd,
1732  const label startNodeI,
1733  const direction startOctant,
1734  const FindIntersectOp& fiOp,
1735  const bool verbose
1736 ) const
1737 {
1738  const vector treeVec(treeEnd - treeStart);
1739 
1740  // Current node as parent+octant
1741  label nodeI = startNodeI;
1742  direction octant = startOctant;
1743 
1744  if (verbose)
1745  {
1746  Pout<< "findLine : treeStart:" << treeStart
1747  << " treeEnd:" << treeEnd << endl
1748  << "node:" << nodeI
1749  << " octant:" << octant
1750  << " bb:" << subBbox(nodeI, octant) << endl;
1751  }
1752 
1753  // Current position. Initialize to miss
1754  pointIndexHit hitInfo(false, treeStart, -1);
1755 
1756  //while (true)
1757  label i = 0;
1758  for (; i < 100000; i++)
1759  {
1760  // Ray-trace to end of current node. Updates point (either on triangle
1761  // in case of hit or on node bounding box in case of miss)
1762 
1763  const treeBoundBox octantBb(subBbox(nodeI, octant));
1764 
1765  // Make sure point is away from any edges/corners
1766  point startPoint
1767  (
1768  pushPointIntoFace
1769  (
1770  octantBb,
1771  treeVec,
1772  hitInfo.rawPoint()
1773  )
1774  );
1775 
1776  if (verbose)
1777  {
1778  Pout<< "iter:" << i
1779  << " at current:" << hitInfo.rawPoint()
1780  << " (perturbed:" << startPoint << ")" << endl
1781  << " node:" << nodeI
1782  << " octant:" << octant
1783  << " bb:" << subBbox(nodeI, octant) << endl;
1784  }
1785 
1786 
1787 
1788 
1789  // Faces of current bounding box current point is on
1790  direction hitFaceID = 0;
1791 
1792  traverseNode
1793  (
1794  findAny,
1795  treeStart,
1796  treeVec,
1797 
1798  startPoint, // Note: pass in copy since hitInfo
1799  // also used in return value.
1800  treeEnd, // pass in overall end so is nicely outside bb
1801  nodeI,
1802  octant,
1803 
1804  hitInfo,
1805  hitFaceID,
1806 
1807  fiOp
1808  );
1809 
1810  // Did we hit a triangle?
1811  if (hitInfo.hit())
1812  {
1813  break;
1814  }
1815 
1816  if (hitFaceID == 0 || hitInfo.rawPoint() == treeEnd)
1817  {
1818  // endpoint inside the tree. Return miss.
1819  break;
1820  }
1821 
1822  // Create a point on other side of face.
1823  point perturbedPoint
1824  (
1825  pushPoint
1826  (
1827  octantBb,
1828  hitFaceID,
1829  hitInfo.rawPoint(),
1830  false // push outside of octantBb
1831  )
1832  );
1833 
1834  if (verbose)
1835  {
1836  Pout<< " iter:" << i
1837  << " hit face:" << faceString(hitFaceID)
1838  << " at:" << hitInfo.rawPoint() << nl
1839  << " node:" << nodeI
1840  << " octant:" << octant
1841  << " bb:" << subBbox(nodeI, octant) << nl
1842  << " walking to neighbour containing:" << perturbedPoint
1843  << endl;
1844  }
1845 
1846 
1847  // Nothing hit so we are on face of bounding box (given as node+octant+
1848  // position bits). Traverse to neighbouring node. Use slightly perturbed
1849  // point.
1850 
1851  bool ok = walkToNeighbour
1852  (
1853  perturbedPoint,
1854  hitFaceID, // face(s) that hitInfo is on
1855 
1856  nodeI,
1857  octant
1858  );
1859 
1860  if (!ok)
1861  {
1862  // Hit the edge of the tree. Return miss.
1863  break;
1864  }
1865 
1866  if (verbose)
1867  {
1868  const treeBoundBox octantBb(subBbox(nodeI, octant));
1869  Pout<< " walked for point:" << hitInfo.rawPoint() << endl
1870  << " to neighbour node:" << nodeI
1871  << " octant:" << octant
1872  << " face:" << faceString(octantBb.faceBits(hitInfo.rawPoint()))
1873  << " of octantBb:" << octantBb << endl
1874  << endl;
1875  }
1876  }
1877 
1878  if (i == 100000)
1879  {
1880  // Probably in loop.
1881  if (!verbose)
1882  {
1883  // Redo intersection but now with verbose flag switched on.
1884  return findLine
1885  (
1886  findAny,
1887  treeStart,
1888  treeEnd,
1889  startNodeI,
1890  startOctant,
1891  fiOp,
1892  true //verbose,
1893  );
1894  }
1895  if (debug)
1896  {
1898  << "Got stuck in loop raytracing from:" << treeStart
1899  << " to:" << treeEnd << endl
1900  << "inside top box:" << subBbox(startNodeI, startOctant)
1901  << abort(FatalError);
1902  }
1903  else
1904  {
1906  << "Got stuck in loop raytracing from:" << treeStart
1907  << " to:" << treeEnd << endl
1908  << "inside top box:" << subBbox(startNodeI, startOctant)
1909  << endl;
1910  }
1911  }
1912 
1913  return hitInfo;
1914 }
1915 
1916 
1917 // Find first intersection
1918 template<class Type>
1919 template<class FindIntersectOp>
1922  const bool findAny,
1923  const point& start,
1924  const point& end,
1925  const FindIntersectOp& fiOp
1926 ) const
1927 {
1928  pointIndexHit hitInfo;
1929 
1930  if (nodes_.size())
1931  {
1932  const treeBoundBox& treeBb = nodes_[0].bb_;
1933 
1934  // No effort is made to deal with points which are on edge of tree
1935  // bounding box for now.
1936 
1937  direction startBit = treeBb.posBits(start);
1938  direction endBit = treeBb.posBits(end);
1939 
1940  if ((startBit & endBit) != 0)
1941  {
1942  // Both start and end outside domain and in same block.
1943  return pointIndexHit(false, vector::zero, -1);
1944  }
1945 
1946 
1947  // Trim segment to treeBb
1948 
1949  point trackStart(start);
1950  point trackEnd(end);
1951 
1952  if (startBit != 0)
1953  {
1954  // Track start to inside domain.
1955  if (!treeBb.intersects(start, end, trackStart))
1956  {
1957  return pointIndexHit(false, vector::zero, -1);
1958  }
1959  }
1960 
1961  if (endBit != 0)
1962  {
1963  // Track end to inside domain.
1964  if (!treeBb.intersects(end, trackStart, trackEnd))
1965  {
1966  return pointIndexHit(false, vector::zero, -1);
1967  }
1968  }
1969 
1970 
1971  // Find lowest level tree node that start is in.
1972  labelBits index = findNode(0, trackStart);
1973 
1974  label parentNodeI = getNode(index);
1975  direction octant = getOctant(index);
1976 
1977  hitInfo = findLine
1978  (
1979  findAny,
1980  trackStart,
1981  trackEnd,
1982  parentNodeI,
1983  octant,
1984  fiOp
1985  );
1986  }
1987 
1988  return hitInfo;
1989 }
1990 
1991 
1992 template<class Type>
1995  const label nodeI,
1996  const treeBoundBox& searchBox,
1997  labelHashSet& elements
1998 ) const
1999 {
2000  const node& nod = nodes_[nodeI];
2001  const treeBoundBox& nodeBb = nod.bb_;
2002 
2003  for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2004  {
2005  labelBits index = nod.subNodes_[octant];
2006 
2007  if (isNode(index))
2008  {
2009  const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
2010 
2011  if (subBb.overlaps(searchBox))
2012  {
2013  findBox(getNode(index), searchBox, elements);
2014  }
2015  }
2016  else if (isContent(index))
2017  {
2018  const treeBoundBox subBb(nodeBb.subBbox(octant));
2019 
2020  if (subBb.overlaps(searchBox))
2021  {
2022  const labelList& indices = contents_[getContent(index)];
2023 
2024  forAll(indices, i)
2025  {
2026  label shapeI = indices[i];
2027 
2028  if (shapes_.overlaps(shapeI, searchBox))
2029  {
2030  elements.insert(shapeI);
2031  }
2032  }
2033  }
2034  }
2035  }
2036 }
2037 
2038 
2039 template<class Type>
2042  const label nodeI,
2043  const point& centre,
2044  const scalar radiusSqr,
2045  labelHashSet& elements
2046 ) const
2047 {
2048  const node& nod = nodes_[nodeI];
2049  const treeBoundBox& nodeBb = nod.bb_;
2050 
2051  for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2052  {
2053  labelBits index = nod.subNodes_[octant];
2054 
2055  if (isNode(index))
2056  {
2057  const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
2058 
2059  if (subBb.overlaps(centre, radiusSqr))
2060  {
2061  findSphere(getNode(index), centre, radiusSqr, elements);
2062  }
2063  }
2064  else if (isContent(index))
2065  {
2066  const treeBoundBox subBb(nodeBb.subBbox(octant));
2067 
2068  if (subBb.overlaps(centre, radiusSqr))
2069  {
2070  const labelList& indices = contents_[getContent(index)];
2071 
2072  forAll(indices, i)
2073  {
2074  label shapeI = indices[i];
2075 
2076  if (shapes_.overlaps(shapeI, centre, radiusSqr))
2077  {
2078  elements.insert(shapeI);
2079  }
2080  }
2081  }
2082  }
2083  }
2084 }
2085 
2086 
2087 template<class Type>
2088 template<class CompareOp>
2091  const scalar nearDist,
2092  const bool okOrder,
2093  const indexedOctree<Type>& tree1,
2094  const labelBits index1,
2095  const treeBoundBox& bb1,
2096  const indexedOctree<Type>& tree2,
2097  const labelBits index2,
2098  const treeBoundBox& bb2,
2099  CompareOp& cop
2100 )
2101 {
2102  const vector nearSpan(nearDist, nearDist, nearDist);
2103 
2104  if (tree1.isNode(index1))
2105  {
2106  const node& nod1 = tree1.nodes()[tree1.getNode(index1)];
2107  const treeBoundBox searchBox
2108  (
2109  bb1.min()-nearSpan,
2110  bb1.max()+nearSpan
2111  );
2112 
2113  if (tree2.isNode(index2))
2114  {
2115  if (bb2.overlaps(searchBox))
2116  {
2117  const node& nod2 = tree2.nodes()[tree2.getNode(index2)];
2118 
2119  for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++)
2120  {
2121  labelBits subIndex2 = nod2.subNodes_[i2];
2122  const treeBoundBox subBb2
2123  (
2124  tree2.isNode(subIndex2)
2125  ? tree2.nodes()[tree2.getNode(subIndex2)].bb_
2126  : bb2.subBbox(i2)
2127  );
2128 
2129  findNear
2130  (
2131  nearDist,
2132  !okOrder,
2133  tree2,
2134  subIndex2,
2135  subBb2,
2136  tree1,
2137  index1,
2138  bb1,
2139  cop
2140  );
2141  }
2142  }
2143  }
2144  else if (tree2.isContent(index2))
2145  {
2146  // index2 is leaf, index1 not yet.
2147  for (direction i1 = 0; i1 < nod1.subNodes_.size(); i1++)
2148  {
2149  labelBits subIndex1 = nod1.subNodes_[i1];
2150  const treeBoundBox subBb1
2151  (
2152  tree1.isNode(subIndex1)
2153  ? tree1.nodes()[tree1.getNode(subIndex1)].bb_
2154  : bb1.subBbox(i1)
2155  );
2156 
2157  findNear
2158  (
2159  nearDist,
2160  !okOrder,
2161  tree2,
2162  index2,
2163  bb2,
2164  tree1,
2165  subIndex1,
2166  subBb1,
2167  cop
2168  );
2169  }
2170  }
2171  }
2172  else if (tree1.isContent(index1))
2173  {
2174  const treeBoundBox searchBox
2175  (
2176  bb1.min()-nearSpan,
2177  bb1.max()+nearSpan
2178  );
2179 
2180  if (tree2.isNode(index2))
2181  {
2182  const node& nod2 =
2183  tree2.nodes()[tree2.getNode(index2)];
2184 
2185  if (bb2.overlaps(searchBox))
2186  {
2187  for (direction i2 = 0; i2 < nod2.subNodes_.size(); i2++)
2188  {
2189  labelBits subIndex2 = nod2.subNodes_[i2];
2190  const treeBoundBox subBb2
2191  (
2192  tree2.isNode(subIndex2)
2193  ? tree2.nodes()[tree2.getNode(subIndex2)].bb_
2194  : bb2.subBbox(i2)
2195  );
2196 
2197  findNear
2198  (
2199  nearDist,
2200  !okOrder,
2201  tree2,
2202  subIndex2,
2203  subBb2,
2204  tree1,
2205  index1,
2206  bb1,
2207  cop
2208  );
2209  }
2210  }
2211  }
2212  else if (tree2.isContent(index2))
2213  {
2214  // Both are leaves. Check n^2.
2215 
2216  const labelList& indices1 =
2217  tree1.contents()[tree1.getContent(index1)];
2218  const labelList& indices2 =
2219  tree2.contents()[tree2.getContent(index2)];
2220 
2221  forAll(indices1, i)
2222  {
2223  label shape1 = indices1[i];
2224 
2225  forAll(indices2, j)
2226  {
2227  label shape2 = indices2[j];
2228 
2229  if ((&tree1 != &tree2) || (shape1 != shape2))
2230  {
2231  if (okOrder)
2232  {
2233  cop
2234  (
2235  nearDist,
2236  tree1.shapes(),
2237  shape1,
2238  tree2.shapes(),
2239  shape2
2240  );
2241  }
2242  else
2243  {
2244  cop
2245  (
2246  nearDist,
2247  tree2.shapes(),
2248  shape2,
2249  tree1.shapes(),
2250  shape1
2251  );
2252  }
2253  }
2254  }
2255  }
2256  }
2257  }
2258 }
2259 
2260 
2261 // Number of elements in node.
2262 template<class Type>
2265  const labelBits index
2266 ) const
2267 {
2268  label nElems = 0;
2269 
2270  if (isNode(index))
2271  {
2272  // tree node.
2273  label nodeI = getNode(index);
2274 
2275  const node& nod = nodes_[nodeI];
2276 
2277  for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2278  {
2279  nElems += countElements(nod.subNodes_[octant]);
2280  }
2281  }
2282  else if (isContent(index))
2283  {
2284  nElems += contents_[getContent(index)].size();
2285  }
2286  else
2287  {
2288  // empty node
2289  }
2290 
2291  return nElems;
2292 }
2293 
2294 
2295 template<class Type>
2298  const label nodeI,
2299  const direction octant
2300 ) const
2301 {
2302  OFstream str
2303  (
2304  "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
2305  );
2306 
2307  labelBits index = nodes_[nodeI].subNodes_[octant];
2308 
2309  treeBoundBox subBb;
2310 
2311  if (isNode(index))
2312  {
2313  subBb = nodes_[getNode(index)].bb_;
2314  }
2315  else if (isContent(index) || isEmpty(index))
2316  {
2317  subBb = nodes_[nodeI].bb_.subBbox(octant);
2318  }
2319 
2320  Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
2321  << " to " << str.name() << endl;
2322 
2323  // Dump bounding box
2324  pointField bbPoints(subBb.points());
2325 
2326  forAll(bbPoints, i)
2327  {
2328  const point& pt = bbPoints[i];
2329 
2330  str<< "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
2331  }
2332 
2333  forAll(treeBoundBox::edges, i)
2334  {
2335  const edge& e = treeBoundBox::edges[i];
2336 
2337  str<< "l " << e[0] + 1 << ' ' << e[1] + 1 << nl;
2338  }
2339 }
2340 
2341 
2342 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
2343 
2344 template<class Type>
2346 :
2347  shapes_(shapes),
2348  nodes_(0),
2349  contents_(0),
2350  nodeTypes_(0)
2351 {}
2352 
2353 
2354 template<class Type>
2357  const Type& shapes,
2358  const List<node>& nodes,
2359  const labelListList& contents
2360 )
2361 :
2362  shapes_(shapes),
2363  nodes_(nodes),
2364  contents_(contents),
2365  nodeTypes_(0)
2366 {}
2367 
2368 
2369 template<class Type>
2372  const Type& shapes,
2373  const treeBoundBox& bb,
2374  const label maxLevels, // maximum number of levels
2375  const scalar maxLeafRatio,
2376  const scalar maxDuplicity
2377 )
2378 :
2379  shapes_(shapes),
2380  nodes_(0),
2381  contents_(0),
2382  nodeTypes_(0)
2383 {
2384  int oldMemSize = 0;
2385  if (debug)
2386  {
2387  Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2388  << " shapes:" << shapes.size() << nl
2389  << " bb:" << bb << nl
2390  << endl;
2391  oldMemSize = memInfo().size();
2392  }
2393 
2394  if (shapes.size() == 0)
2395  {
2396  return;
2397  }
2398 
2399  // Start off with one node with all shapes in it.
2400  DynamicList<node> nodes(label(shapes.size() / maxLeafRatio));
2401  DynamicList<labelList> contents(label(shapes.size() / maxLeafRatio));
2402  contents.append(identity(shapes.size()));
2403 
2404  // Create topnode.
2405  node topNode(divide(bb, contents, 0));
2406  nodes.append(topNode);
2407 
2408 
2409  // Now have all contents at level 1. Create levels by splitting levels
2410  // above.
2411 
2412  label nLevels = 1;
2413 
2414  for (; nLevels < maxLevels; nLevels++)
2415  {
2416  // Count number of references into shapes (i.e. contents)
2417  label nEntries = 0;
2418  forAll(contents, i)
2419  {
2420  nEntries += contents[i].size();
2421  }
2422 
2423  if (debug)
2424  {
2425  Pout<< "indexedOctree<Type>::indexedOctree:" << nl
2426  << " nLevels:" << nLevels << nl
2427  << " nEntries per treeLeaf:" << nEntries/contents.size()
2428  << nl
2429  << " nEntries per shape (duplicity):"
2430  << nEntries/shapes.size()
2431  << nl
2432  << endl;
2433  }
2434 
2435  if
2436  (
2437  //nEntries < maxLeafRatio*contents.size()
2438  // ||
2439  nEntries > maxDuplicity*shapes.size()
2440  )
2441  {
2442  break;
2443  }
2444 
2445 
2446  // Split nodes with more than maxLeafRatio elements
2447  label nOldNodes = nodes.size();
2448  splitNodes
2449  (
2450  label(maxLeafRatio),
2451  nodes,
2452  contents
2453  );
2454 
2455  if (nOldNodes == nodes.size())
2456  {
2457  break;
2458  }
2459  }
2460 
2461  // Shrink
2462  nodes.shrink();
2463  contents.shrink();
2464 
2465 
2466  // Compact such that deeper level contents are always after the
2467  // ones for a shallower level. This way we can slice a coarser level
2468  // off the tree.
2469  contents_.setSize(contents.size());
2470  label compactI = 0;
2471 
2472  label level = 0;
2473 
2474  while (true)
2475  {
2476  label nNodes = compactContents
2477  (
2478  nodes,
2479  contents,
2480  level,
2481  0,
2482  0,
2483  contents_,
2484  compactI
2485  );
2486 
2487  if (compactI == 0 && nNodes == 0)
2488  {
2489  // Did not put contents anywhere - are outside bb!
2490  break;
2491  }
2492 
2493  if (compactI == contents_.size())
2494  {
2495  // Transferred all contents to contents_ (in order breadth first)
2496  break;
2497  }
2498 
2499  level++;
2500  }
2501  nodes_.transfer(nodes);
2502  nodes.clear();
2503 
2504  if (debug)
2505  {
2506  label nEntries = 0;
2507  forAll(contents_, i)
2508  {
2509  nEntries += contents_[i].size();
2510  }
2511 
2512  label memSize = memInfo().size();
2513 
2514 
2515  Pout<< "indexedOctree<Type>::indexedOctree"
2516  << " : finished construction of tree of:" << shapes.typeName
2517  << nl
2518  << " bb:" << this->bb() << nl
2519  << " shapes:" << shapes.size() << nl
2520  << " nLevels:" << nLevels << nl
2521  << " treeNodes:" << nodes_.size() << nl
2522  << " nEntries:" << nEntries << nl
2523  << " per treeLeaf:"
2524  << scalar(nEntries)/contents.size() << nl
2525  << " per shape (duplicity):"
2526  << scalar(nEntries)/shapes.size() << nl
2527  << " total memory:" << memSize-oldMemSize
2528  << endl;
2529  }
2530 }
2531 
2532 
2533 template<class Type>
2536  const Type& shapes,
2537  Istream& is
2538 )
2539 :
2540  shapes_(shapes),
2541  nodes_(is),
2542  contents_(is),
2543  nodeTypes_(0)
2544 {}
2545 
2546 
2547 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2548 
2549 template<class Type>
2551 {
2552  return perturbTol_;
2553 }
2554 
2555 
2556 //template<class Type>
2557 //bool Foam::indexedOctree<Type>::findAnyOverlap
2558 //(
2559 // const point& sample,
2560 // const scalar startDistSqr
2561 //) const
2562 //{
2563 // if (nodes_.size())
2564 // {
2565 // return findAnyOverlap
2566 // (
2567 // 0,
2568 // sample,
2569 // startDistSqr
2570 // );
2571 // }
2572 //
2573 // return false;
2574 //}
2575 
2576 
2577 template<class Type>
2580  const point& sample,
2581  const scalar startDistSqr
2582 ) const
2583 {
2584  return findNearest
2585  (
2586  sample,
2587  startDistSqr,
2588  typename Type::findNearestOp(*this)
2589  );
2590 }
2591 
2592 
2593 template<class Type>
2594 template<class FindNearestOp>
2597  const point& sample,
2598  const scalar startDistSqr,
2599 
2600  const FindNearestOp& fnOp
2601 ) const
2602 {
2603  scalar nearestDistSqr = startDistSqr;
2604  label nearestShapeI = -1;
2605  point nearestPoint = vector::zero;
2606 
2607  if (nodes_.size())
2608  {
2609  findNearest
2610  (
2611  0,
2612  sample,
2613 
2614  nearestDistSqr,
2615  nearestShapeI,
2616  nearestPoint,
2617 
2618  fnOp
2619  );
2620  }
2621 
2622  return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2623 }
2624 
2625 
2626 template<class Type>
2629  const linePointRef& ln,
2630  treeBoundBox& tightest,
2631  point& linePoint
2632 ) const
2633 {
2634  return findNearest
2635  (
2636  ln,
2637  tightest,
2638  linePoint,
2639  typename Type::findNearestOp(*this)
2640  );
2641 }
2642 
2643 
2644 template<class Type>
2645 template<class FindNearestOp>
2648  const linePointRef& ln,
2649  treeBoundBox& tightest,
2650  point& linePoint,
2651 
2652  const FindNearestOp& fnOp
2653 ) const
2654 {
2655  label nearestShapeI = -1;
2656  point nearestPoint = vector::zero;
2657 
2658  if (nodes_.size())
2659  {
2660  findNearest
2661  (
2662  0,
2663  ln,
2664 
2665  tightest,
2666  nearestShapeI,
2667  linePoint,
2668  nearestPoint,
2669 
2670  fnOp
2671  );
2672  }
2673 
2674  return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
2675 }
2676 
2677 
2678 // Find nearest intersection
2679 template<class Type>
2682  const point& start,
2683  const point& end
2684 ) const
2685 {
2686  return findLine
2687  (
2688  false,
2689  start,
2690  end,
2691  typename Type::findIntersectOp(*this)
2692  );
2693 }
2694 
2695 
2696 // Find nearest intersection
2697 template<class Type>
2700  const point& start,
2701  const point& end
2702 ) const
2703 {
2704  return findLine
2705  (
2706  true,
2707  start,
2708  end,
2709  typename Type::findIntersectOp(*this)
2710  );
2711 }
2712 
2713 
2714 // Find nearest intersection
2715 template<class Type>
2716 template<class FindIntersectOp>
2719  const point& start,
2720  const point& end,
2721  const FindIntersectOp& fiOp
2722 ) const
2723 {
2724  return findLine(false, start, end, fiOp);
2725 }
2726 
2727 
2728 // Find nearest intersection
2729 template<class Type>
2730 template<class FindIntersectOp>
2733  const point& start,
2734  const point& end,
2735  const FindIntersectOp& fiOp
2736 ) const
2737 {
2738  return findLine(true, start, end, fiOp);
2739 }
2740 
2741 
2742 template<class Type>
2744 (
2745  const treeBoundBox& searchBox
2746 ) const
2747 {
2748  // Storage for labels of shapes inside bb. Size estimate.
2749  labelHashSet elements(shapes_.size() / 100);
2750 
2751  if (nodes_.size())
2752  {
2753  findBox(0, searchBox, elements);
2754  }
2755 
2756  return elements.toc();
2757 }
2758 
2759 
2760 template<class Type>
2763  const point& centre,
2764  const scalar radiusSqr
2765 ) const
2766 {
2767  // Storage for labels of shapes inside bb. Size estimate.
2768  labelHashSet elements(shapes_.size() / 100);
2769 
2770  if (nodes_.size())
2771  {
2772  findSphere(0, centre, radiusSqr, elements);
2773  }
2774 
2775  return elements.toc();
2776 }
2777 
2778 
2779 // Find node (as parent+octant) containing point
2780 template<class Type>
2783  const label nodeI,
2784  const point& sample
2785 ) const
2786 {
2787  if (nodes_.empty())
2788  {
2789  // Empty tree. Return what?
2790  return nodePlusOctant(nodeI, 0);
2791  }
2792 
2793  const node& nod = nodes_[nodeI];
2794 
2795  if (debug)
2796  {
2797  if (!nod.bb_.contains(sample))
2798  {
2800  << "Cannot find " << sample << " in node " << nodeI
2801  << abort(FatalError);
2802  }
2803  }
2804 
2805  direction octant = nod.bb_.subOctant(sample);
2806 
2807  labelBits index = nod.subNodes_[octant];
2808 
2809  if (isNode(index))
2810  {
2811  // Recurse
2812  return findNode(getNode(index), sample);
2813  }
2814  else if (isContent(index))
2815  {
2816  // Content. Return treenode+octant
2817  return nodePlusOctant(nodeI, octant);
2818  }
2819  else
2820  {
2821  // Empty. Return treenode+octant
2822  return nodePlusOctant(nodeI, octant);
2823  }
2824 }
2825 
2826 
2827 template<class Type>
2829 {
2830  labelBits index = findNode(0, sample);
2831 
2832  const node& nod = nodes_[getNode(index)];
2833 
2834  labelBits contentIndex = nod.subNodes_[getOctant(index)];
2835 
2836  // Need to check for the presence of content, in-case the node is empty
2837  if (isContent(contentIndex))
2838  {
2839  labelList indices = contents_[getContent(contentIndex)];
2840 
2841  forAll(indices, elemI)
2842  {
2843  label shapeI = indices[elemI];
2844 
2845  if (shapes_.contains(shapeI, sample))
2846  {
2847  return shapeI;
2848  }
2849  }
2850  }
2851 
2852  return -1;
2853 }
2854 
2855 
2856 template<class Type>
2859  const point& sample
2860 ) const
2861 {
2862  labelBits index = findNode(0, sample);
2863 
2864  const node& nod = nodes_[getNode(index)];
2865 
2866  labelBits contentIndex = nod.subNodes_[getOctant(index)];
2867 
2868  // Need to check for the presence of content, in-case the node is empty
2869  if (isContent(contentIndex))
2870  {
2871  return contents_[getContent(contentIndex)];
2872  }
2873  else
2874  {
2875  return emptyList<label>();
2876  }
2877 }
2878 
2879 
2880 // Determine type (inside/outside/mixed) per node.
2881 template<class Type>
2883 (
2884  const point& sample
2885 ) const
2886 {
2887  if (nodes_.empty())
2888  {
2889  return volumeType::UNKNOWN;
2890  }
2891 
2892 // // If the sample is not within the octree, then have to query shapes
2893 // // directly
2894 // if (!nodes_[0].bb_.contains(sample))
2895 // {
2896 // return volumeType(shapes_.getVolumeType(*this, sample));
2897 // }
2898 
2899  if (nodeTypes_.size() != 8*nodes_.size())
2900  {
2901  // Calculate type for every octant of node.
2902 
2903  nodeTypes_.setSize(8*nodes_.size());
2904  nodeTypes_ = volumeType::UNKNOWN;
2905 
2906  calcVolumeType(0);
2907 
2908  if (debug)
2909  {
2910  label nUNKNOWN = 0;
2911  label nMIXED = 0;
2912  label nINSIDE = 0;
2913  label nOUTSIDE = 0;
2914 
2915  forAll(nodeTypes_, i)
2916  {
2917  volumeType type = volumeType::type(nodeTypes_.get(i));
2918 
2919  if (type == volumeType::UNKNOWN)
2920  {
2921  nUNKNOWN++;
2922  }
2923  else if (type == volumeType::MIXED)
2924  {
2925  nMIXED++;
2926  }
2927  else if (type == volumeType::INSIDE)
2928  {
2929  nINSIDE++;
2930  }
2931  else if (type == volumeType::OUTSIDE)
2932  {
2933  nOUTSIDE++;
2934  }
2935  else
2936  {
2938  }
2939  }
2940 
2941  Pout<< "indexedOctree<Type>::getVolumeType : "
2942  << " bb:" << bb()
2943  << " nodes_:" << nodes_.size()
2944  << " nodeTypes_:" << nodeTypes_.size()
2945  << " nUNKNOWN:" << nUNKNOWN
2946  << " nMIXED:" << nMIXED
2947  << " nINSIDE:" << nINSIDE
2948  << " nOUTSIDE:" << nOUTSIDE
2949  << endl;
2950  }
2951  }
2952 
2953  return getVolumeType(0, sample);
2954 }
2955 
2956 
2957 template<class Type>
2958 template<class CompareOp>
2961  const scalar nearDist,
2962  const indexedOctree<Type>& tree2,
2963  CompareOp& cop
2964 ) const
2965 {
2966  findNear
2967  (
2968  nearDist,
2969  true,
2970  *this,
2971  nodePlusOctant(0, 0),
2972  bb(),
2973  tree2,
2974  nodePlusOctant(0, 0),
2975  tree2.bb(),
2976  cop
2977  );
2978 }
2979 
2980 
2981 // Print contents of nodeI
2982 template<class Type>
2985  prefixOSstream& os,
2986  const bool printContents,
2987  const label nodeI
2988 ) const
2989 {
2990  const node& nod = nodes_[nodeI];
2991  const treeBoundBox& bb = nod.bb_;
2992 
2993  os << "nodeI:" << nodeI << " bb:" << bb << nl
2994  << "parent:" << nod.parent_ << nl
2995  << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
2996 
2997  for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
2998  {
2999  const treeBoundBox subBb(bb.subBbox(octant));
3000 
3001  labelBits index = nod.subNodes_[octant];
3002 
3003  if (isNode(index))
3004  {
3005  // tree node.
3006  label subNodeI = getNode(index);
3007 
3008  os << "octant:" << octant
3009  << " node: n:" << countElements(index)
3010  << " bb:" << subBb << endl;
3011 
3012  string oldPrefix = os.prefix();
3013  os.prefix() = " " + oldPrefix;
3014 
3015  print(os, printContents, subNodeI);
3016 
3017  os.prefix() = oldPrefix;
3018  }
3019  else if (isContent(index))
3020  {
3021  const labelList& indices = contents_[getContent(index)];
3022 
3023  if (debug)
3024  {
3025  writeOBJ(nodeI, octant);
3026  }
3027 
3028  os << "octant:" << octant
3029  << " content: n:" << indices.size()
3030  << " bb:" << subBb;
3031 
3032  if (printContents)
3033  {
3034  os << " contents:";
3035  forAll(indices, j)
3036  {
3037  os << ' ' << indices[j];
3038  }
3039  }
3040  os << endl;
3041  }
3042  else
3043  {
3044  if (debug)
3045  {
3046  writeOBJ(nodeI, octant);
3047  }
3048 
3049  os << "octant:" << octant << " empty:" << subBb << endl;
3050  }
3051  }
3052 }
3053 
3054 
3055 // Print contents of nodeI
3056 template<class Type>
3058 {
3059  os << *this;
3060 
3061  return os.good();
3062 }
3063 
3064 
3065 template<class Type>
3067 {
3068  return
3069  os << t.bb() << token::SPACE << t.nodes()
3070  << token::SPACE << t.contents();
3071 }
3072 
3073 
3074 // ************************************************************************* //
Foam::indexedOctree::traverseNode
void traverseNode(const bool findAny, const point &treeStart, const vector &treeVec, const point &start, const point &end, const label nodeI, const direction octantI, pointIndexHit &hitInfo, direction &faceID, const FindIntersectOp &fiOp) const
Traverse a node. If intersects a triangle return first.
Definition: indexedOctree.C:1567
Foam::indexedOctree::findNear
static void findNear(const scalar nearDist, const bool okOrder, const indexedOctree< Type > &tree1, const labelBits index1, const treeBoundBox &bb1, const indexedOctree< Type > &tree2, const labelBits index2, const treeBoundBox &bb2, CompareOp &cop)
Definition: indexedOctree.C:2090
Foam::boundBox::midpoint
point midpoint() const
The midpoint of the bounding box.
Definition: boundBoxI.H:78
Foam::word
A class for handling words, derived from string.
Definition: word.H:59
Foam::indexedOctree::indexedOctree
indexedOctree(const Type &shapes)
Construct null.
Definition: indexedOctree.C:2345
print
void print(const char *msg, Ostream &os, const PtrList< GeoField > &flds)
Definition: foamToVTK.C:164
Foam::labelBits
A 29bits label and 3bits direction packed into single label.
Definition: labelBits.H:51
Foam::labelList
List< label > labelList
A List of labels.
Definition: labelList.H:56
Foam::PointIndexHit::setIndex
void setIndex(const label index)
Definition: PointIndexHit.H:168
Foam::boundBox::max
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:60
Foam::HashTable::toc
List< Key > toc() const
Return the table of contents.
Definition: HashTable.C:201
Foam::indexedOctree::pushPointIntoFace
static point pushPointIntoFace(const treeBoundBox &bb, const vector &dir, const point &pt)
Helper: take point on face(s) of bb and push it away from.
Definition: indexedOctree.C:870
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
writeOBJ
void writeOBJ(Ostream &os, label &vertI, const tetPoints &tet)
Definition: Test-tetTetOverlap.C:38
Foam::treeBoundBox::points
tmp< pointField > points() const
Vertex coordinates. In octant coding.
Definition: treeBoundBox.C:163
Foam::indexedOctree::isContent
static bool isContent(const labelBits i)
Definition: indexedOctree.H:481
Foam::indexedOctree::countElements
label countElements(const labelBits index) const
Count number of elements on this and sublevels.
Definition: indexedOctree.C:2264
Foam::DynamicList
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:56
Foam::diag
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
Definition: pointPatchFieldFunctions.H:262
Foam::treeBoundBox
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:75
Foam::indexedOctree::isNode
static bool isNode(const labelBits i)
Definition: indexedOctree.H:491
indexedOctree.H
Foam::indexedOctree::node
Tree node. Has up pointer and down pointers.
Definition: indexedOctree.H:78
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
Foam::PointIndexHit::hit
bool hit() const
Is there a hit.
Definition: PointIndexHit.H:105
Foam::indexedOctree::nodes
const List< node > & nodes() const
List of all nodes.
Definition: indexedOctree.H:455
Foam::List::transfer
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Foam::treeBoundBox::posBits
direction posBits(const point &) const
Position of point relative to bounding box.
Definition: treeBoundBox.C:469
Foam::indexedOctree::shapes
const Type & shapes() const
Reference to shape.
Definition: indexedOctree.H:449
Foam::treeBoundBox::subBbox
treeBoundBox subBbox(const direction) const
Sub box given by octant number. Midpoint calculated.
Definition: treeBoundBox.C:178
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::HashSet< label, Hash< label > >
Foam::indexedOctree::faceString
static word faceString(const direction faceID)
Debug: return verbose the bounding box faces.
Definition: indexedOctree.C:1514
Foam::indexedOctree::getNode
static label getNode(const labelBits i)
Definition: indexedOctree.H:506
Foam::indexedOctree::walkToNeighbour
bool walkToNeighbour(const point &facePoint, const direction faceID, label &nodeI, direction &octant) const
Walk tree to neighbouring node. Return false if edge of tree.
Definition: indexedOctree.C:1276
Foam::indexedOctree::perturbTol
static scalar & perturbTol()
Get the perturbation tolerance.
Definition: indexedOctree.C:2550
OFstream.H
Foam::divide
void divide(FieldField< Field, Type > &f, const FieldField< Field, Type > &f1, const FieldField< Field, scalar > &f2)
Foam::facePoint
label facePoint(const int facei, const block &block, const label i, const label j)
Definition: blockMeshMergeFast.C:202
Foam::indexedOctree::splitNodes
void splitNodes(const label minSize, DynamicList< node > &nodes, DynamicList< labelList > &contents) const
Split any contents node with more than minSize elements.
Definition: indexedOctree.C:240
Foam::boundBox::span
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:84
Foam::prefixOSstream
Version of OSstream which prints a prefix on each line.
Definition: prefixOSstream.H:51
Foam::PointIndexHit
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:53
Foam::PointIndexHit::rawPoint
const Point & rawPoint() const
Return point with no checking.
Definition: PointIndexHit.H:143
Foam::indexedOctree::findBox
void findBox(const label nodeI, const treeBoundBox &searchBox, labelHashSet &elements) const
Find all elements intersecting box.
Definition: indexedOctree.C:1994
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::volumeType
Definition: volumeType.H:54
Foam::indexedOctree::findNode
labelBits findNode(const label nodeI, const point &) const
Find deepest node (as parent+octant) containing point. Starts.
Definition: indexedOctree.C:2782
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:57
Foam::List::append
void append(const T &)
Append an element at the end of the list.
Foam::indexedOctree::findLine
pointIndexHit findLine(const bool findAny, const point &treeStart, const point &treeEnd, const label startNodeI, const direction startOctantI, const FindIntersectOp &fiOp, const bool verbose=false) const
Find any or nearest intersection.
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::treeBoundBox::intersects
bool intersects(const point &overallStart, const vector &overallVec, const point &start, const point &end, point &pt, direction &ptBits) const
Intersects segment; set point to intersection position and face,.
Definition: treeBoundBox.C:253
Foam::indexedOctree::compactContents
static label compactContents(DynamicList< node > &nodes, DynamicList< labelList > &contents, const label compactLevel, const label nodeI, const label level, List< labelList > &compactedContents, label &compactI)
Definition: indexedOctree.C:294
Foam::indexedOctree::calcVolumeType
volumeType calcVolumeType(const label nodeI) const
Determine inside/outside per node (mixed if cannot be.
Definition: indexedOctree.C:364
Foam::DynamicList::clear
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:242
Foam::indexedOctree::contents
const labelListList & contents() const
List of all contents (referenced by those nodes that are.
Definition: indexedOctree.H:462
Foam::indexedOctree
Non-pointer based hierarchical recursive searching.
Definition: treeDataTriSurface.H:47
Foam::PointIndexHit::setHit
void setHit()
Definition: PointIndexHit.H:153
Foam::DynamicList::shrink
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:258
Foam::boundBox::min
const point & min() const
Minimum describing the bounding box.
Definition: boundBoxI.H:54
Foam::operator<<
Ostream & operator<<(Ostream &, const edgeMesh &)
Definition: edgeMeshIO.C:130
Foam::indexedOctree::findInside
label findInside(const point &) const
Find shape containing point. Only implemented for certain.
Definition: indexedOctree.C:2828
Foam::indexedOctree::print
void print(prefixOSstream &, const bool printContents, const label) const
Print tree. Either print all indices (printContent = true) or.
Definition: indexedOctree.C:2984
Foam::indexedOctree::writeOBJ
void writeOBJ(const label nodeI, const direction octant) const
Dump node+octant to an obj file.
Definition: indexedOctree.C:2297
Foam::identity
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Foam::Vector::x
const Cmpt & x() const
Definition: VectorI.H:65
Foam::FatalError
error FatalError
Foam::indexedOctree::overlaps
static bool overlaps(const treeBoundBox &parentBb, const direction octant, const scalar nearestDistSqr, const point &sample)
Helper: does bb intersect a sphere around sample? Or is any.
Definition: indexedOctree.C:61
Foam::memInfo
Memory usage information for the process running this object.
Definition: memInfo.H:53
Foam::Vector::z
const Cmpt & z() const
Definition: VectorI.H:77
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:131
Foam::indexedOctree::divide
void divide(const labelList &indices, const treeBoundBox &bb, labelListList &result) const
Split list of indices into 8 bins.
Definition: indexedOctree.C:124
Foam::PointIndexHit::setPoint
void setPoint(const Point &p)
Definition: PointIndexHit.H:163
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
s
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Foam::indexedOctree::pushPoint
static point pushPoint(const treeBoundBox &, const point &, const bool pushInside)
Helper: take a point on/close to face of bb and push it.
Foam::DynamicList::append
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Foam::OFstream
Output to file stream.
Definition: OFstream.H:81
Foam::indexedOctree::bb
const treeBoundBox & bb() const
Top bounding box.
Definition: indexedOctree.H:468
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
memInfo.H
Foam::List::setSize
void setSize(const label)
Reset size of List.
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::pointIndexHit
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:42
Foam::treeBoundBox::contains
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
Definition: treeBoundBox.C:395
Foam::Pout
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Foam::Vector< scalar >
Foam::indexedOctree::getContent
static label getContent(const labelBits i)
Definition: indexedOctree.H:496
Foam::indexedOctree::getSide
static volumeType getSide(const vector &outsideNormal, const vector &vec)
Helper function to return the side. Returns outside if.
Definition: indexedOctree.C:487
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::FixedList::size
label size() const
Return the number of elements in the FixedList.
Definition: FixedListI.H:408
Foam::treeBoundBox::faceBits
direction faceBits(const point &) const
Code position of point on bounding box faces.
Definition: treeBoundBox.C:435
Foam::FixedList
A 1D vector of objects of type <T> with a fixed size <Size>.
Definition: FixedList.H:53
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: doubleFloat.H:94
Foam::DynamicList::transfer
void transfer(List< T > &)
Transfer contents of the argument List into this.
Foam::indexedOctree::findIndices
const labelList & findIndices(const point &) const
Find the shape indices that occupy the result of findNode.
Definition: indexedOctree.C:2858
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
Foam::direction
unsigned char direction
Definition: direction.H:43
Foam::line
A line primitive.
Definition: line.H:56
Foam::indexedOctree::findLineAny
pointIndexHit findLineAny(const point &start, const point &end) const
Find any intersection of line between start and end.
Foam::ln
bool ln(const fileName &src, const fileName &dst)
Create a softlink. dst should not exist. Returns true if successful.
Definition: POSIX.C:854
Foam::indexedOctree::findNearest
void findNearest(const label nodeI, const linePointRef &ln, treeBoundBox &tightest, label &nearestShapeI, point &linePoint, point &nearestPoint, const FindNearestOp &fnOp) const
Find nearest point to line.
Definition: indexedOctree.C:590
Foam::indexedOctree::getVolumeType
volumeType getVolumeType(const label nodeI, const point &) const
Search cached volume type.
Foam::Vector::y
const Cmpt & y() const
Definition: VectorI.H:71
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
Foam::treeBoundBox::overlaps
bool overlaps(const boundBox &) const
Overlaps other bounding box?
Definition: boundBoxI.H:120
ListOps.H
Various functions to operate on Lists.
Foam::indexedOctree::walkToParent
bool walkToParent(const label nodeI, const direction octant, label &parentNodeI, label &parentOctant) const
Walk to parent of node+octant.
Definition: indexedOctree.C:1226
Foam::OFstream::name
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:118
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:53
Foam::point
vector point
Point is a vector.
Definition: point.H:41
Foam::memInfo::size
int size() const
Access the stored memory size (VmSize in /proc/<pid>/status)
Definition: memInfo.H:95
Foam::IOstream::good
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
Foam::type
fileName::Type type(const fileName &)
Return the file type: DIRECTORY or FILE.
Definition: POSIX.C:588
Foam::indexedOctree::subBbox
treeBoundBox subBbox(const label parentNodeI, const direction octant) const
Return bbox of octant.
Definition: indexedOctree.C:660
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:259
Foam::prefixOSstream::prefix
const string & prefix() const
Return the prefix of the stream.
Definition: prefixOSstream.H:86
Foam::name
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Foam::indexedOctree::findSphere
void findSphere(const label nodeI, const point &centre, const scalar radiusSqr, labelHashSet &elements) const
Find all elements intersecting sphere.
Definition: indexedOctree.C:2041
Y
PtrList< volScalarField > & Y
Definition: createFields.H:36
linePointRef.H
Foam::indexedOctree::write
bool write(Ostream &os) const
Definition: indexedOctree.C:3057