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