00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "indexedOctree.H"
00027 #include <OpenFOAM/linePointRef.H>
00028 #include <meshTools/meshTools.H>
00029 #include <OpenFOAM/OFstream.H>
00030
00031
00032
00033 template <class Type>
00034 Foam::scalar Foam::indexedOctree<Type>::perturbTol_ = 10*SMALL;
00035
00036
00037
00038
00039
00040
00041 template <class Type>
00042 bool Foam::indexedOctree<Type>::overlaps
00043 (
00044 const point& p0,
00045 const point& p1,
00046 const scalar nearestDistSqr,
00047 const point& sample
00048 )
00049 {
00050
00051
00052 scalar distSqr = 0;
00053
00054 for (direction dir = 0; dir < vector::nComponents; dir++)
00055 {
00056 scalar d0 = p0[dir] - sample[dir];
00057 scalar d1 = p1[dir] - sample[dir];
00058
00059 if ((d0 > 0) != (d1 > 0))
00060 {
00061
00062
00063 }
00064 else if (mag(d0) < mag(d1))
00065 {
00066 distSqr += d0*d0;
00067 }
00068 else
00069 {
00070 distSqr += d1*d1;
00071 }
00072
00073 if (distSqr > nearestDistSqr)
00074 {
00075 return false;
00076 }
00077 }
00078
00079 return true;
00080 }
00081
00082
00083
00084
00085 template <class Type>
00086 bool Foam::indexedOctree<Type>::overlaps
00087 (
00088 const treeBoundBox& parentBb,
00089 const direction octant,
00090 const scalar nearestDistSqr,
00091 const point& sample
00092 )
00093 {
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 const point& min = parentBb.min();
00105 const point& max = parentBb.max();
00106
00107 point other;
00108
00109 if (octant & treeBoundBox::RIGHTHALF)
00110 {
00111 other.x() = max.x();
00112 }
00113 else
00114 {
00115 other.x() = min.x();
00116 }
00117
00118 if (octant & treeBoundBox::TOPHALF)
00119 {
00120 other.y() = max.y();
00121 }
00122 else
00123 {
00124 other.y() = min.y();
00125 }
00126
00127 if (octant & treeBoundBox::FRONTHALF)
00128 {
00129 other.z() = max.z();
00130 }
00131 else
00132 {
00133 other.z() = min.z();
00134 }
00135
00136 const point mid(0.5*(min+max));
00137
00138 return overlaps(mid, other, nearestDistSqr, sample);
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148 template <class Type>
00149 void Foam::indexedOctree<Type>::divide
00150 (
00151 const labelList& indices,
00152 const treeBoundBox& bb,
00153 labelListList& result
00154 ) const
00155 {
00156 List<DynamicList<label> > subIndices(8);
00157 for (direction octant = 0; octant < subIndices.size(); octant++)
00158 {
00159 subIndices[octant].setCapacity(indices.size()/8);
00160 }
00161
00162
00163 FixedList<treeBoundBox, 8> subBbs;
00164 for (direction octant = 0; octant < subBbs.size(); octant++)
00165 {
00166 subBbs[octant] = bb.subBbox(octant);
00167 }
00168
00169 forAll(indices, i)
00170 {
00171 label shapeI = indices[i];
00172
00173 for (direction octant = 0; octant < 8; octant++)
00174 {
00175 if (shapes_.overlaps(shapeI, subBbs[octant]))
00176 {
00177 subIndices[octant].append(shapeI);
00178 }
00179 }
00180 }
00181
00182 result.setSize(8);
00183 for (direction octant = 0; octant < subIndices.size(); octant++)
00184 {
00185 result[octant].transfer(subIndices[octant]);
00186 }
00187 }
00188
00189
00190
00191 template <class Type>
00192 typename Foam::indexedOctree<Type>::node
00193 Foam::indexedOctree<Type>::divide
00194 (
00195 const treeBoundBox& bb,
00196 DynamicList<labelList>& contents,
00197 const label contentI
00198 ) const
00199 {
00200 const labelList& indices = contents[contentI];
00201
00202 node nod;
00203
00204 if
00205 (
00206 bb.min()[0] >= bb.max()[0]
00207 || bb.min()[1] >= bb.max()[1]
00208 || bb.min()[2] >= bb.max()[2]
00209 )
00210 {
00211 FatalErrorIn("indexedOctree<Type>::divide(..)")
00212 << "Badly formed bounding box:" << bb
00213 << abort(FatalError);
00214 }
00215
00216 nod.bb_ = bb;
00217 nod.parent_ = -1;
00218
00219 labelListList dividedIndices(8);
00220 divide(indices, bb, dividedIndices);
00221
00222
00223
00224
00225 bool replaced = false;
00226
00227 for (direction octant = 0; octant < dividedIndices.size(); octant++)
00228 {
00229 labelList& subIndices = dividedIndices[octant];
00230
00231 if (subIndices.size())
00232 {
00233 if (!replaced)
00234 {
00235 contents[contentI].transfer(subIndices);
00236 nod.subNodes_[octant] = contentPlusOctant(contentI, octant);
00237 replaced = true;
00238 }
00239 else
00240 {
00241
00242
00243 label sz = contents.size();
00244 contents.append(labelList(0));
00245 contents[sz].transfer(subIndices);
00246 nod.subNodes_[octant] = contentPlusOctant(sz, octant);
00247 }
00248 }
00249 else
00250 {
00251
00252 nod.subNodes_[octant] = emptyPlusOctant(octant);
00253 }
00254 }
00255
00256 return nod;
00257 }
00258
00259
00260
00261 template <class Type>
00262 void Foam::indexedOctree<Type>::splitNodes
00263 (
00264 const label minSize,
00265 DynamicList<indexedOctree<Type>::node>& nodes,
00266 DynamicList<labelList>& contents
00267 ) const
00268 {
00269 label currentSize = nodes.size();
00270
00271
00272
00273
00274 for (label nodeI = 0; nodeI < currentSize; nodeI++)
00275 {
00276 for
00277 (
00278 direction octant = 0;
00279 octant < nodes[nodeI].subNodes_.size();
00280 octant++
00281 )
00282 {
00283 labelBits index = nodes[nodeI].subNodes_[octant];
00284
00285 if (isNode(index))
00286 {
00287
00288 }
00289 else if (isContent(index))
00290 {
00291 label contentI = getContent(index);
00292
00293 if (contents[contentI].size() > minSize)
00294 {
00295
00296
00297
00298 const node& nod = nodes[nodeI];
00299 const treeBoundBox bb(nod.bb_.subBbox(octant));
00300
00301 node subNode(divide(bb, contents, contentI));
00302 subNode.parent_ = nodeI;
00303 label sz = nodes.size();
00304 nodes.append(subNode);
00305 nodes[nodeI].subNodes_[octant] = nodePlusOctant(sz, octant);
00306 }
00307 }
00308 }
00309 }
00310 }
00311
00312
00313
00314
00315 template <class Type>
00316 Foam::label Foam::indexedOctree<Type>::compactContents
00317 (
00318 DynamicList<node>& nodes,
00319 DynamicList<labelList>& contents,
00320 const label compactLevel,
00321 const label nodeI,
00322 const label level,
00323
00324 List<labelList>& compactedContents,
00325 label& compactI
00326 )
00327 {
00328 const node& nod = nodes[nodeI];
00329
00330 label nNodes = 0;
00331
00332 if (level < compactLevel)
00333 {
00334 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
00335 {
00336 labelBits index = nod.subNodes_[octant];
00337
00338 if (isNode(index))
00339 {
00340 nNodes += compactContents
00341 (
00342 nodes,
00343 contents,
00344 compactLevel,
00345 getNode(index),
00346 level+1,
00347 compactedContents,
00348 compactI
00349 );
00350 }
00351 }
00352 }
00353 else if (level == compactLevel)
00354 {
00355
00356 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
00357 {
00358 labelBits index = nod.subNodes_[octant];
00359
00360 if (isContent(index))
00361 {
00362 label contentI = getContent(index);
00363
00364 compactedContents[compactI].transfer(contents[contentI]);
00365
00366
00367 nodes[nodeI].subNodes_[octant] =
00368 contentPlusOctant(compactI, octant);
00369
00370 compactI++;
00371 }
00372 else if (isNode(index))
00373 {
00374 nNodes++;
00375 }
00376 }
00377 }
00378 return nNodes;
00379 }
00380
00381
00382
00383
00384
00385 template <class Type>
00386 typename Foam::indexedOctree<Type>::volumeType
00387 Foam::indexedOctree<Type>::calcVolumeType
00388 (
00389 const label nodeI
00390 ) const
00391 {
00392 const node& nod = nodes_[nodeI];
00393
00394 volumeType myType = UNKNOWN;
00395
00396 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
00397 {
00398 volumeType subType;
00399
00400 labelBits index = nod.subNodes_[octant];
00401
00402 if (isNode(index))
00403 {
00404
00405 subType = calcVolumeType(getNode(index));
00406 }
00407 else if (isContent(index))
00408 {
00409
00410
00411 subType = MIXED;
00412 }
00413 else
00414 {
00415
00416
00417 const treeBoundBox subBb = nod.bb_.subBbox(octant);
00418
00419 subType = volumeType
00420 (
00421 shapes_.getVolumeType(*this, subBb.midpoint())
00422 );
00423 }
00424
00425
00426 nodeTypes_.set((nodeI<<3)+octant, subType);
00427
00428
00429
00430 if (myType == UNKNOWN)
00431 {
00432 myType = subType;
00433 }
00434 else if (subType != myType)
00435 {
00436 myType = MIXED;
00437 }
00438 }
00439 return myType;
00440 }
00441
00442
00443 template <class Type>
00444 typename Foam::indexedOctree<Type>::volumeType
00445 Foam::indexedOctree<Type>::getVolumeType
00446 (
00447 const label nodeI,
00448 const point& sample
00449 ) const
00450 {
00451 const node& nod = nodes_[nodeI];
00452
00453 direction octant = nod.bb_.subOctant(sample);
00454
00455 volumeType octantType = volumeType(nodeTypes_.get((nodeI<<3)+octant));
00456
00457 if (octantType == INSIDE)
00458 {
00459 return octantType;
00460 }
00461 else if (octantType == OUTSIDE)
00462 {
00463 return octantType;
00464 }
00465 else if (octantType == UNKNOWN)
00466 {
00467
00468 return octantType;
00469 }
00470 else if (octantType == MIXED)
00471 {
00472 labelBits index = nod.subNodes_[octant];
00473
00474 if (isNode(index))
00475 {
00476
00477 volumeType subType = getVolumeType(getNode(index), sample);
00478
00479 return subType;
00480 }
00481 else if (isContent(index))
00482 {
00483
00484 return volumeType(shapes_.getVolumeType(*this, sample));
00485 }
00486 else
00487 {
00488
00489
00490 FatalErrorIn
00491 (
00492 "indexedOctree<Type>::getVolumeType"
00493 "(const label, const point&)"
00494 ) << "Sample:" << sample << " node:" << nodeI
00495 << " with bb:" << nodes_[nodeI].bb_ << nl
00496 << "Empty subnode has invalid volume type MIXED."
00497 << abort(FatalError);
00498
00499 return UNKNOWN;
00500 }
00501 }
00502 else
00503 {
00504 FatalErrorIn
00505 (
00506 "indexedOctree<Type>::getVolumeType"
00507 "(const label, const point&)"
00508 ) << "Sample:" << sample << " at node:" << nodeI
00509 << " octant:" << octant
00510 << " with bb:" << nod.bb_.subBbox(octant) << nl
00511 << "Node has invalid volume type " << octantType
00512 << abort(FatalError);
00513
00514 return UNKNOWN;
00515 }
00516 }
00517
00518
00519 template <class Type>
00520 typename Foam::indexedOctree<Type>::volumeType
00521 Foam::indexedOctree<Type>::getSide
00522 (
00523 const vector& outsideNormal,
00524 const vector& vec
00525 )
00526 {
00527 if ((outsideNormal&vec) >= 0)
00528 {
00529 return OUTSIDE;
00530 }
00531 else
00532 {
00533 return INSIDE;
00534 }
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544 template <class Type>
00545 void Foam::indexedOctree<Type>::findNearest
00546 (
00547 const label nodeI,
00548 const point& sample,
00549
00550 scalar& nearestDistSqr,
00551 label& nearestShapeI,
00552 point& nearestPoint
00553 ) const
00554 {
00555 const node& nod = nodes_[nodeI];
00556
00557
00558 FixedList<direction, 8> octantOrder;
00559 nod.bb_.searchOrder(sample, octantOrder);
00560
00561
00562 for (direction i = 0; i < 8; i++)
00563 {
00564 direction octant = octantOrder[i];
00565
00566 labelBits index = nod.subNodes_[octant];
00567
00568 if (isNode(index))
00569 {
00570 label subNodeI = getNode(index);
00571
00572 const treeBoundBox& subBb = nodes_[subNodeI].bb_;
00573
00574 if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
00575 {
00576 findNearest
00577 (
00578 subNodeI,
00579 sample,
00580
00581 nearestDistSqr,
00582 nearestShapeI,
00583 nearestPoint
00584 );
00585 }
00586 }
00587 else if (isContent(index))
00588 {
00589 if
00590 (
00591 overlaps
00592 (
00593 nod.bb_,
00594 octant,
00595 nearestDistSqr,
00596 sample
00597 )
00598 )
00599 {
00600 shapes_.findNearest
00601 (
00602 contents_[getContent(index)],
00603 sample,
00604
00605 nearestDistSqr,
00606 nearestShapeI,
00607 nearestPoint
00608 );
00609 }
00610 }
00611 }
00612 }
00613
00614
00615
00616 template <class Type>
00617 void Foam::indexedOctree<Type>::findNearest
00618 (
00619 const label nodeI,
00620 const linePointRef& ln,
00621
00622 treeBoundBox& tightest,
00623 label& nearestShapeI,
00624 point& linePoint,
00625 point& nearestPoint
00626 ) const
00627 {
00628 const node& nod = nodes_[nodeI];
00629 const treeBoundBox& nodeBb = nod.bb_;
00630
00631
00632 FixedList<direction, 8> octantOrder;
00633 nod.bb_.searchOrder(ln.centre(), octantOrder);
00634
00635
00636 for (direction i = 0; i < 8; i++)
00637 {
00638 direction octant = octantOrder[i];
00639
00640 labelBits index = nod.subNodes_[octant];
00641
00642 if (isNode(index))
00643 {
00644 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
00645
00646 if (subBb.overlaps(tightest))
00647 {
00648 findNearest
00649 (
00650 getNode(index),
00651 ln,
00652
00653 tightest,
00654 nearestShapeI,
00655 linePoint,
00656 nearestPoint
00657 );
00658 }
00659 }
00660 else if (isContent(index))
00661 {
00662 const treeBoundBox subBb(nodeBb.subBbox(octant));
00663
00664 if (subBb.overlaps(tightest))
00665 {
00666 shapes_.findNearest
00667 (
00668 contents_[getContent(index)],
00669 ln,
00670
00671 tightest,
00672 nearestShapeI,
00673 linePoint,
00674 nearestPoint
00675 );
00676 }
00677 }
00678 }
00679 }
00680
00681
00682 template <class Type>
00683 Foam::treeBoundBox Foam::indexedOctree<Type>::subBbox
00684 (
00685 const label parentNodeI,
00686 const direction octant
00687 ) const
00688 {
00689
00690 const node& nod = nodes_[parentNodeI];
00691 labelBits index = nod.subNodes_[octant];
00692
00693 if (isNode(index))
00694 {
00695
00696 return nodes_[getNode(index)].bb_;
00697 }
00698 else
00699 {
00700
00701 return nod.bb_.subBbox(octant);
00702 }
00703 }
00704
00705
00706
00707
00708 template <class Type>
00709 Foam::point Foam::indexedOctree<Type>::pushPoint
00710 (
00711 const treeBoundBox& bb,
00712 const point& pt,
00713 const bool pushInside
00714 )
00715 {
00716
00717 const vector perturbVec = perturbTol_*(bb.span());
00718
00719 point perturbedPt(pt);
00720
00721
00722
00723
00724 if (pushInside)
00725 {
00726 for (direction dir = 0; dir < vector::nComponents; dir++)
00727 {
00728 if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
00729 {
00730
00731 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
00732 perturbedPt[dir] = bb.min()[dir] + perturbDist;
00733 }
00734 else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
00735 {
00736
00737 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
00738 perturbedPt[dir] = bb.max()[dir] - perturbDist;
00739 }
00740 }
00741 }
00742 else
00743 {
00744 for (direction dir = 0; dir < vector::nComponents; dir++)
00745 {
00746 if (mag(pt[dir]-bb.min()[dir]) < mag(perturbVec[dir]))
00747 {
00748 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
00749 perturbedPt[dir] = bb.min()[dir] - perturbDist;
00750 }
00751 else if (mag(pt[dir]-bb.max()[dir]) < mag(perturbVec[dir]))
00752 {
00753 scalar perturbDist = perturbVec[dir] + ROOTVSMALL;
00754 perturbedPt[dir] = bb.max()[dir] + perturbDist;
00755 }
00756 }
00757 }
00758
00759 if (debug)
00760 {
00761 if (pushInside != bb.contains(perturbedPt))
00762 {
00763 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
00764 << "pushed point:" << pt
00765 << " to:" << perturbedPt
00766 << " wanted side:" << pushInside
00767 << " obtained side:" << bb.contains(perturbedPt)
00768 << " of bb:" << bb
00769 << abort(FatalError);
00770 }
00771 }
00772
00773 return perturbedPt;
00774 }
00775
00776
00777
00778
00779 template <class Type>
00780 Foam::point Foam::indexedOctree<Type>::pushPoint
00781 (
00782 const treeBoundBox& bb,
00783 const direction faceID,
00784 const point& pt,
00785 const bool pushInside
00786 )
00787 {
00788
00789 const vector perturbVec = perturbTol_*bb.span();
00790
00791 point perturbedPt(pt);
00792
00793
00794
00795
00796 if (faceID == 0)
00797 {
00798 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
00799 << abort(FatalError);
00800 }
00801
00802 if (faceID & treeBoundBox::LEFTBIT)
00803 {
00804 if (pushInside)
00805 {
00806 perturbedPt[0] = bb.min()[0] + (perturbVec[0] + ROOTVSMALL);
00807 }
00808 else
00809 {
00810 perturbedPt[0] = bb.min()[0] - (perturbVec[0] + ROOTVSMALL);
00811 }
00812 }
00813 else if (faceID & treeBoundBox::RIGHTBIT)
00814 {
00815 if (pushInside)
00816 {
00817 perturbedPt[0] = bb.max()[0] - (perturbVec[0] + ROOTVSMALL);
00818 }
00819 else
00820 {
00821 perturbedPt[0] = bb.max()[0] + (perturbVec[0] + ROOTVSMALL);
00822 }
00823 }
00824
00825 if (faceID & treeBoundBox::BOTTOMBIT)
00826 {
00827 if (pushInside)
00828 {
00829 perturbedPt[1] = bb.min()[1] + (perturbVec[1] + ROOTVSMALL);
00830 }
00831 else
00832 {
00833 perturbedPt[1] = bb.min()[1] - (perturbVec[1] + ROOTVSMALL);
00834 }
00835 }
00836 else if (faceID & treeBoundBox::TOPBIT)
00837 {
00838 if (pushInside)
00839 {
00840 perturbedPt[1] = bb.max()[1] - (perturbVec[1] + ROOTVSMALL);
00841 }
00842 else
00843 {
00844 perturbedPt[1] = bb.max()[1] + (perturbVec[1] + ROOTVSMALL);
00845 }
00846 }
00847
00848 if (faceID & treeBoundBox::BACKBIT)
00849 {
00850 if (pushInside)
00851 {
00852 perturbedPt[2] = bb.min()[2] + (perturbVec[2] + ROOTVSMALL);
00853 }
00854 else
00855 {
00856 perturbedPt[2] = bb.min()[2] - (perturbVec[2] + ROOTVSMALL);
00857 }
00858 }
00859 else if (faceID & treeBoundBox::FRONTBIT)
00860 {
00861 if (pushInside)
00862 {
00863 perturbedPt[2] = bb.max()[2] - (perturbVec[2] + ROOTVSMALL);
00864 }
00865 else
00866 {
00867 perturbedPt[2] = bb.max()[2] + (perturbVec[2] + ROOTVSMALL);
00868 }
00869 }
00870
00871 if (debug)
00872 {
00873 if (pushInside != bb.contains(perturbedPt))
00874 {
00875 FatalErrorIn("indexedOctree<Type>::pushPoint(..)")
00876 << "pushed point:" << pt << " on face:" << faceString(faceID)
00877 << " to:" << perturbedPt
00878 << " wanted side:" << pushInside
00879 << " obtained side:" << bb.contains(perturbedPt)
00880 << " of bb:" << bb
00881 << abort(FatalError);
00882 }
00883 }
00884
00885 return perturbedPt;
00886 }
00887
00888
00889
00890
00891
00892 template <class Type>
00893 Foam::point Foam::indexedOctree<Type>::pushPointIntoFace
00894 (
00895 const treeBoundBox& bb,
00896 const vector& dir,
00897 const point& pt
00898 )
00899 {
00900 if (debug)
00901 {
00902 if (bb.posBits(pt) != 0)
00903 {
00904 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
00905 << " bb:" << bb << endl
00906 << "does not contain point " << pt << abort(FatalError);
00907 }
00908 }
00909
00910
00911
00912
00913
00914
00915 direction ptFaceID = bb.faceBits(pt);
00916
00917 direction nFaces = 0;
00918 FixedList<direction, 3> faceIndices;
00919
00920 if (ptFaceID & treeBoundBox::LEFTBIT)
00921 {
00922 faceIndices[nFaces++] = treeBoundBox::LEFT;
00923 }
00924 else if (ptFaceID & treeBoundBox::RIGHTBIT)
00925 {
00926 faceIndices[nFaces++] = treeBoundBox::RIGHT;
00927 }
00928
00929 if (ptFaceID & treeBoundBox::BOTTOMBIT)
00930 {
00931 faceIndices[nFaces++] = treeBoundBox::BOTTOM;
00932 }
00933 else if (ptFaceID & treeBoundBox::TOPBIT)
00934 {
00935 faceIndices[nFaces++] = treeBoundBox::TOP;
00936 }
00937
00938 if (ptFaceID & treeBoundBox::BACKBIT)
00939 {
00940 faceIndices[nFaces++] = treeBoundBox::BACK;
00941 }
00942 else if (ptFaceID & treeBoundBox::FRONTBIT)
00943 {
00944 faceIndices[nFaces++] = treeBoundBox::FRONT;
00945 }
00946
00947
00948
00949
00950 direction keepFaceID;
00951
00952 if (nFaces == 0)
00953 {
00954
00955 return pt;
00956 }
00957 else if (nFaces == 1)
00958 {
00959
00960 keepFaceID = faceIndices[0];
00961 }
00962 else
00963 {
00964
00965
00966
00967 keepFaceID = faceIndices[0];
00968 scalar maxInproduct = mag(treeBoundBox::faceNormals[keepFaceID] & dir);
00969
00970 for (direction i = 1; i < nFaces; i++)
00971 {
00972 direction face = faceIndices[i];
00973 scalar s = mag(treeBoundBox::faceNormals[face] & dir);
00974 if (s > maxInproduct)
00975 {
00976 maxInproduct = s;
00977 keepFaceID = face;
00978 }
00979 }
00980 }
00981
00982
00983
00984
00985 point facePoint(pushPoint(bb, pt, true));
00986 direction faceID = 0;
00987
00988
00989
00990 if (keepFaceID == treeBoundBox::LEFT)
00991 {
00992 facePoint.x() = bb.min().x();
00993 faceID = treeBoundBox::LEFTBIT;
00994 }
00995 else if (keepFaceID == treeBoundBox::RIGHT)
00996 {
00997 facePoint.x() = bb.max().x();
00998 faceID = treeBoundBox::RIGHTBIT;
00999 }
01000 else if (keepFaceID == treeBoundBox::BOTTOM)
01001 {
01002 facePoint.y() = bb.min().y();
01003 faceID = treeBoundBox::BOTTOMBIT;
01004 }
01005 else if (keepFaceID == treeBoundBox::TOP)
01006 {
01007 facePoint.y() = bb.max().y();
01008 faceID = treeBoundBox::TOPBIT;
01009 }
01010 else if (keepFaceID == treeBoundBox::BACK)
01011 {
01012 facePoint.z() = bb.min().z();
01013 faceID = treeBoundBox::BACKBIT;
01014 }
01015 else if (keepFaceID == treeBoundBox::FRONT)
01016 {
01017 facePoint.z() = bb.max().z();
01018 faceID = treeBoundBox::FRONTBIT;
01019 }
01020
01021
01022 if (debug)
01023 {
01024 if (faceID != bb.faceBits(facePoint))
01025 {
01026 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
01027 << "Pushed point from " << pt
01028 << " on face:" << ptFaceID << " of bb:" << bb << endl
01029 << "onto " << facePoint
01030 << " on face:" << faceID
01031 << " which is not consistent with geometric face "
01032 << bb.faceBits(facePoint)
01033 << abort(FatalError);
01034 }
01035 if (bb.posBits(facePoint) != 0)
01036 {
01037 FatalErrorIn("indexedOctree<Type>::pushPointIntoFace(..)")
01038 << " bb:" << bb << endl
01039 << "does not contain perturbed point "
01040 << facePoint << abort(FatalError);
01041 }
01042 }
01043
01044
01045 return facePoint;
01046 }
01047
01048
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247 template <class Type>
01248 bool Foam::indexedOctree<Type>::walkToParent
01249 (
01250 const label nodeI,
01251 const direction octant,
01252
01253 label& parentNodeI,
01254 label& parentOctant
01255 ) const
01256 {
01257 parentNodeI = nodes_[nodeI].parent_;
01258
01259 if (parentNodeI == -1)
01260 {
01261
01262 return false;
01263 }
01264
01265 const node& parentNode = nodes_[parentNodeI];
01266
01267
01268 parentOctant = 255;
01269
01270 for (direction i = 0; i < parentNode.subNodes_.size(); i++)
01271 {
01272 labelBits index = parentNode.subNodes_[i];
01273
01274 if (isNode(index) && getNode(index) == nodeI)
01275 {
01276 parentOctant = i;
01277 break;
01278 }
01279 }
01280
01281 if (parentOctant == 255)
01282 {
01283 FatalErrorIn("walkToParent(..)")
01284 << "Problem: no parent found for octant:" << octant
01285 << " node:" << nodeI
01286 << abort(FatalError);
01287 }
01288
01289 return true;
01290 }
01291
01292
01293
01294
01295
01296
01297 template <class Type>
01298 bool Foam::indexedOctree<Type>::walkToNeighbour
01299 (
01300 const point& facePoint,
01301 const direction faceID,
01302 label& nodeI,
01303 direction& octant
01304 ) const
01305 {
01306 label oldNodeI = nodeI;
01307 direction oldOctant = octant;
01308
01309
01310
01311
01312
01313
01314 const direction X = treeBoundBox::RIGHTHALF;
01315 const direction Y = treeBoundBox::TOPHALF;
01316 const direction Z = treeBoundBox::FRONTHALF;
01317
01318 direction octantMask = 0;
01319 direction wantedValue = 0;
01320
01321 if ((faceID & treeBoundBox::LEFTBIT) != 0)
01322 {
01323
01324 octantMask |= X;
01325 wantedValue |= X;
01326 }
01327 else if ((faceID & treeBoundBox::RIGHTBIT) != 0)
01328 {
01329 octantMask |= X;
01330 }
01331
01332 if ((faceID & treeBoundBox::BOTTOMBIT) != 0)
01333 {
01334
01335 octantMask |= Y;
01336 wantedValue |= Y;
01337 }
01338 else if ((faceID & treeBoundBox::TOPBIT) != 0)
01339 {
01340
01341 octantMask |= Y;
01342 }
01343
01344 if ((faceID & treeBoundBox::BACKBIT) != 0)
01345 {
01346 octantMask |= Z;
01347 wantedValue |= Z;
01348 }
01349 else if ((faceID & treeBoundBox::FRONTBIT) != 0)
01350 {
01351 octantMask |= Z;
01352 }
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381 while (wantedValue != (octant & octantMask))
01382 {
01383
01384
01385
01386
01387 if (wantedValue & X)
01388 {
01389
01390 if (octant & X)
01391 {
01392
01393 octantMask &= ~X;
01394 wantedValue &= ~X;
01395 }
01396 }
01397 else
01398 {
01399 if (!(octant & X))
01400 {
01401
01402 octantMask &= ~X;
01403 wantedValue &= ~X;
01404 }
01405 }
01406
01407 if (wantedValue & Y)
01408 {
01409 if (octant & Y)
01410 {
01411 octantMask &= ~Y;
01412 wantedValue &= ~Y;
01413 }
01414 }
01415 else
01416 {
01417 if (!(octant & Y))
01418 {
01419 octantMask &= ~Y;
01420 wantedValue &= ~Y;
01421 }
01422 }
01423
01424 if (wantedValue & Z)
01425 {
01426 if (octant & Z)
01427 {
01428 octantMask &= ~Z;
01429 wantedValue &= ~Z;
01430 }
01431 }
01432 else
01433 {
01434 if (!(octant & Z))
01435 {
01436 octantMask &= ~Z;
01437 wantedValue &= ~Z;
01438 }
01439 }
01440
01441
01442 label parentNodeI;
01443 label parentOctant;
01444 walkToParent(nodeI, octant, parentNodeI, parentOctant);
01445
01446 if (parentNodeI == -1)
01447 {
01448
01449 return false;
01450 }
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461 nodeI = parentNodeI;
01462 octant = parentOctant;
01463 }
01464
01465
01466
01467
01468 octant ^= octantMask;
01469
01470
01471
01472
01473
01474 if (debug)
01475 {
01476 const treeBoundBox subBb(subBbox(nodeI, octant));
01477
01478 if (!subBb.contains(facePoint))
01479 {
01480 FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
01481 << "When searching for " << facePoint
01482 << " ended up in node:" << nodeI
01483 << " octant:" << octant
01484 << " with bb:" << subBb
01485 << abort(FatalError);
01486 }
01487 }
01488
01489
01490
01491
01492 labelBits index = nodes_[nodeI].subNodes_[octant];
01493
01494 if (isNode(index))
01495 {
01496 labelBits node = findNode(getNode(index), facePoint);
01497
01498 nodeI = getNode(node);
01499 octant = getOctant(node);
01500 }
01501
01502
01503 if (debug)
01504 {
01505 const treeBoundBox subBb(subBbox(nodeI, octant));
01506
01507 if (nodeI == oldNodeI && octant == oldOctant)
01508 {
01509 FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
01510 << "Did not go to neighbour when searching for " << facePoint
01511 << endl
01512 << " starting from face:" << faceString(faceID)
01513 << " node:" << nodeI
01514 << " octant:" << octant
01515 << " bb:" << subBb
01516 << abort(FatalError);
01517 }
01518
01519 if (!subBb.contains(facePoint))
01520 {
01521 FatalErrorIn("indexedOctree<Type>::walkToNeighbour(..)")
01522 << "When searching for " << facePoint
01523 << " ended up in node:" << nodeI
01524 << " octant:" << octant
01525 << " bb:" << subBb
01526 << abort(FatalError);
01527 }
01528 }
01529
01530
01531 return true;
01532 }
01533
01534
01535 template <class Type>
01536 Foam::word Foam::indexedOctree<Type>::faceString
01537 (
01538 const direction faceID
01539 )
01540 {
01541 word desc;
01542
01543 if (faceID == 0)
01544 {
01545 desc = "noFace";
01546 }
01547 if (faceID & treeBoundBox::LEFTBIT)
01548 {
01549 if (!desc.empty()) desc += "+";
01550 desc += "left";
01551 }
01552 if (faceID & treeBoundBox::RIGHTBIT)
01553 {
01554 if (!desc.empty()) desc += "+";
01555 desc += "right";
01556 }
01557 if (faceID & treeBoundBox::BOTTOMBIT)
01558 {
01559 if (!desc.empty()) desc += "+";
01560 desc += "bottom";
01561 }
01562 if (faceID & treeBoundBox::TOPBIT)
01563 {
01564 if (!desc.empty()) desc += "+";
01565 desc += "top";
01566 }
01567 if (faceID & treeBoundBox::BACKBIT)
01568 {
01569 if (!desc.empty()) desc += "+";
01570 desc += "back";
01571 }
01572 if (faceID & treeBoundBox::FRONTBIT)
01573 {
01574 if (!desc.empty()) desc += "+";
01575 desc += "front";
01576 }
01577 return desc;
01578 }
01579
01580
01581
01582
01583
01584
01585
01586
01587 template <class Type>
01588 void Foam::indexedOctree<Type>::traverseNode
01589 (
01590 const bool findAny,
01591 const point& treeStart,
01592 const vector& treeVec,
01593
01594 const point& start,
01595 const point& end,
01596 const label nodeI,
01597 const direction octant,
01598
01599 pointIndexHit& hitInfo,
01600 direction& hitBits
01601 ) const
01602 {
01603 if (debug)
01604 {
01605 const treeBoundBox octantBb(subBbox(nodeI, octant));
01606
01607 if (octantBb.posBits(start) != 0)
01608 {
01609 FatalErrorIn("indexedOctree<Type>::traverseNode(..)")
01610 << "Node:" << nodeI << " octant:" << octant
01611 << " bb:" << octantBb << endl
01612 << "does not contain point " << start << abort(FatalError);
01613 }
01614 }
01615
01616
01617 const node& nod = nodes_[nodeI];
01618
01619 labelBits index = nod.subNodes_[octant];
01620
01621 if (isContent(index))
01622 {
01623 const labelList& indices = contents_[getContent(index)];
01624
01625 if (findAny)
01626 {
01627
01628
01629 forAll(indices, elemI)
01630 {
01631 label shapeI = indices[elemI];
01632
01633 point pt;
01634 bool hit = shapes_.intersects(shapeI, start, end, pt);
01635
01636 if (hit)
01637 {
01638
01639
01640 hitInfo.setHit();
01641 hitInfo.setIndex(shapeI);
01642 hitInfo.setPoint(pt);
01643 return;
01644 }
01645 }
01646 }
01647 else
01648 {
01649
01650
01651 point nearestPoint(end);
01652
01653 forAll(indices, elemI)
01654 {
01655 label shapeI = indices[elemI];
01656
01657 point pt;
01658 bool hit = shapes_.intersects(shapeI, start, nearestPoint, pt);
01659
01660 if (hit)
01661 {
01662
01663 nearestPoint = pt;
01664
01665 hitInfo.setHit();
01666 hitInfo.setIndex(shapeI);
01667 hitInfo.setPoint(pt);
01668 }
01669 }
01670
01671 if (hitInfo.hit())
01672 {
01673
01674 return;
01675 }
01676 }
01677 }
01678
01679
01680
01681
01682
01683
01684 const treeBoundBox octantBb(subBbox(nodeI, octant));
01685
01686 point pt;
01687 bool intersected = octantBb.intersects
01688 (
01689 end,
01690 (start-end),
01691
01692 end,
01693 start,
01694
01695 pt,
01696 hitBits
01697 );
01698
01699
01700 if (intersected)
01701 {
01702
01703 hitInfo.setPoint(pt);
01704 }
01705 else
01706 {
01707
01708
01709
01710
01711
01712 point perturbedEnd(pushPoint(octantBb, end, false));
01713
01714
01715
01716 {
01717
01718 writeOBJ(nodeI, octant);
01719
01720 {
01721 OFstream str("ray.obj");
01722 meshTools::writeOBJ(str, start);
01723 meshTools::writeOBJ(str, end);
01724 str << "l 1 2" << nl;
01725 }
01726 WarningIn("indexedOctree<Type>::traverseNode(..)")
01727 << "Did not intersect ray from endpoint:" << end
01728 << " to startpoint:" << start
01729 << " with bounding box:" << octantBb << nl
01730 << "Re-intersecting with perturbed endpoint:" << perturbedEnd
01731 << endl;
01732 }
01733
01734 traverseNode
01735 (
01736 findAny,
01737 treeStart,
01738 treeVec,
01739 start,
01740 perturbedEnd,
01741 nodeI,
01742 octant,
01743
01744 hitInfo,
01745 hitBits
01746 );
01747 }
01748 }
01749
01750
01751
01752 template <class Type>
01753 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
01754 (
01755 const bool findAny,
01756 const point& treeStart,
01757 const point& treeEnd,
01758 const label startNodeI,
01759 const direction startOctant,
01760 const bool verbose
01761 ) const
01762 {
01763 const vector treeVec(treeEnd - treeStart);
01764
01765
01766 label nodeI = startNodeI;
01767 direction octant = startOctant;
01768
01769 if (verbose)
01770 {
01771 Pout<< "findLine : treeStart:" << treeStart
01772 << " treeEnd:" << treeEnd << endl
01773 << "node:" << nodeI
01774 << " octant:" << octant
01775 << " bb:" << subBbox(nodeI, octant) << endl;
01776 }
01777
01778
01779 pointIndexHit hitInfo(false, treeStart, -1);
01780
01781
01782 label i = 0;
01783 for (; i < 100000; i++)
01784 {
01785
01786
01787
01788 const treeBoundBox octantBb(subBbox(nodeI, octant));
01789
01790
01791 point startPoint
01792 (
01793 pushPointIntoFace
01794 (
01795 octantBb,
01796 treeVec,
01797 hitInfo.rawPoint()
01798 )
01799 );
01800
01801 if (verbose)
01802 {
01803 Pout<< "iter:" << i
01804 << " at current:" << hitInfo.rawPoint()
01805 << " (perturbed:" << startPoint << ")" << endl
01806 << " node:" << nodeI
01807 << " octant:" << octant
01808 << " bb:" << subBbox(nodeI, octant) << endl;
01809 }
01810
01811
01812
01813
01814
01815 direction hitFaceID = 0;
01816
01817 traverseNode
01818 (
01819 findAny,
01820 treeStart,
01821 treeVec,
01822
01823 startPoint,
01824
01825 treeEnd,
01826 nodeI,
01827 octant,
01828
01829 hitInfo,
01830 hitFaceID
01831 );
01832
01833
01834 if (hitInfo.hit())
01835 {
01836 break;
01837 }
01838
01839 if (hitFaceID == 0 || hitInfo.rawPoint() == treeEnd)
01840 {
01841
01842 break;
01843 }
01844
01845
01846 point perturbedPoint
01847 (
01848 pushPoint
01849 (
01850 octantBb,
01851 hitFaceID,
01852 hitInfo.rawPoint(),
01853 false
01854 )
01855 );
01856
01857 if (verbose)
01858 {
01859 Pout<< " iter:" << i
01860 << " hit face:" << faceString(hitFaceID)
01861 << " at:" << hitInfo.rawPoint() << nl
01862 << " node:" << nodeI
01863 << " octant:" << octant
01864 << " bb:" << subBbox(nodeI, octant) << nl
01865 << " walking to neighbour containing:" << perturbedPoint
01866 << endl;
01867 }
01868
01869
01870
01871
01872
01873
01874 bool ok = walkToNeighbour
01875 (
01876 perturbedPoint,
01877 hitFaceID,
01878
01879 nodeI,
01880 octant
01881 );
01882
01883 if (!ok)
01884 {
01885
01886 break;
01887 }
01888
01889 if (verbose)
01890 {
01891 const treeBoundBox octantBb(subBbox(nodeI, octant));
01892 Pout<< " walked for point:" << hitInfo.rawPoint() << endl
01893 << " to neighbour node:" << nodeI
01894 << " octant:" << octant
01895 << " face:" << faceString(octantBb.faceBits(hitInfo.rawPoint()))
01896 << " of octantBb:" << octantBb << endl
01897 << endl;
01898 }
01899 }
01900
01901 if (i == 100000)
01902 {
01903
01904 if (!verbose)
01905 {
01906
01907 return findLine
01908 (
01909 findAny,
01910 treeStart,
01911 treeEnd,
01912 startNodeI,
01913 startOctant,
01914 true
01915 );
01916 }
01917 if (debug)
01918 {
01919 FatalErrorIn("indexedOctree<Type>::findLine(..)")
01920 << "Got stuck in loop raytracing from:" << treeStart
01921 << " to:" << treeEnd << endl
01922 << "inside top box:" << subBbox(startNodeI, startOctant)
01923 << abort(FatalError);
01924 }
01925 else
01926 {
01927 WarningIn("indexedOctree<Type>::findLine(..)")
01928 << "Got stuck in loop raytracing from:" << treeStart
01929 << " to:" << treeEnd << endl
01930 << "inside top box:" << subBbox(startNodeI, startOctant)
01931 << endl;
01932 }
01933 }
01934
01935 return hitInfo;
01936 }
01937
01938
01939
01940 template <class Type>
01941 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
01942 (
01943 const bool findAny,
01944 const point& start,
01945 const point& end
01946 ) const
01947 {
01948 pointIndexHit hitInfo;
01949
01950 if (nodes_.size())
01951 {
01952 const treeBoundBox& treeBb = nodes_[0].bb_;
01953
01954
01955
01956
01957 direction startBit = treeBb.posBits(start);
01958 direction endBit = treeBb.posBits(end);
01959
01960 if ((startBit & endBit) != 0)
01961 {
01962
01963 return pointIndexHit(false, vector::zero, -1);
01964 }
01965
01966
01967
01968
01969 point trackStart(start);
01970 point trackEnd(end);
01971
01972 if (startBit != 0)
01973 {
01974
01975 if (!treeBb.intersects(start, end, trackStart))
01976 {
01977 return pointIndexHit(false, vector::zero, -1);
01978 }
01979 }
01980
01981 if (endBit != 0)
01982 {
01983
01984 if (!treeBb.intersects(end, trackStart, trackEnd))
01985 {
01986 return pointIndexHit(false, vector::zero, -1);
01987 }
01988 }
01989
01990
01991
01992 labelBits index = findNode(0, trackStart);
01993
01994 label parentNodeI = getNode(index);
01995 direction octant = getOctant(index);
01996
01997 hitInfo = findLine
01998 (
01999 findAny,
02000 trackStart,
02001 trackEnd,
02002 parentNodeI,
02003 octant
02004 );
02005 }
02006
02007 return hitInfo;
02008 }
02009
02010
02011 template <class Type>
02012 void Foam::indexedOctree<Type>::findBox
02013 (
02014 const label nodeI,
02015 const treeBoundBox& searchBox,
02016 labelHashSet& elements
02017 ) const
02018 {
02019 const node& nod = nodes_[nodeI];
02020 const treeBoundBox& nodeBb = nod.bb_;
02021
02022 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
02023 {
02024 labelBits index = nod.subNodes_[octant];
02025
02026 if (isNode(index))
02027 {
02028 const treeBoundBox& subBb = nodes_[getNode(index)].bb_;
02029
02030 if (subBb.overlaps(searchBox))
02031 {
02032 findBox(getNode(index), searchBox, elements);
02033 }
02034 }
02035 else if (isContent(index))
02036 {
02037 const treeBoundBox subBb(nodeBb.subBbox(octant));
02038
02039 if (subBb.overlaps(searchBox))
02040 {
02041 const labelList& indices = contents_[getContent(index)];
02042
02043 forAll(indices, i)
02044 {
02045 label shapeI = indices[i];
02046
02047 if (shapes_.overlaps(shapeI, searchBox))
02048 {
02049 elements.insert(shapeI);
02050 }
02051 }
02052 }
02053 }
02054 }
02055 }
02056
02057
02058
02059 template <class Type>
02060 Foam::label Foam::indexedOctree<Type>::countElements
02061 (
02062 const labelBits index
02063 ) const
02064 {
02065 label nElems = 0;
02066
02067 if (isNode(index))
02068 {
02069
02070 label nodeI = getNode(index);
02071
02072 const node& nod = nodes_[nodeI];
02073
02074 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
02075 {
02076 nElems += countElements(nod.subNodes_[octant]);
02077 }
02078 }
02079 else if (isContent(index))
02080 {
02081 nElems += contents_[getContent(index)].size();
02082 }
02083 else
02084 {
02085
02086 }
02087
02088 return nElems;
02089 }
02090
02091
02092 template <class Type>
02093 void Foam::indexedOctree<Type>::writeOBJ
02094 (
02095 const label nodeI,
02096 const direction octant
02097 ) const
02098 {
02099 OFstream str
02100 (
02101 "node" + Foam::name(nodeI) + "_octant" + Foam::name(octant) + ".obj"
02102 );
02103
02104 labelBits index = nodes_[nodeI].subNodes_[octant];
02105
02106 treeBoundBox subBb;
02107
02108 if (isNode(index))
02109 {
02110 subBb = nodes_[getNode(index)].bb_;
02111 }
02112 else if (isContent(index))
02113 {
02114 subBb = nodes_[nodeI].bb_.subBbox(octant);
02115 }
02116
02117 Pout<< "dumpContentNode : writing node:" << nodeI << " octant:" << octant
02118 << " to " << str.name() << endl;
02119
02120 label vertI = 0;
02121
02122
02123 pointField bbPoints(subBb.points());
02124
02125 label pointVertI = vertI;
02126 forAll(bbPoints, i)
02127 {
02128 meshTools::writeOBJ(str, bbPoints[i]);
02129 vertI++;
02130 }
02131
02132 forAll(treeBoundBox::edges, i)
02133 {
02134 const edge& e = treeBoundBox::edges[i];
02135
02136 str<< "l " << e[0]+pointVertI+1 << ' ' << e[1]+pointVertI+1 << nl;
02137 }
02138 }
02139
02140
02141
02142
02143 template <class Type>
02144 Foam::indexedOctree<Type>::indexedOctree(const Type& shapes)
02145 :
02146 shapes_(shapes),
02147 nodes_(0),
02148 contents_(0),
02149 nodeTypes_(0)
02150 {}
02151
02152
02153 template <class Type>
02154 Foam::indexedOctree<Type>::indexedOctree
02155 (
02156 const Type& shapes,
02157 const List<node>& nodes,
02158 const labelListList& contents
02159 )
02160 :
02161 shapes_(shapes),
02162 nodes_(nodes),
02163 contents_(contents),
02164 nodeTypes_(0)
02165 {}
02166
02167
02168 template <class Type>
02169 Foam::indexedOctree<Type>::indexedOctree
02170 (
02171 const Type& shapes,
02172 const treeBoundBox& bb,
02173 const label maxLevels,
02174 const scalar maxLeafRatio,
02175 const scalar maxDuplicity
02176 )
02177 :
02178 shapes_(shapes),
02179 nodes_(0),
02180 contents_(0),
02181 nodeTypes_(0)
02182 {
02183 if (debug)
02184 {
02185 Pout<< "indexedOctree<Type>::indexedOctree:" << nl
02186 << " shapes:" << shapes.size() << nl
02187 << " bb:" << bb << nl
02188 << endl;
02189 }
02190
02191 if (shapes.size() == 0)
02192 {
02193 return;
02194 }
02195
02196
02197 DynamicList<node> nodes(label(shapes.size() / maxLeafRatio));
02198 DynamicList<labelList> contents(label(shapes.size() / maxLeafRatio));
02199 contents.append(identity(shapes.size()));
02200
02201
02202 node topNode(divide(bb, contents, 0));
02203 nodes.append(topNode);
02204
02205
02206
02207
02208
02209 label nLevels = 1;
02210
02211 for (; nLevels < maxLevels; nLevels++)
02212 {
02213
02214 label nEntries = 0;
02215 forAll(contents, i)
02216 {
02217 nEntries += contents[i].size();
02218 }
02219
02220 if (debug)
02221 {
02222 Pout<< "indexedOctree<Type>::indexedOctree:" << nl
02223 << " nLevels:" << nLevels << nl
02224 << " nEntries per treeLeaf:" << nEntries/contents.size()
02225 << nl
02226 << " nEntries per shape (duplicity):"
02227 << nEntries/shapes.size()
02228 << nl
02229 << endl;
02230 }
02231
02232 if
02233 (
02234
02235
02236 nEntries > maxDuplicity*shapes.size()
02237 )
02238 {
02239 break;
02240 }
02241
02242
02243
02244 label nOldNodes = nodes.size();
02245 splitNodes
02246 (
02247 label(maxLeafRatio),
02248 nodes,
02249 contents
02250 );
02251
02252 if (nOldNodes == nodes.size())
02253 {
02254 break;
02255 }
02256 }
02257
02258
02259 nodes.shrink();
02260 contents.shrink();
02261
02262
02263
02264
02265
02266 contents_.setSize(contents.size());
02267 label compactI = 0;
02268
02269 label level = 0;
02270
02271 while (true)
02272 {
02273 compactContents
02274 (
02275 nodes,
02276 contents,
02277 level,
02278 0,
02279 0,
02280 contents_,
02281 compactI
02282 );
02283
02284 if (compactI == contents_.size())
02285 {
02286
02287 break;
02288 }
02289
02290 level++;
02291 }
02292 nodes_.transfer(nodes);
02293 nodes.clear();
02294
02295 if (debug)
02296 {
02297 label nEntries = 0;
02298 forAll(contents_, i)
02299 {
02300 nEntries += contents_[i].size();
02301 }
02302
02303 Pout<< "indexedOctree<Type>::indexedOctree"
02304 << " : finished construction of tree of:" << shapes.typeName
02305 << nl
02306 << " bb:" << this->bb() << nl
02307 << " shapes:" << shapes.size() << nl
02308 << " nLevels:" << nLevels << nl
02309 << " treeNodes:" << nodes_.size() << nl
02310 << " nEntries:" << nEntries << nl
02311 << " per treeLeaf:"
02312 << scalar(nEntries)/contents.size() << nl
02313 << " per shape (duplicity):"
02314 << scalar(nEntries)/shapes.size() << nl
02315 << endl;
02316 }
02317 }
02318
02319
02320 template <class Type>
02321 Foam::indexedOctree<Type>::indexedOctree
02322 (
02323 const Type& shapes,
02324 Istream& is
02325 )
02326 :
02327 shapes_(shapes),
02328 nodes_(is),
02329 contents_(is),
02330 nodeTypes_(0)
02331 {}
02332
02333
02334
02335
02336 template <class Type>
02337 Foam::scalar& Foam::indexedOctree<Type>::perturbTol()
02338 {
02339 return perturbTol_;
02340 }
02341
02342
02343 template <class Type>
02344 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
02345 (
02346 const point& sample,
02347 const scalar startDistSqr
02348 ) const
02349 {
02350 scalar nearestDistSqr = startDistSqr;
02351 label nearestShapeI = -1;
02352 point nearestPoint;
02353
02354 if (nodes_.size())
02355 {
02356 findNearest
02357 (
02358 0,
02359 sample,
02360
02361 nearestDistSqr,
02362 nearestShapeI,
02363 nearestPoint
02364 );
02365 }
02366 else
02367 {
02368 nearestPoint = vector::zero;
02369 }
02370
02371 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
02372 }
02373
02374
02375 template <class Type>
02376 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
02377 (
02378 const linePointRef& ln,
02379 treeBoundBox& tightest,
02380 point& linePoint
02381 ) const
02382 {
02383 label nearestShapeI = -1;
02384 point nearestPoint;
02385
02386 if (nodes_.size())
02387 {
02388 findNearest
02389 (
02390 0,
02391 ln,
02392
02393 tightest,
02394 nearestShapeI,
02395 linePoint,
02396 nearestPoint
02397 );
02398 }
02399 else
02400 {
02401 nearestPoint = vector::zero;
02402 }
02403
02404 return pointIndexHit(nearestShapeI != -1, nearestPoint, nearestShapeI);
02405 }
02406
02407
02408
02409 template <class Type>
02410 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
02411 (
02412 const point& start,
02413 const point& end
02414 ) const
02415 {
02416 return findLine(false, start, end);
02417 }
02418
02419
02420
02421 template <class Type>
02422 Foam::pointIndexHit Foam::indexedOctree<Type>::findLineAny
02423 (
02424 const point& start,
02425 const point& end
02426 ) const
02427 {
02428 return findLine(true, start, end);
02429 }
02430
02431
02432 template <class Type>
02433 Foam::labelList Foam::indexedOctree<Type>::findBox
02434 (
02435 const treeBoundBox& searchBox
02436 ) const
02437 {
02438
02439 labelHashSet elements(shapes_.size() / 100);
02440
02441 if (nodes_.size())
02442 {
02443 findBox(0, searchBox, elements);
02444 }
02445
02446 return elements.toc();
02447 }
02448
02449
02450
02451 template <class Type>
02452 Foam::labelBits Foam::indexedOctree<Type>::findNode
02453 (
02454 const label nodeI,
02455 const point& sample
02456 ) const
02457 {
02458 if (nodes_.empty())
02459 {
02460
02461 return nodePlusOctant(nodeI, 0);
02462 }
02463
02464 const node& nod = nodes_[nodeI];
02465
02466 if (debug)
02467 {
02468 if (!nod.bb_.contains(sample))
02469 {
02470 FatalErrorIn("findNode(..)")
02471 << "Cannot find " << sample << " in node " << nodeI
02472 << abort(FatalError);
02473 }
02474 }
02475
02476 direction octant = nod.bb_.subOctant(sample);
02477
02478 labelBits index = nod.subNodes_[octant];
02479
02480 if (isNode(index))
02481 {
02482
02483 return findNode(getNode(index), sample);
02484 }
02485 else if (isContent(index))
02486 {
02487
02488 return nodePlusOctant(nodeI, octant);
02489 }
02490 else
02491 {
02492
02493 return nodePlusOctant(nodeI, octant);
02494 }
02495 }
02496
02497
02498
02499 template <class Type>
02500 typename Foam::indexedOctree<Type>::volumeType
02501 Foam::indexedOctree<Type>::getVolumeType
02502 (
02503 const point& sample
02504 ) const
02505 {
02506 if (nodes_.empty())
02507 {
02508 return UNKNOWN;
02509 }
02510
02511 if (nodeTypes_.size() != 8*nodes_.size())
02512 {
02513
02514
02515 nodeTypes_.setSize(8*nodes_.size());
02516 nodeTypes_ = UNKNOWN;
02517
02518 calcVolumeType(0);
02519
02520 if (debug)
02521 {
02522 label nUNKNOWN = 0;
02523 label nMIXED = 0;
02524 label nINSIDE = 0;
02525 label nOUTSIDE = 0;
02526
02527 forAll(nodeTypes_, i)
02528 {
02529 volumeType type = volumeType(nodeTypes_.get(i));
02530
02531 if (type == UNKNOWN)
02532 {
02533 nUNKNOWN++;
02534 }
02535 else if (type == MIXED)
02536 {
02537 nMIXED++;
02538 }
02539 else if (type == INSIDE)
02540 {
02541 nINSIDE++;
02542 }
02543 else if (type == OUTSIDE)
02544 {
02545 nOUTSIDE++;
02546 }
02547 else
02548 {
02549 FatalErrorIn("getVolumeType") << abort(FatalError);
02550 }
02551 }
02552
02553 Pout<< "indexedOctree<Type>::getVolumeType : "
02554 << " bb:" << bb()
02555 << " nodes_:" << nodes_.size()
02556 << " nodeTypes_:" << nodeTypes_.size()
02557 << " nUNKNOWN:" << nUNKNOWN
02558 << " nMIXED:" << nMIXED
02559 << " nINSIDE:" << nINSIDE
02560 << " nOUTSIDE:" << nOUTSIDE
02561 << endl;
02562 }
02563 }
02564
02565 return getVolumeType(0, sample);
02566 }
02567
02568
02569
02570 template <class Type>
02571 void Foam::indexedOctree<Type>::print
02572 (
02573 prefixOSstream& os,
02574 const bool printContents,
02575 const label nodeI
02576 ) const
02577 {
02578 const node& nod = nodes_[nodeI];
02579 const treeBoundBox& bb = nod.bb_;
02580
02581 os << "nodeI:" << nodeI << " bb:" << bb << nl
02582 << "parent:" << nod.parent_ << nl
02583 << "n:" << countElements(nodePlusOctant(nodeI, 0)) << nl;
02584
02585 for (direction octant = 0; octant < nod.subNodes_.size(); octant++)
02586 {
02587 const treeBoundBox subBb(bb.subBbox(octant));
02588
02589 labelBits index = nod.subNodes_[octant];
02590
02591 if (isNode(index))
02592 {
02593
02594 label subNodeI = getNode(index);
02595
02596 os << "octant:" << octant
02597 << " node: n:" << countElements(index)
02598 << " bb:" << subBb << endl;
02599
02600 string oldPrefix = os.prefix();
02601 os.prefix() = " " + oldPrefix;
02602
02603 print(os, printContents, subNodeI);
02604
02605 os.prefix() = oldPrefix;
02606 }
02607 else if (isContent(index))
02608 {
02609 const labelList& indices = contents_[getContent(index)];
02610
02611 os << "octant:" << octant
02612 << " content: n:" << indices.size()
02613 << " bb:" << subBb;
02614
02615 if (printContents)
02616 {
02617 os << " contents:";
02618 forAll(indices, j)
02619 {
02620 os << ' ' << indices[j];
02621 }
02622 }
02623 os << endl;
02624 }
02625 else
02626 {
02627 os << "octant:" << octant << " empty:" << subBb << endl;
02628 }
02629 }
02630 }
02631
02632
02633
02634 template <class Type>
02635 bool Foam::indexedOctree<Type>::write(Ostream& os) const
02636 {
02637 os << *this;
02638
02639 return os.good();
02640 }
02641
02642
02643 template <class Type>
02644 Foam::Ostream& Foam::operator<<(Ostream& os, const indexedOctree<Type>& t)
02645 {
02646 return
02647 os << t.bb() << token::SPACE << t.nodes()
02648 << token::SPACE << t.contents();
02649 }
02650
02651
02652