1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "meshSearch.H"
28 #include "indexedOctree.H"
29 #include "DynamicList.H"
30 #include "demandDrivenData.H"
31 #include "treeDataCell.H"
32 #include "treeDataFace.H"
33 #include "treeDataPoint.H"
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 defineTypeNameAndDebug(Foam::meshSearch, 0);
39 Foam::scalar Foam::meshSearch::tol_ = 1E-3;
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 bool Foam::meshSearch::findNearer
47 const pointField& points,
49 scalar& nearestDistSqr
54 forAll(points, pointI)
56 scalar distSqr = magSqr(points[pointI] - sample);
58 if (distSqr < nearestDistSqr)
60 nearestDistSqr = distSqr;
70 bool Foam::meshSearch::findNearer
73 const pointField& points,
74 const labelList& indices,
76 scalar& nearestDistSqr
83 label pointI = indices[i];
85 scalar distSqr = magSqr(points[pointI] - sample);
87 if (distSqr < nearestDistSqr)
89 nearestDistSqr = distSqr;
99 // tree based searching
100 Foam::label Foam::meshSearch::findNearestCellTree(const point& location) const
102 const indexedOctree<treeDataPoint>& tree = cellCentreTree();
104 scalar span = tree.bb().mag();
106 pointIndexHit info = tree.findNearest(location, Foam::sqr(span));
110 info = tree.findNearest(location, Foam::sqr(GREAT));
117 Foam::label Foam::meshSearch::findNearestCellLinear(const point& location) const
119 const vectorField& centres = mesh_.cellCentres();
121 label nearestIndex = 0;
122 scalar minProximity = magSqr(centres[nearestIndex] - location);
137 Foam::label Foam::meshSearch::findNearestCellWalk
139 const point& location,
140 const label seedCellI
147 "meshSearch::findNearestCellWalk(const point&, const label)"
148 ) << "illegal seedCell:" << seedCellI << exit(FatalError);
151 // Walk in direction of face that decreases distance
153 label curCellI = seedCellI;
154 scalar distanceSqr = magSqr(mesh_.cellCentres()[curCellI] - location);
160 // Try neighbours of curCellI
165 mesh_.cellCells()[curCellI],
175 // tree based searching
176 Foam::label Foam::meshSearch::findNearestFaceTree(const point& location) const
178 // Search nearest cell centre.
179 const indexedOctree<treeDataPoint>& tree = cellCentreTree();
181 scalar span = tree.bb().mag();
183 // Search with decent span
184 pointIndexHit info = tree.findNearest(location, Foam::sqr(span));
188 // Search with desparate span
189 info = tree.findNearest(location, Foam::sqr(GREAT));
193 // Now check any of the faces of the nearest cell
194 const vectorField& centres = mesh_.faceCentres();
195 const cell& ownFaces = mesh_.cells()[info.index()];
197 label nearestFaceI = ownFaces[0];
198 scalar minProximity = magSqr(centres[nearestFaceI] - location);
214 Foam::label Foam::meshSearch::findNearestFaceLinear(const point& location) const
216 const vectorField& centres = mesh_.faceCentres();
218 label nearestFaceI = 0;
219 scalar minProximity = magSqr(centres[nearestFaceI] - location);
234 Foam::label Foam::meshSearch::findNearestFaceWalk
236 const point& location,
237 const label seedFaceI
244 "meshSearch::findNearestFaceWalk(const point&, const label)"
245 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
248 const vectorField& centres = mesh_.faceCentres();
251 // Walk in direction of face that decreases distance
253 label curFaceI = seedFaceI;
254 scalar distanceSqr = magSqr(centres[curFaceI] - location);
258 label betterFaceI = curFaceI;
264 mesh_.cells()[mesh_.faceOwner()[curFaceI]],
269 if (mesh_.isInternalFace(curFaceI))
275 mesh_.cells()[mesh_.faceNeighbour()[curFaceI]],
281 if (betterFaceI == curFaceI)
286 curFaceI = betterFaceI;
293 Foam::label Foam::meshSearch::findCellLinear(const point& location) const
295 bool cellFound = false;
300 while ((!cellFound) && (n < mesh_.nCells()))
302 if (pointInCell(location, n))
323 Foam::label Foam::meshSearch::findNearestBoundaryFaceWalk
325 const point& location,
326 const label seedFaceI
333 "meshSearch::findNearestBoundaryFaceWalk"
334 "(const point&, const label)"
335 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
338 // Start off from seedFaceI
340 label curFaceI = seedFaceI;
342 const face& f = mesh_.faces()[curFaceI];
344 scalar minDist = f.nearestPoint
356 // Search through all neighbouring boundary faces by going
359 label lastFaceI = curFaceI;
361 const labelList& myEdges = mesh_.faceEdges()[curFaceI];
363 forAll (myEdges, myEdgeI)
365 const labelList& neighbours = mesh_.edgeFaces()[myEdges[myEdgeI]];
367 // Check any face which uses edge, is boundary face and
368 // is not curFaceI itself.
370 forAll(neighbours, nI)
372 label faceI = neighbours[nI];
376 (faceI >= mesh_.nInternalFaces())
377 && (faceI != lastFaceI)
380 const face& f = mesh_.faces()[faceI];
382 pointHit curHit = f.nearestPoint
388 // If the face is closer, reset current face and distance
389 if (curHit.distance() < minDist)
391 minDist = curHit.distance();
393 closer = true; // a closer neighbour has been found
404 Foam::vector Foam::meshSearch::offset
411 // Get the neighbouring cell
412 label ownerCellI = mesh_.faceOwner()[bFaceI];
414 const point& c = mesh_.cellCentres()[ownerCellI];
416 // Typical dimension: distance from point on face to cell centre
417 scalar typDim = mag(c - bPoint);
419 return tol_*typDim*dir;
423 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
425 // Construct from components
426 Foam::meshSearch::meshSearch(const polyMesh& mesh, const bool faceDecomp)
429 faceDecomp_(faceDecomp),
430 cloud_(mesh_, IDLList<passiveParticle>()),
431 boundaryTreePtr_(NULL),
433 cellCentreTreePtr_(NULL)
437 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
439 Foam::meshSearch::~meshSearch()
445 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
447 const Foam::indexedOctree<Foam::treeDataFace>& Foam::meshSearch::boundaryTree()
450 if (!boundaryTreePtr_)
456 // all boundary faces (not just walls)
457 labelList bndFaces(mesh_.nFaces()-mesh_.nInternalFaces());
460 bndFaces[i] = mesh_.nInternalFaces() + i;
463 treeBoundBox overallBb(mesh_.points());
464 Random rndGen(123456);
465 overallBb = overallBb.extend(rndGen, 1E-4);
466 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
467 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
469 boundaryTreePtr_ = new indexedOctree<treeDataFace>
471 treeDataFace // all information needed to search faces
473 false, // do not cache bb
475 bndFaces // boundary faces only
477 overallBb, // overall search domain
484 return *boundaryTreePtr_;
488 const Foam::indexedOctree<Foam::treeDataCell>& Foam::meshSearch::cellTree()
497 treeBoundBox overallBb(mesh_.points());
498 Random rndGen(123456);
499 overallBb = overallBb.extend(rndGen, 1E-4);
500 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
501 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
503 cellTreePtr_ = new indexedOctree<treeDataCell>
507 false, // not cache bb
510 overallBb, // overall search domain
517 return *cellTreePtr_;
522 const Foam::indexedOctree<Foam::treeDataPoint>&
523 Foam::meshSearch::cellCentreTree() const
525 if (!cellCentreTreePtr_)
531 treeBoundBox overallBb(mesh_.cellCentres());
532 Random rndGen(123456);
533 overallBb = overallBb.extend(rndGen, 1E-4);
534 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
535 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
537 cellCentreTreePtr_ = new indexedOctree<treeDataPoint>
539 treeDataPoint(mesh_.cellCentres()),
540 overallBb, // overall search domain
542 10.0, // maximum ratio of cubes v.s. cells
543 100.0 // max. duplicity; n/a since no bounding boxes.
547 return *cellCentreTreePtr_;
551 // Is the point in the cell
552 // Works by checking if there is a face inbetween the point and the cell
554 // Check for internal uses proper face decomposition or just average normal.
555 bool Foam::meshSearch::pointInCell(const point& p, label cellI) const
559 const point& ctr = mesh_.cellCentres()[cellI];
562 scalar magDir = mag(dir);
564 // Check if any faces are hit by ray from cell centre to p.
565 // If none -> p is in cell.
566 const labelList& cFaces = mesh_.cells()[cellI];
568 // Make sure half_ray does not pick up any faces on the wrong
570 scalar oldTol = intersection::setPlanarTol(0.0);
574 label faceI = cFaces[i];
576 pointHit inter = mesh_.faces()[faceI].ray
581 intersection::HALF_RAY,
587 scalar dist = inter.distance();
591 // Valid hit. Hit face so point is not in cell.
592 intersection::setPlanarTol(oldTol);
599 intersection::setPlanarTol(oldTol);
601 // No face inbetween point and cell centre so point is inside.
606 const labelList& f = mesh_.cells()[cellI];
607 const labelList& owner = mesh_.faceOwner();
608 const vectorField& cf = mesh_.faceCentres();
609 const vectorField& Sf = mesh_.faceAreas();
613 label nFace = f[facei];
614 vector proj = p - cf[nFace];
615 vector normal = Sf[nFace];
616 if (owner[nFace] == cellI)
618 if ((normal & proj) > 0)
625 if ((normal & proj) < 0)
637 Foam::label Foam::meshSearch::findNearestCell
639 const point& location,
640 const label seedCellI,
641 const bool useTreeSearch
648 return findNearestCellTree(location);
652 return findNearestCellLinear(location);
657 return findNearestCellWalk(location, seedCellI);
662 Foam::label Foam::meshSearch::findNearestFace
664 const point& location,
665 const label seedFaceI,
666 const bool useTreeSearch
673 return findNearestFaceTree(location);
677 return findNearestFaceLinear(location);
682 return findNearestFaceWalk(location, seedFaceI);
687 Foam::label Foam::meshSearch::findCell
689 const point& location,
690 const label seedCellI,
691 const bool useTreeSearch
694 // Find the nearest cell centre to this location
695 label nearCellI = findNearestCell(location, seedCellI, useTreeSearch);
699 Pout<< "findCell : nearCellI:" << nearCellI
700 << " ctr:" << mesh_.cellCentres()[nearCellI]
704 if (pointInCell(location, nearCellI))
712 // Start searching from cell centre of nearCell
713 point curPoint = mesh_.cellCentres()[nearCellI];
715 vector edgeVec = location - curPoint;
716 edgeVec /= mag(edgeVec);
720 // Walk neighbours (using tracking) to get closer
721 passiveParticle tracker(cloud_, curPoint, nearCellI);
725 Pout<< "findCell : tracked from curPoint:" << curPoint
726 << " nearCellI:" << nearCellI;
729 tracker.track(location);
733 Pout<< " to " << tracker.position()
734 << " need:" << location
735 << " onB:" << tracker.onBoundary()
736 << " cell:" << tracker.cell()
737 << " face:" << tracker.face() << endl;
740 if (!tracker.onBoundary())
742 // stopped not on boundary -> reached location
743 return tracker.cell();
746 // stopped on boundary face. Compare positions
747 scalar typDim = sqrt(mag(mesh_.faceAreas()[tracker.face()]));
749 if ((mag(tracker.position() - location)/typDim) < SMALL)
751 return tracker.cell();
754 // tracking stopped at boundary. Find next boundary
755 // intersection from current point (shifted out a little bit)
756 // in the direction of the destination
760 + offset(tracker.position(), tracker.face(), edgeVec);
764 Pout<< "Searching for next boundary from curPoint:"
766 << " to location:" << location << endl;
768 pointIndexHit curHit = intersection(curPoint, location);
771 Pout<< "Returned from line search with ";
782 nearCellI = mesh_.faceOwner()[curHit.index()];
785 + offset(curHit.hitPoint(), curHit.index(), edgeVec);
792 return findCellLinear(location);
799 Foam::label Foam::meshSearch::findNearestBoundaryFace
801 const point& location,
802 const label seedFaceI,
803 const bool useTreeSearch
810 const indexedOctree<treeDataFace>& tree = boundaryTree();
812 scalar span = tree.bb().mag();
814 pointIndexHit info = boundaryTree().findNearest
822 info = boundaryTree().findNearest
829 return tree.shapes().faceLabels()[info.index()];
833 scalar minDist = GREAT;
839 label faceI = mesh_.nInternalFaces();
840 faceI < mesh_.nFaces();
844 const face& f = mesh_.faces()[faceI];
853 if (curHit.distance() < minDist)
855 minDist = curHit.distance();
864 return findNearestBoundaryFaceWalk(location, seedFaceI);
869 Foam::pointIndexHit Foam::meshSearch::intersection
875 pointIndexHit curHit = boundaryTree().findLine(pStart, pEnd);
879 // Change index into octreeData into face label
880 curHit.setIndex(boundaryTree().shapes().faceLabels()[curHit.index()]);
886 Foam::List<Foam::pointIndexHit> Foam::meshSearch::intersections
892 DynamicList<pointIndexHit> hits;
894 vector edgeVec = pEnd - pStart;
895 edgeVec /= mag(edgeVec);
902 bHit = intersection(pt, pEnd);
908 const vector& area = mesh_.faceAreas()[bHit.index()];
910 scalar typDim = Foam::sqrt(mag(area));
912 if ((mag(bHit.hitPoint() - pEnd)/typDim) < SMALL)
917 // Restart from hitPoint shifted a little bit in the direction
918 // of the destination
922 + offset(bHit.hitPoint(), bHit.index(), edgeVec);
934 bool Foam::meshSearch::isInside(const point& p) const
937 boundaryTree().getVolumeType(p)
938 == indexedOctree<treeDataFace>::INSIDE;
942 // Delete all storage
943 void Foam::meshSearch::clearOut()
945 deleteDemandDrivenData(boundaryTreePtr_);
946 deleteDemandDrivenData(cellTreePtr_);
947 deleteDemandDrivenData(cellCentreTreePtr_);
951 void Foam::meshSearch::correct()
957 // ************************************************************************* //