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