1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2004-2011 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<treeDataCell>& tree = cellTree();
104 pointIndexHit info = tree.findNearest
107 magSqr(tree.bb().max()-tree.bb().min())
112 info = tree.findNearest(location, Foam::sqr(GREAT));
119 Foam::label Foam::meshSearch::findNearestCellLinear(const point& location) const
121 const vectorField& centres = mesh_.cellCentres();
123 label nearestIndex = 0;
124 scalar minProximity = magSqr(centres[nearestIndex] - location);
139 Foam::label Foam::meshSearch::findNearestCellWalk
141 const point& location,
142 const label seedCellI
149 "meshSearch::findNearestCellWalk(const point&, const label)"
150 ) << "illegal seedCell:" << seedCellI << exit(FatalError);
153 // Walk in direction of face that decreases distance
155 label curCellI = seedCellI;
156 scalar distanceSqr = magSqr(mesh_.cellCentres()[curCellI] - location);
162 // Try neighbours of curCellI
167 mesh_.cellCells()[curCellI],
177 // tree based searching
178 Foam::label Foam::meshSearch::findNearestFaceTree(const point& location) const
180 // Search nearest cell centre.
181 const indexedOctree<treeDataCell>& tree = cellTree();
183 // Search with decent span
184 pointIndexHit info = tree.findNearest
187 magSqr(tree.bb().max()-tree.bb().min())
192 // Search with desparate span
193 info = tree.findNearest(location, Foam::sqr(GREAT));
197 // Now check any of the faces of the nearest cell
198 const vectorField& centres = mesh_.faceCentres();
199 const cell& ownFaces = mesh_.cells()[info.index()];
201 label nearestFaceI = ownFaces[0];
202 scalar minProximity = magSqr(centres[nearestFaceI] - location);
218 Foam::label Foam::meshSearch::findNearestFaceLinear(const point& location) const
220 const vectorField& centres = mesh_.faceCentres();
222 label nearestFaceI = 0;
223 scalar minProximity = magSqr(centres[nearestFaceI] - location);
238 Foam::label Foam::meshSearch::findNearestFaceWalk
240 const point& location,
241 const label seedFaceI
248 "meshSearch::findNearestFaceWalk(const point&, const label)"
249 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
252 const vectorField& centres = mesh_.faceCentres();
255 // Walk in direction of face that decreases distance
257 label curFaceI = seedFaceI;
258 scalar distanceSqr = magSqr(centres[curFaceI] - location);
262 label betterFaceI = curFaceI;
268 mesh_.cells()[mesh_.faceOwner()[curFaceI]],
273 if (mesh_.isInternalFace(curFaceI))
279 mesh_.cells()[mesh_.faceNeighbour()[curFaceI]],
285 if (betterFaceI == curFaceI)
290 curFaceI = betterFaceI;
297 Foam::label Foam::meshSearch::findCellLinear(const point& location) const
299 bool cellFound = false;
304 while ((!cellFound) && (n < mesh_.nCells()))
306 if (pointInCell(location, n))
328 Foam::label Foam::meshSearch::findCellWalk
330 const point& location,
331 const label seedCellI
338 "meshSearch::findCellWalk(const point&, const label)"
339 ) << "illegal seedCell:" << seedCellI << exit(FatalError);
342 if (pointInCell(location, seedCellI))
347 // Walk in direction of face that decreases distance
348 label curCellI = seedCellI;
349 scalar nearestDistSqr = magSqr(mesh_.cellCentres()[curCellI] - location);
353 // Try neighbours of curCellI
355 const cell& cFaces = mesh_.cells()[curCellI];
357 label nearestCellI = -1;
361 label faceI = cFaces[i];
363 if (mesh_.isInternalFace(faceI))
365 label cellI = mesh_.faceOwner()[faceI];
366 if (cellI == curCellI)
368 cellI = mesh_.faceNeighbour()[faceI];
371 // Check if this is the correct cell
372 if (pointInCell(location, cellI))
377 // Also calculate the nearest cell
378 scalar distSqr = magSqr(mesh_.cellCentres()[cellI] - location);
380 if (distSqr < nearestDistSqr)
382 nearestDistSqr = distSqr;
383 nearestCellI = cellI;
388 if (nearestCellI == -1)
393 // Continue with the nearest cell
394 curCellI = nearestCellI;
401 Foam::label Foam::meshSearch::findNearestBoundaryFaceWalk
403 const point& location,
404 const label seedFaceI
411 "meshSearch::findNearestBoundaryFaceWalk"
412 "(const point&, const label)"
413 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
416 // Start off from seedFaceI
418 label curFaceI = seedFaceI;
420 const face& f = mesh_.faces()[curFaceI];
422 scalar minDist = f.nearestPoint
434 // Search through all neighbouring boundary faces by going
437 label lastFaceI = curFaceI;
439 const labelList& myEdges = mesh_.faceEdges()[curFaceI];
441 forAll(myEdges, myEdgeI)
443 const labelList& neighbours = mesh_.edgeFaces()[myEdges[myEdgeI]];
445 // Check any face which uses edge, is boundary face and
446 // is not curFaceI itself.
448 forAll(neighbours, nI)
450 label faceI = neighbours[nI];
454 (faceI >= mesh_.nInternalFaces())
455 && (faceI != lastFaceI)
458 const face& f = mesh_.faces()[faceI];
460 pointHit curHit = f.nearestPoint
466 // If the face is closer, reset current face and distance
467 if (curHit.distance() < minDist)
469 minDist = curHit.distance();
471 closer = true; // a closer neighbour has been found
482 Foam::vector Foam::meshSearch::offset
489 // Get the neighbouring cell
490 label ownerCellI = mesh_.faceOwner()[bFaceI];
492 const point& c = mesh_.cellCentres()[ownerCellI];
494 // Typical dimension: distance from point on face to cell centre
495 scalar typDim = mag(c - bPoint);
497 return tol_*typDim*dir;
501 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
503 // Construct from components
504 Foam::meshSearch::meshSearch(const polyMesh& mesh, const bool faceDecomp)
507 faceDecomp_(faceDecomp)
511 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
513 Foam::meshSearch::~meshSearch()
519 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
521 const Foam::indexedOctree<Foam::treeDataFace>& Foam::meshSearch::boundaryTree()
524 if (!boundaryTreePtr_.valid())
530 // all boundary faces (not just walls)
531 labelList bndFaces(mesh_.nFaces()-mesh_.nInternalFaces());
534 bndFaces[i] = mesh_.nInternalFaces() + i;
537 treeBoundBox overallBb(mesh_.points());
538 Random rndGen(123456);
539 overallBb = overallBb.extend(rndGen, 1E-4);
540 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
541 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
543 boundaryTreePtr_.reset
545 new indexedOctree<treeDataFace>
547 treeDataFace // all information needed to search faces
549 false, // do not cache bb
551 bndFaces // boundary faces only
553 overallBb, // overall search domain
561 return boundaryTreePtr_();
565 const Foam::indexedOctree<Foam::treeDataCell>& Foam::meshSearch::cellTree()
568 if (!cellTreePtr_.valid())
570 treeBoundBox overallBb(mesh_.points());
572 Random rndGen(261782);
574 overallBb = overallBb.extend(rndGen, 1E-4);
575 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
576 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
580 new indexedOctree<treeDataCell>
584 false, // not cache bb
595 return cellTreePtr_();
599 // Is the point in the cell
600 // Works by checking if there is a face inbetween the point and the cell
602 // Check for internal uses proper face decomposition or just average normal.
603 bool Foam::meshSearch::pointInCell(const point& p, label cellI) const
607 const point& ctr = mesh_.cellCentres()[cellI];
610 scalar magDir = mag(dir);
612 // Check if any faces are hit by ray from cell centre to p.
613 // If none -> p is in cell.
614 const labelList& cFaces = mesh_.cells()[cellI];
616 // Make sure half_ray does not pick up any faces on the wrong
618 scalar oldTol = intersection::setPlanarTol(0.0);
622 label faceI = cFaces[i];
624 pointHit inter = mesh_.faces()[faceI].ray
629 intersection::HALF_RAY,
635 scalar dist = inter.distance();
639 // Valid hit. Hit face so point is not in cell.
640 intersection::setPlanarTol(oldTol);
647 intersection::setPlanarTol(oldTol);
649 // No face inbetween point and cell centre so point is inside.
654 const labelList& f = mesh_.cells()[cellI];
655 const labelList& owner = mesh_.faceOwner();
656 const vectorField& cf = mesh_.faceCentres();
657 const vectorField& Sf = mesh_.faceAreas();
661 label nFace = f[facei];
662 vector proj = p - cf[nFace];
663 vector normal = Sf[nFace];
664 if (owner[nFace] == cellI)
666 if ((normal & proj) > 0)
673 if ((normal & proj) < 0)
685 Foam::label Foam::meshSearch::findNearestCell
687 const point& location,
688 const label seedCellI,
689 const bool useTreeSearch
696 return findNearestCellTree(location);
700 return findNearestCellLinear(location);
705 return findNearestCellWalk(location, seedCellI);
710 Foam::label Foam::meshSearch::findNearestFace
712 const point& location,
713 const label seedFaceI,
714 const bool useTreeSearch
721 return findNearestFaceTree(location);
725 return findNearestFaceLinear(location);
730 return findNearestFaceWalk(location, seedFaceI);
735 Foam::label Foam::meshSearch::findCell
737 const point& location,
738 const label seedCellI,
739 const bool useTreeSearch
742 // Find the nearest cell centre to this location
747 return cellTree().findInside(location);
751 return findCellLinear(location);
756 return findCellWalk(location, seedCellI);
761 Foam::label Foam::meshSearch::findNearestBoundaryFace
763 const point& location,
764 const label seedFaceI,
765 const bool useTreeSearch
772 const indexedOctree<treeDataFace>& tree = boundaryTree();
774 pointIndexHit info = boundaryTree().findNearest
777 magSqr(tree.bb().max()-tree.bb().min())
782 info = boundaryTree().findNearest
789 return tree.shapes().faceLabels()[info.index()];
793 scalar minDist = GREAT;
799 label faceI = mesh_.nInternalFaces();
800 faceI < mesh_.nFaces();
804 const face& f = mesh_.faces()[faceI];
813 if (curHit.distance() < minDist)
815 minDist = curHit.distance();
824 return findNearestBoundaryFaceWalk(location, seedFaceI);
829 Foam::pointIndexHit Foam::meshSearch::intersection
835 pointIndexHit curHit = boundaryTree().findLine(pStart, pEnd);
839 // Change index into octreeData into face label
840 curHit.setIndex(boundaryTree().shapes().faceLabels()[curHit.index()]);
846 Foam::List<Foam::pointIndexHit> Foam::meshSearch::intersections
852 DynamicList<pointIndexHit> hits;
854 vector edgeVec = pEnd - pStart;
855 edgeVec /= mag(edgeVec);
862 bHit = intersection(pt, pEnd);
868 const vector& area = mesh_.faceAreas()[bHit.index()];
870 scalar typDim = Foam::sqrt(mag(area));
872 if ((mag(bHit.hitPoint() - pEnd)/typDim) < SMALL)
877 // Restart from hitPoint shifted a little bit in the direction
878 // of the destination
882 + offset(bHit.hitPoint(), bHit.index(), edgeVec);
885 } while (bHit.hit());
894 bool Foam::meshSearch::isInside(const point& p) const
897 boundaryTree().getVolumeType(p)
898 == indexedOctree<treeDataFace>::INSIDE;
902 // Delete all storage
903 void Foam::meshSearch::clearOut()
905 boundaryTreePtr_.clear();
906 cellTreePtr_.clear();
910 void Foam::meshSearch::correct()
916 // ************************************************************************* //