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