1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. 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
102 const point& location
105 const indexedOctree<treeDataPoint>& tree = cellCentreTree();
107 scalar span = tree.bb().mag();
109 pointIndexHit info = tree.findNearest(location, Foam::sqr(span));
113 info = tree.findNearest(location, Foam::sqr(GREAT));
122 Foam::meshSearch::findNearestCellLinear
124 const point& location
127 const vectorField& centres = mesh_.cellCentres();
129 label nearestIndex = 0;
130 scalar minProximity = magSqr(centres[nearestIndex] - location);
145 Foam::label Foam::meshSearch::findNearestCellWalk
147 const point& location,
148 const label seedCellI
155 "meshSearch::findNearestCellWalk(const point&, const label)"
156 ) << "illegal seedCell:" << seedCellI << exit(FatalError);
159 // Walk in direction of face that decreases distance
161 label curCellI = seedCellI;
162 scalar distanceSqr = magSqr(mesh_.cellCentres()[curCellI] - location);
168 // Try neighbours of curCellI
173 mesh_.cellCells()[curCellI],
183 // tree based searching
184 Foam::label Foam::meshSearch::findNearestFaceTree(const point& location) const
186 // Search nearest cell centre.
187 const indexedOctree<treeDataPoint>& tree = cellCentreTree();
189 scalar span = tree.bb().mag();
191 // Search with decent span
192 pointIndexHit info = tree.findNearest(location, Foam::sqr(span));
196 // Search with desparate span
197 info = tree.findNearest(location, Foam::sqr(GREAT));
201 // Now check any of the faces of the nearest cell
202 const vectorField& centres = mesh_.faceCentres();
203 const cell& ownFaces = mesh_.cells()[info.index()];
205 label nearestFaceI = ownFaces[0];
206 scalar minProximity = magSqr(centres[nearestFaceI] - location);
222 Foam::label Foam::meshSearch::findNearestFaceLinear(const point& location) const
224 const vectorField& centres = mesh_.faceCentres();
226 label nearestFaceI = 0;
227 scalar minProximity = magSqr(centres[nearestFaceI] - location);
242 Foam::label Foam::meshSearch::findNearestFaceWalk
244 const point& location,
245 const label seedFaceI
252 "meshSearch::findNearestFaceWalk(const point&, const label)"
253 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
256 const vectorField& centres = mesh_.faceCentres();
259 // Walk in direction of face that decreases distance
261 label curFaceI = seedFaceI;
262 scalar distanceSqr = magSqr(centres[curFaceI] - location);
266 label betterFaceI = curFaceI;
272 mesh_.cells()[mesh_.faceOwner()[curFaceI]],
277 if (mesh_.isInternalFace(curFaceI))
283 mesh_.cells()[mesh_.faceNeighbour()[curFaceI]],
289 if (betterFaceI == curFaceI)
294 curFaceI = betterFaceI;
301 Foam::label Foam::meshSearch::findCellLinear(const point& location) const
303 bool cellFound = false;
308 while ((!cellFound) && (n < mesh_.nCells()))
310 if (pointInCell(location, n))
331 Foam::label Foam::meshSearch::findNearestBoundaryFaceWalk
333 const point& location,
334 const label seedFaceI
341 "meshSearch::findNearestBoundaryFaceWalk"
342 "(const point&, const label)"
343 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
346 // Start off from seedFaceI
348 label curFaceI = seedFaceI;
350 const face& f = mesh_.faces()[curFaceI];
352 scalar minDist = f.nearestPoint
364 // Search through all neighbouring boundary faces by going
367 label lastFaceI = curFaceI;
369 const labelList& myEdges = mesh_.faceEdges()[curFaceI];
371 forAll (myEdges, myEdgeI)
373 const labelList& neighbours = mesh_.edgeFaces()[myEdges[myEdgeI]];
375 // Check any face which uses edge, is boundary face and
376 // is not curFaceI itself.
378 forAll(neighbours, nI)
380 label faceI = neighbours[nI];
384 (faceI >= mesh_.nInternalFaces())
385 && (faceI != lastFaceI)
388 const face& f = mesh_.faces()[faceI];
390 pointHit curHit = f.nearestPoint
396 // If the face is closer, reset current face and distance
397 if (curHit.distance() < minDist)
399 minDist = curHit.distance();
401 closer = true; // a closer neighbour has been found
412 Foam::vector Foam::meshSearch::offset
419 // Get the neighbouring cell
420 label ownerCellI = mesh_.faceOwner()[bFaceI];
422 const point& c = mesh_.cellCentres()[ownerCellI];
424 // Typical dimension: distance from point on face to cell centre
425 scalar typDim = mag(c - bPoint);
427 return tol_*typDim*dir;
431 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
433 // Construct from components
434 Foam::meshSearch::meshSearch(const polyMesh& mesh, const bool faceDecomp)
437 faceDecomp_(faceDecomp),
438 cloud_(mesh_, IDLList<passiveParticle>()),
439 boundaryTreePtr_(NULL),
441 cellCentreTreePtr_(NULL)
445 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
447 Foam::meshSearch::~meshSearch()
453 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
455 const Foam::indexedOctree<Foam::treeDataFace>& Foam::meshSearch::boundaryTree()
458 if (!boundaryTreePtr_)
464 // all boundary faces (not just walls)
465 labelList bndFaces(mesh_.nFaces()-mesh_.nInternalFaces());
468 bndFaces[i] = mesh_.nInternalFaces() + i;
471 treeBoundBox overallBb(mesh_.points());
472 Random rndGen(123456);
473 overallBb = overallBb.extend(rndGen, 1E-4);
474 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
475 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
477 boundaryTreePtr_ = new indexedOctree<treeDataFace>
479 treeDataFace // all information needed to search faces
481 false, // do not cache bb
483 bndFaces // boundary faces only
485 overallBb, // overall search domain
492 return *boundaryTreePtr_;
496 const Foam::indexedOctree<Foam::treeDataCell>&
497 Foam::meshSearch::cellTree() const
505 treeBoundBox overallBb(mesh_.points());
506 Random rndGen(123456);
507 overallBb = overallBb.extend(rndGen, 1E-4);
508 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
509 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
511 cellTreePtr_ = new indexedOctree<treeDataCell>
515 false, // not cache bb
518 overallBb, // overall search domain
525 return *cellTreePtr_;
530 const Foam::indexedOctree<Foam::treeDataPoint>&
531 Foam::meshSearch::cellCentreTree() const
533 if (!cellCentreTreePtr_)
539 treeBoundBox overallBb(mesh_.cellCentres());
540 Random rndGen(123456);
541 overallBb = overallBb.extend(rndGen, 1E-4);
542 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
543 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
545 cellCentreTreePtr_ = new indexedOctree<treeDataPoint>
547 treeDataPoint(mesh_.cellCentres()),
548 overallBb, // overall search domain
550 10.0, // maximum ratio of cubes v.s. cells
551 100.0 // max. duplicity; n/a since no bounding boxes.
555 return *cellCentreTreePtr_;
559 // Is the point in the cell
560 // Works by checking if there is a face inbetween the point and the cell
562 // Check for internal uses proper face decomposition or just average normal.
563 bool Foam::meshSearch::pointInCell(const point& p, label cellI) const
567 const point& ctr = mesh_.cellCentres()[cellI];
570 scalar magDir = mag(dir);
572 // Check if any faces are hit by ray from cell centre to p.
573 // If none -> p is in cell.
574 const labelList& cFaces = mesh_.cells()[cellI];
576 // Make sure half_ray does not pick up any faces on the wrong
578 scalar oldTol = intersection::setPlanarTol(0.0);
582 label faceI = cFaces[i];
584 const face& f = mesh_.faces()[faceI];
588 pointHit inter = f.ray
593 intersection::HALF_RAY,
599 scalar dist = inter.distance();
603 // Valid hit. Hit face so point is not in cell.
604 intersection::setPlanarTol(oldTol);
612 intersection::setPlanarTol(oldTol);
614 // No face inbetween point and cell centre so point is inside.
619 const labelList& f = mesh_.cells()[cellI];
620 const labelList& owner = mesh_.faceOwner();
621 const vectorField& cf = mesh_.faceCentres();
622 const vectorField& Sf = mesh_.faceAreas();
626 label nFace = f[facei];
627 vector proj = p - cf[nFace];
628 vector normal = Sf[nFace];
629 if (owner[nFace] == cellI)
631 if ((normal & proj) > 0)
638 if ((normal & proj) < 0)
650 Foam::label Foam::meshSearch::findNearestCell
652 const point& location,
653 const label seedCellI,
654 const bool useTreeSearch
661 return findNearestCellTree(location);
665 return findNearestCellLinear(location);
670 return findNearestCellWalk(location, seedCellI);
675 Foam::label Foam::meshSearch::findNearestFace
677 const point& location,
678 const label seedFaceI,
679 const bool useTreeSearch
686 return findNearestFaceTree(location);
690 return findNearestFaceLinear(location);
695 return findNearestFaceWalk(location, seedFaceI);
700 Foam::label Foam::meshSearch::findCell
702 const point& location,
703 const label seedCellI,
704 const bool useTreeSearch
707 // Find the nearest cell centre to this location
708 label nearCellI = findNearestCell(location, seedCellI, useTreeSearch);
712 Pout<< "findCell : nearCellI:" << nearCellI
713 << " ctr:" << mesh_.cellCentres()[nearCellI]
717 if (pointInCell(location, nearCellI))
725 // Start searching from cell centre of nearCell
726 point curPoint = mesh_.cellCentres()[nearCellI];
728 vector edgeVec = location - curPoint;
729 edgeVec /= mag(edgeVec);
733 // Walk neighbours (using tracking) to get closer
734 passiveParticle tracker(cloud_, curPoint, nearCellI);
738 Pout<< "findCell : tracked from curPoint:" << curPoint
739 << " nearCellI:" << nearCellI;
742 tracker.track(location);
746 Pout<< " to " << tracker.position()
747 << " need:" << location
748 << " onB:" << tracker.onBoundary()
749 << " cell:" << tracker.cell()
750 << " face:" << tracker.face() << endl;
753 if (!tracker.onBoundary())
755 // stopped not on boundary -> reached location
756 return tracker.cell();
759 // stopped on boundary face. Compare positions
760 scalar typDim = sqrt(mag(mesh_.faceAreas()[tracker.face()]));
762 if ((mag(tracker.position() - location)/typDim) < SMALL)
764 return tracker.cell();
767 // tracking stopped at boundary. Find next boundary
768 // intersection from current point (shifted out a little bit)
769 // in the direction of the destination
773 + offset(tracker.position(), tracker.face(), edgeVec);
777 Pout<< "Searching for next boundary from curPoint:"
779 << " to location:" << location << endl;
781 pointIndexHit curHit = intersection(curPoint, location);
784 Pout<< "Returned from line search with ";
795 nearCellI = mesh_.faceOwner()[curHit.index()];
798 + offset(curHit.hitPoint(), curHit.index(), edgeVec);
805 return findCellLinear(location);
812 Foam::label Foam::meshSearch::findNearestBoundaryFace
814 const point& location,
815 const label seedFaceI,
816 const bool useTreeSearch
823 const indexedOctree<treeDataFace>& tree = boundaryTree();
825 scalar span = tree.bb().mag();
827 pointIndexHit info = boundaryTree().findNearest
835 info = boundaryTree().findNearest
842 return tree.shapes().faceLabels()[info.index()];
846 scalar minDist = GREAT;
852 label faceI = mesh_.nInternalFaces();
853 faceI < mesh_.nFaces();
857 const face& f = mesh_.faces()[faceI];
866 if (curHit.distance() < minDist)
868 minDist = curHit.distance();
877 return findNearestBoundaryFaceWalk(location, seedFaceI);
882 Foam::pointIndexHit Foam::meshSearch::intersection
888 pointIndexHit curHit = boundaryTree().findLine(pStart, pEnd);
892 // Change index into octreeData into face label
893 curHit.setIndex(boundaryTree().shapes().faceLabels()[curHit.index()]);
899 Foam::List<Foam::pointIndexHit> Foam::meshSearch::intersections
905 DynamicList<pointIndexHit> hits;
907 vector edgeVec = pEnd - pStart;
908 edgeVec /= mag(edgeVec);
915 bHit = intersection(pt, pEnd);
921 const vector& area = mesh_.faceAreas()[bHit.index()];
923 scalar typDim = Foam::sqrt(mag(area));
925 if ((mag(bHit.hitPoint() - pEnd)/typDim) < SMALL)
930 // Restart from hitPoint shifted a little bit in the direction
931 // of the destination
935 + offset(bHit.hitPoint(), bHit.index(), edgeVec);
947 bool Foam::meshSearch::isInside(const point& p) const
950 boundaryTree().getVolumeType(p)
951 == indexedOctree<treeDataFace>::INSIDE;
955 // Delete all storage
956 void Foam::meshSearch::clearOut()
958 deleteDemandDrivenData(boundaryTreePtr_);
959 deleteDemandDrivenData(cellTreePtr_);
960 deleteDemandDrivenData(cellCentreTreePtr_);
964 void Foam::meshSearch::correct()
970 // ************************************************************************* //