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