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 "meshSearch.H"
00027 #include <OpenFOAM/polyMesh.H>
00028 #include <meshTools/indexedOctree.H>
00029 #include <OpenFOAM/DynamicList.H>
00030 #include <OpenFOAM/demandDrivenData.H>
00031 #include <meshTools/treeDataCell.H>
00032 #include <meshTools/treeDataFace.H>
00033 #include <meshTools/treeDataPoint.H>
00034
00035
00036
00037 defineTypeNameAndDebug(Foam::meshSearch, 0);
00038
00039 Foam::scalar Foam::meshSearch::tol_ = 1E-3;
00040
00041
00042
00043
00044 bool Foam::meshSearch::findNearer
00045 (
00046 const point& sample,
00047 const pointField& points,
00048 label& nearestI,
00049 scalar& nearestDistSqr
00050 )
00051 {
00052 bool nearer = false;
00053
00054 forAll(points, pointI)
00055 {
00056 scalar distSqr = magSqr(points[pointI] - sample);
00057
00058 if (distSqr < nearestDistSqr)
00059 {
00060 nearestDistSqr = distSqr;
00061 nearestI = pointI;
00062 nearer = true;
00063 }
00064 }
00065
00066 return nearer;
00067 }
00068
00069
00070 bool Foam::meshSearch::findNearer
00071 (
00072 const point& sample,
00073 const pointField& points,
00074 const labelList& indices,
00075 label& nearestI,
00076 scalar& nearestDistSqr
00077 )
00078 {
00079 bool nearer = false;
00080
00081 forAll(indices, i)
00082 {
00083 label pointI = indices[i];
00084
00085 scalar distSqr = magSqr(points[pointI] - sample);
00086
00087 if (distSqr < nearestDistSqr)
00088 {
00089 nearestDistSqr = distSqr;
00090 nearestI = pointI;
00091 nearer = true;
00092 }
00093 }
00094
00095 return nearer;
00096 }
00097
00098
00099
00100 Foam::label Foam::meshSearch::findNearestCellTree(const point& location) const
00101 {
00102 const indexedOctree<treeDataPoint>& tree = cellCentreTree();
00103
00104 scalar span = tree.bb().mag();
00105
00106 pointIndexHit info = tree.findNearest(location, Foam::sqr(span));
00107
00108 if (!info.hit())
00109 {
00110 info = tree.findNearest(location, Foam::sqr(GREAT));
00111 }
00112 return info.index();
00113 }
00114
00115
00116
00117 Foam::label Foam::meshSearch::findNearestCellLinear(const point& location) const
00118 {
00119 const vectorField& centres = mesh_.cellCentres();
00120
00121 label nearestIndex = 0;
00122 scalar minProximity = magSqr(centres[nearestIndex] - location);
00123
00124 findNearer
00125 (
00126 location,
00127 centres,
00128 nearestIndex,
00129 minProximity
00130 );
00131
00132 return nearestIndex;
00133 }
00134
00135
00136
00137 Foam::label Foam::meshSearch::findNearestCellWalk
00138 (
00139 const point& location,
00140 const label seedCellI
00141 ) const
00142 {
00143 if (seedCellI < 0)
00144 {
00145 FatalErrorIn
00146 (
00147 "meshSearch::findNearestCellWalk(const point&, const label)"
00148 ) << "illegal seedCell:" << seedCellI << exit(FatalError);
00149 }
00150
00151
00152
00153 label curCellI = seedCellI;
00154 scalar distanceSqr = magSqr(mesh_.cellCentres()[curCellI] - location);
00155
00156 bool closer;
00157
00158 do
00159 {
00160
00161 closer = findNearer
00162 (
00163 location,
00164 mesh_.cellCentres(),
00165 mesh_.cellCells()[curCellI],
00166 curCellI,
00167 distanceSqr
00168 );
00169 } while (closer);
00170
00171 return curCellI;
00172 }
00173
00174
00175
00176 Foam::label Foam::meshSearch::findNearestFaceTree(const point& location) const
00177 {
00178
00179 const indexedOctree<treeDataPoint>& tree = cellCentreTree();
00180
00181 scalar span = tree.bb().mag();
00182
00183
00184 pointIndexHit info = tree.findNearest(location, Foam::sqr(span));
00185
00186 if (!info.hit())
00187 {
00188
00189 info = tree.findNearest(location, Foam::sqr(GREAT));
00190 }
00191
00192
00193
00194 const vectorField& centres = mesh_.faceCentres();
00195 const cell& ownFaces = mesh_.cells()[info.index()];
00196
00197 label nearestFaceI = ownFaces[0];
00198 scalar minProximity = magSqr(centres[nearestFaceI] - location);
00199
00200 findNearer
00201 (
00202 location,
00203 centres,
00204 ownFaces,
00205 nearestFaceI,
00206 minProximity
00207 );
00208
00209 return nearestFaceI;
00210 }
00211
00212
00213
00214 Foam::label Foam::meshSearch::findNearestFaceLinear(const point& location) const
00215 {
00216 const vectorField& centres = mesh_.faceCentres();
00217
00218 label nearestFaceI = 0;
00219 scalar minProximity = magSqr(centres[nearestFaceI] - location);
00220
00221 findNearer
00222 (
00223 location,
00224 centres,
00225 nearestFaceI,
00226 minProximity
00227 );
00228
00229 return nearestFaceI;
00230 }
00231
00232
00233
00234 Foam::label Foam::meshSearch::findNearestFaceWalk
00235 (
00236 const point& location,
00237 const label seedFaceI
00238 ) const
00239 {
00240 if (seedFaceI < 0)
00241 {
00242 FatalErrorIn
00243 (
00244 "meshSearch::findNearestFaceWalk(const point&, const label)"
00245 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
00246 }
00247
00248 const vectorField& centres = mesh_.faceCentres();
00249
00250
00251
00252
00253 label curFaceI = seedFaceI;
00254 scalar distanceSqr = magSqr(centres[curFaceI] - location);
00255
00256 while (true)
00257 {
00258 label betterFaceI = curFaceI;
00259
00260 findNearer
00261 (
00262 location,
00263 centres,
00264 mesh_.cells()[mesh_.faceOwner()[curFaceI]],
00265 betterFaceI,
00266 distanceSqr
00267 );
00268
00269 if (mesh_.isInternalFace(curFaceI))
00270 {
00271 findNearer
00272 (
00273 location,
00274 centres,
00275 mesh_.cells()[mesh_.faceNeighbour()[curFaceI]],
00276 betterFaceI,
00277 distanceSqr
00278 );
00279 }
00280
00281 if (betterFaceI == curFaceI)
00282 {
00283 break;
00284 }
00285
00286 curFaceI = betterFaceI;
00287 }
00288
00289 return curFaceI;
00290 }
00291
00292
00293 Foam::label Foam::meshSearch::findCellLinear(const point& location) const
00294 {
00295 bool cellFound = false;
00296 label n = 0;
00297
00298 label cellI = -1;
00299
00300 while ((!cellFound) && (n < mesh_.nCells()))
00301 {
00302 if (pointInCell(location, n))
00303 {
00304 cellFound = true;
00305 cellI = n;
00306 }
00307 else
00308 {
00309 n++;
00310 }
00311 }
00312 if (cellFound)
00313 {
00314 return cellI;
00315 }
00316 else
00317 {
00318 return -1;
00319 }
00320 }
00321
00322
00323 Foam::label Foam::meshSearch::findNearestBoundaryFaceWalk
00324 (
00325 const point& location,
00326 const label seedFaceI
00327 ) const
00328 {
00329 if (seedFaceI < 0)
00330 {
00331 FatalErrorIn
00332 (
00333 "meshSearch::findNearestBoundaryFaceWalk"
00334 "(const point&, const label)"
00335 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
00336 }
00337
00338
00339
00340 label curFaceI = seedFaceI;
00341
00342 const face& f = mesh_.faces()[curFaceI];
00343
00344 scalar minDist = f.nearestPoint
00345 (
00346 location,
00347 mesh_.points()
00348 ).distance();
00349
00350 bool closer;
00351
00352 do
00353 {
00354 closer = false;
00355
00356
00357
00358
00359 label lastFaceI = curFaceI;
00360
00361 const labelList& myEdges = mesh_.faceEdges()[curFaceI];
00362
00363 forAll (myEdges, myEdgeI)
00364 {
00365 const labelList& neighbours = mesh_.edgeFaces()[myEdges[myEdgeI]];
00366
00367
00368
00369
00370 forAll(neighbours, nI)
00371 {
00372 label faceI = neighbours[nI];
00373
00374 if
00375 (
00376 (faceI >= mesh_.nInternalFaces())
00377 && (faceI != lastFaceI)
00378 )
00379 {
00380 const face& f = mesh_.faces()[faceI];
00381
00382 pointHit curHit = f.nearestPoint
00383 (
00384 location,
00385 mesh_.points()
00386 );
00387
00388
00389 if (curHit.distance() < minDist)
00390 {
00391 minDist = curHit.distance();
00392 curFaceI = faceI;
00393 closer = true;
00394 }
00395 }
00396 }
00397 }
00398 } while (closer);
00399
00400 return curFaceI;
00401 }
00402
00403
00404 Foam::vector Foam::meshSearch::offset
00405 (
00406 const point& bPoint,
00407 const label bFaceI,
00408 const vector& dir
00409 ) const
00410 {
00411
00412 label ownerCellI = mesh_.faceOwner()[bFaceI];
00413
00414 const point& c = mesh_.cellCentres()[ownerCellI];
00415
00416
00417 scalar typDim = mag(c - bPoint);
00418
00419 return tol_*typDim*dir;
00420 }
00421
00422
00423
00424
00425
00426 Foam::meshSearch::meshSearch(const polyMesh& mesh, const bool faceDecomp)
00427 :
00428 mesh_(mesh),
00429 faceDecomp_(faceDecomp),
00430 cloud_(mesh_, IDLList<passiveParticle>()),
00431 boundaryTreePtr_(NULL),
00432 cellTreePtr_(NULL),
00433 cellCentreTreePtr_(NULL)
00434 {}
00435
00436
00437
00438
00439 Foam::meshSearch::~meshSearch()
00440 {
00441 clearOut();
00442 }
00443
00444
00445
00446
00447 const Foam::indexedOctree<Foam::treeDataFace>& Foam::meshSearch::boundaryTree()
00448 const
00449 {
00450 if (!boundaryTreePtr_)
00451 {
00452
00453
00454
00455
00456
00457 labelList bndFaces(mesh_.nFaces()-mesh_.nInternalFaces());
00458 forAll(bndFaces, i)
00459 {
00460 bndFaces[i] = mesh_.nInternalFaces() + i;
00461 }
00462
00463 treeBoundBox overallBb(mesh_.points());
00464 Random rndGen(123456);
00465 overallBb = overallBb.extend(rndGen, 1E-4);
00466 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00467 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00468
00469 boundaryTreePtr_ = new indexedOctree<treeDataFace>
00470 (
00471 treeDataFace
00472 (
00473 false,
00474 mesh_,
00475 bndFaces
00476 ),
00477 overallBb,
00478 8,
00479 10,
00480 3.0
00481 );
00482 }
00483
00484 return *boundaryTreePtr_;
00485 }
00486
00487
00488 const Foam::indexedOctree<Foam::treeDataCell>& Foam::meshSearch::cellTree()
00489 const
00490 {
00491 if (!cellTreePtr_)
00492 {
00493
00494
00495
00496
00497 treeBoundBox overallBb(mesh_.points());
00498 Random rndGen(123456);
00499 overallBb = overallBb.extend(rndGen, 1E-4);
00500 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00501 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00502
00503 cellTreePtr_ = new indexedOctree<treeDataCell>
00504 (
00505 treeDataCell
00506 (
00507 false,
00508 mesh_
00509 ),
00510 overallBb,
00511 8,
00512 10,
00513 3.0
00514 );
00515 }
00516
00517 return *cellTreePtr_;
00518
00519 }
00520
00521
00522 const Foam::indexedOctree<Foam::treeDataPoint>&
00523 Foam::meshSearch::cellCentreTree() const
00524 {
00525 if (!cellCentreTreePtr_)
00526 {
00527
00528
00529
00530
00531 treeBoundBox overallBb(mesh_.cellCentres());
00532 Random rndGen(123456);
00533 overallBb = overallBb.extend(rndGen, 1E-4);
00534 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00535 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00536
00537 cellCentreTreePtr_ = new indexedOctree<treeDataPoint>
00538 (
00539 treeDataPoint(mesh_.cellCentres()),
00540 overallBb,
00541 10,
00542 10.0,
00543 100.0
00544 );
00545 }
00546
00547 return *cellCentreTreePtr_;
00548 }
00549
00550
00551
00552
00553
00554
00555 bool Foam::meshSearch::pointInCell(const point& p, label cellI) const
00556 {
00557 if (faceDecomp_)
00558 {
00559 const point& ctr = mesh_.cellCentres()[cellI];
00560
00561 vector dir(p - ctr);
00562 scalar magDir = mag(dir);
00563
00564
00565
00566 const labelList& cFaces = mesh_.cells()[cellI];
00567
00568
00569
00570 scalar oldTol = intersection::setPlanarTol(0.0);
00571
00572 forAll(cFaces, i)
00573 {
00574 label faceI = cFaces[i];
00575
00576 pointHit inter = mesh_.faces()[faceI].ray
00577 (
00578 ctr,
00579 dir,
00580 mesh_.points(),
00581 intersection::HALF_RAY,
00582 intersection::VECTOR
00583 );
00584
00585 if (inter.hit())
00586 {
00587 scalar dist = inter.distance();
00588
00589 if (dist < magDir)
00590 {
00591
00592 intersection::setPlanarTol(oldTol);
00593
00594 return false;
00595 }
00596 }
00597 }
00598
00599 intersection::setPlanarTol(oldTol);
00600
00601
00602 return true;
00603 }
00604 else
00605 {
00606 const labelList& f = mesh_.cells()[cellI];
00607 const labelList& owner = mesh_.faceOwner();
00608 const vectorField& cf = mesh_.faceCentres();
00609 const vectorField& Sf = mesh_.faceAreas();
00610
00611 forAll(f, facei)
00612 {
00613 label nFace = f[facei];
00614 vector proj = p - cf[nFace];
00615 vector normal = Sf[nFace];
00616 if (owner[nFace] == cellI)
00617 {
00618 if ((normal & proj) > 0)
00619 {
00620 return false;
00621 }
00622 }
00623 else
00624 {
00625 if ((normal & proj) < 0)
00626 {
00627 return false;
00628 }
00629 }
00630 }
00631
00632 return true;
00633 }
00634 }
00635
00636
00637 Foam::label Foam::meshSearch::findNearestCell
00638 (
00639 const point& location,
00640 const label seedCellI,
00641 const bool useTreeSearch
00642 ) const
00643 {
00644 if (seedCellI == -1)
00645 {
00646 if (useTreeSearch)
00647 {
00648 return findNearestCellTree(location);
00649 }
00650 else
00651 {
00652 return findNearestCellLinear(location);
00653 }
00654 }
00655 else
00656 {
00657 return findNearestCellWalk(location, seedCellI);
00658 }
00659 }
00660
00661
00662 Foam::label Foam::meshSearch::findNearestFace
00663 (
00664 const point& location,
00665 const label seedFaceI,
00666 const bool useTreeSearch
00667 ) const
00668 {
00669 if (seedFaceI == -1)
00670 {
00671 if (useTreeSearch)
00672 {
00673 return findNearestFaceTree(location);
00674 }
00675 else
00676 {
00677 return findNearestFaceLinear(location);
00678 }
00679 }
00680 else
00681 {
00682 return findNearestFaceWalk(location, seedFaceI);
00683 }
00684 }
00685
00686
00687 Foam::label Foam::meshSearch::findCell
00688 (
00689 const point& location,
00690 const label seedCellI,
00691 const bool useTreeSearch
00692 ) const
00693 {
00694
00695 label nearCellI = findNearestCell(location, seedCellI, useTreeSearch);
00696
00697 if (debug)
00698 {
00699 Pout<< "findCell : nearCellI:" << nearCellI
00700 << " ctr:" << mesh_.cellCentres()[nearCellI]
00701 << endl;
00702 }
00703
00704 if (pointInCell(location, nearCellI))
00705 {
00706 return nearCellI;
00707 }
00708 else
00709 {
00710 if (useTreeSearch)
00711 {
00712
00713 point curPoint = mesh_.cellCentres()[nearCellI];
00714
00715 vector edgeVec = location - curPoint;
00716 edgeVec /= mag(edgeVec);
00717
00718 do
00719 {
00720
00721 passiveParticle tracker(cloud_, curPoint, nearCellI);
00722
00723 if (debug)
00724 {
00725 Pout<< "findCell : tracked from curPoint:" << curPoint
00726 << " nearCellI:" << nearCellI;
00727 }
00728
00729 tracker.track(location);
00730
00731 if (debug)
00732 {
00733 Pout<< " to " << tracker.position()
00734 << " need:" << location
00735 << " onB:" << tracker.onBoundary()
00736 << " cell:" << tracker.cell()
00737 << " face:" << tracker.face() << endl;
00738 }
00739
00740 if (!tracker.onBoundary())
00741 {
00742
00743 return tracker.cell();
00744 }
00745
00746
00747 scalar typDim = sqrt(mag(mesh_.faceAreas()[tracker.face()]));
00748
00749 if ((mag(tracker.position() - location)/typDim) < SMALL)
00750 {
00751 return tracker.cell();
00752 }
00753
00754
00755
00756
00757
00758 curPoint =
00759 tracker.position()
00760 + offset(tracker.position(), tracker.face(), edgeVec);
00761
00762 if (debug)
00763 {
00764 Pout<< "Searching for next boundary from curPoint:"
00765 << curPoint
00766 << " to location:" << location << endl;
00767 }
00768 pointIndexHit curHit = intersection(curPoint, location);
00769 if (debug)
00770 {
00771 Pout<< "Returned from line search with ";
00772 curHit.write(Pout);
00773 Pout<< endl;
00774 }
00775
00776 if (!curHit.hit())
00777 {
00778 return -1;
00779 }
00780 else
00781 {
00782 nearCellI = mesh_.faceOwner()[curHit.index()];
00783 curPoint =
00784 curHit.hitPoint()
00785 + offset(curHit.hitPoint(), curHit.index(), edgeVec);
00786 }
00787 }
00788 while(true);
00789 }
00790 else
00791 {
00792 return findCellLinear(location);
00793 }
00794 }
00795 return -1;
00796 }
00797
00798
00799 Foam::label Foam::meshSearch::findNearestBoundaryFace
00800 (
00801 const point& location,
00802 const label seedFaceI,
00803 const bool useTreeSearch
00804 ) const
00805 {
00806 if (seedFaceI == -1)
00807 {
00808 if (useTreeSearch)
00809 {
00810 const indexedOctree<treeDataFace>& tree = boundaryTree();
00811
00812 scalar span = tree.bb().mag();
00813
00814 pointIndexHit info = boundaryTree().findNearest
00815 (
00816 location,
00817 Foam::sqr(span)
00818 );
00819
00820 if (!info.hit())
00821 {
00822 info = boundaryTree().findNearest
00823 (
00824 location,
00825 Foam::sqr(GREAT)
00826 );
00827 }
00828
00829 return tree.shapes().faceLabels()[info.index()];
00830 }
00831 else
00832 {
00833 scalar minDist = GREAT;
00834
00835 label minFaceI = -1;
00836
00837 for
00838 (
00839 label faceI = mesh_.nInternalFaces();
00840 faceI < mesh_.nFaces();
00841 faceI++
00842 )
00843 {
00844 const face& f = mesh_.faces()[faceI];
00845
00846 pointHit curHit =
00847 f.nearestPoint
00848 (
00849 location,
00850 mesh_.points()
00851 );
00852
00853 if (curHit.distance() < minDist)
00854 {
00855 minDist = curHit.distance();
00856 minFaceI = faceI;
00857 }
00858 }
00859 return minFaceI;
00860 }
00861 }
00862 else
00863 {
00864 return findNearestBoundaryFaceWalk(location, seedFaceI);
00865 }
00866 }
00867
00868
00869 Foam::pointIndexHit Foam::meshSearch::intersection
00870 (
00871 const point& pStart,
00872 const point& pEnd
00873 ) const
00874 {
00875 pointIndexHit curHit = boundaryTree().findLine(pStart, pEnd);
00876
00877 if (curHit.hit())
00878 {
00879
00880 curHit.setIndex(boundaryTree().shapes().faceLabels()[curHit.index()]);
00881 }
00882 return curHit;
00883 }
00884
00885
00886 Foam::List<Foam::pointIndexHit> Foam::meshSearch::intersections
00887 (
00888 const point& pStart,
00889 const point& pEnd
00890 ) const
00891 {
00892 DynamicList<pointIndexHit> hits;
00893
00894 vector edgeVec = pEnd - pStart;
00895 edgeVec /= mag(edgeVec);
00896
00897 point pt = pStart;
00898
00899 pointIndexHit bHit;
00900 do
00901 {
00902 bHit = intersection(pt, pEnd);
00903
00904 if (bHit.hit())
00905 {
00906 hits.append(bHit);
00907
00908 const vector& area = mesh_.faceAreas()[bHit.index()];
00909
00910 scalar typDim = Foam::sqrt(mag(area));
00911
00912 if ((mag(bHit.hitPoint() - pEnd)/typDim) < SMALL)
00913 {
00914 break;
00915 }
00916
00917
00918
00919
00920 pt =
00921 bHit.hitPoint()
00922 + offset(bHit.hitPoint(), bHit.index(), edgeVec);
00923 }
00924
00925 } while(bHit.hit());
00926
00927
00928 hits.shrink();
00929
00930 return hits;
00931 }
00932
00933
00934 bool Foam::meshSearch::isInside(const point& p) const
00935 {
00936 return
00937 boundaryTree().getVolumeType(p)
00938 == indexedOctree<treeDataFace>::INSIDE;
00939 }
00940
00941
00942
00943 void Foam::meshSearch::clearOut()
00944 {
00945 deleteDemandDrivenData(boundaryTreePtr_);
00946 deleteDemandDrivenData(cellTreePtr_);
00947 deleteDemandDrivenData(cellCentreTreePtr_);
00948 }
00949
00950
00951 void Foam::meshSearch::correct()
00952 {
00953 clearOut();
00954 }
00955
00956
00957