1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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 "treeDataPolyMeshCell.H"
32 #include "treeDataFace.H"
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 defineTypeNameAndDebug(Foam::meshSearch, 0);
38 Foam::scalar Foam::meshSearch::tol_ = 1E-3;
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 bool Foam::meshSearch::findNearer
46 const pointField& points,
48 scalar& nearestDistSqr
53 forAll(points, pointI)
55 scalar distSqr = magSqr(points[pointI] - sample);
57 if (distSqr < nearestDistSqr)
59 nearestDistSqr = distSqr;
69 bool Foam::meshSearch::findNearer
72 const pointField& points,
73 const labelList& indices,
75 scalar& nearestDistSqr
82 label pointI = indices[i];
84 scalar distSqr = magSqr(points[pointI] - sample);
86 if (distSqr < nearestDistSqr)
88 nearestDistSqr = distSqr;
98 // tree based searching
99 Foam::label Foam::meshSearch::findNearestCellTree(const point& location) const
101 const indexedOctree<treeDataPolyMeshCell>& tree = cellTree();
103 pointIndexHit info = tree.findNearest
106 magSqr(tree.bb().max()-tree.bb().min())
111 info = tree.findNearest(location, Foam::sqr(GREAT));
118 Foam::label Foam::meshSearch::findNearestCellLinear(const point& location) const
120 const vectorField& centres = mesh_.cellCentres();
122 label nearestIndex = 0;
123 scalar minProximity = magSqr(centres[nearestIndex] - location);
138 Foam::label Foam::meshSearch::findNearestCellWalk
140 const point& location,
141 const label seedCellI
148 "meshSearch::findNearestCellWalk(const point&, const label)"
149 ) << "illegal seedCell:" << seedCellI << exit(FatalError);
152 // Walk in direction of face that decreases distance
154 label curCellI = seedCellI;
155 scalar distanceSqr = magSqr(mesh_.cellCentres()[curCellI] - location);
161 // Try neighbours of curCellI
166 mesh_.cellCells()[curCellI],
176 // tree based searching
177 Foam::label Foam::meshSearch::findNearestFaceTree(const point& location) const
179 // Search nearest cell centre.
180 const indexedOctree<treeDataPolyMeshCell>& tree = cellTree();
182 // Search with decent span
183 pointIndexHit info = tree.findNearest
186 magSqr(tree.bb().max()-tree.bb().min())
191 // Search with desparate span
192 info = tree.findNearest(location, Foam::sqr(GREAT));
196 // Now check any of the faces of the nearest cell
197 const vectorField& centres = mesh_.faceCentres();
198 const cell& ownFaces = mesh_.cells()[info.index()];
200 label nearestFaceI = ownFaces[0];
201 scalar minProximity = magSqr(centres[nearestFaceI] - location);
217 Foam::label Foam::meshSearch::findNearestFaceLinear(const point& location) const
219 const vectorField& centres = mesh_.faceCentres();
221 label nearestFaceI = 0;
222 scalar minProximity = magSqr(centres[nearestFaceI] - location);
237 Foam::label Foam::meshSearch::findNearestFaceWalk
239 const point& location,
240 const label seedFaceI
247 "meshSearch::findNearestFaceWalk(const point&, const label)"
248 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
251 const vectorField& centres = mesh_.faceCentres();
254 // Walk in direction of face that decreases distance
256 label curFaceI = seedFaceI;
257 scalar distanceSqr = magSqr(centres[curFaceI] - location);
261 label betterFaceI = curFaceI;
267 mesh_.cells()[mesh_.faceOwner()[curFaceI]],
272 if (mesh_.isInternalFace(curFaceI))
278 mesh_.cells()[mesh_.faceNeighbour()[curFaceI]],
284 if (betterFaceI == curFaceI)
289 curFaceI = betterFaceI;
296 Foam::label Foam::meshSearch::findCellLinear(const point& location) const
298 bool cellFound = false;
303 while ((!cellFound) && (n < mesh_.nCells()))
305 if (pointInCell(location, n))
327 Foam::label Foam::meshSearch::findCellWalk
329 const point& location,
330 const label seedCellI
337 "meshSearch::findCellWalk(const point&, const label)"
338 ) << "illegal seedCell:" << seedCellI << exit(FatalError);
341 if (pointInCell(location, seedCellI))
346 // Walk in direction of face that decreases distance
347 label curCellI = seedCellI;
348 scalar nearestDistSqr = magSqr(mesh_.cellCentres()[curCellI] - location);
352 // Try neighbours of curCellI
354 const cell& cFaces = mesh_.cells()[curCellI];
356 label nearestCellI = -1;
360 label faceI = cFaces[i];
362 if (mesh_.isInternalFace(faceI))
364 label cellI = mesh_.faceOwner()[faceI];
365 if (cellI == curCellI)
367 cellI = mesh_.faceNeighbour()[faceI];
370 // Check if this is the correct cell
371 if (pointInCell(location, cellI))
376 // Also calculate the nearest cell
377 scalar distSqr = magSqr(mesh_.cellCentres()[cellI] - location);
379 if (distSqr < nearestDistSqr)
381 nearestDistSqr = distSqr;
382 nearestCellI = cellI;
387 if (nearestCellI == -1)
392 // Continue with the nearest cell
393 curCellI = nearestCellI;
400 Foam::label Foam::meshSearch::findNearestBoundaryFaceWalk
402 const point& location,
403 const label seedFaceI
410 "meshSearch::findNearestBoundaryFaceWalk"
411 "(const point&, const label)"
412 ) << "illegal seedFace:" << seedFaceI << exit(FatalError);
415 // Start off from seedFaceI
417 label curFaceI = seedFaceI;
419 const face& f = mesh_.faces()[curFaceI];
421 scalar minDist = f.nearestPoint
433 // Search through all neighbouring boundary faces by going
436 label lastFaceI = curFaceI;
438 const labelList& myEdges = mesh_.faceEdges()[curFaceI];
440 forAll(myEdges, myEdgeI)
442 const labelList& neighbours = mesh_.edgeFaces()[myEdges[myEdgeI]];
444 // Check any face which uses edge, is boundary face and
445 // is not curFaceI itself.
447 forAll(neighbours, nI)
449 label faceI = neighbours[nI];
453 (faceI >= mesh_.nInternalFaces())
454 && (faceI != lastFaceI)
457 const face& f = mesh_.faces()[faceI];
459 pointHit curHit = f.nearestPoint
465 // If the face is closer, reset current face and distance
466 if (curHit.distance() < minDist)
468 minDist = curHit.distance();
470 closer = true; // a closer neighbour has been found
481 Foam::vector Foam::meshSearch::offset
488 // Get the neighbouring cell
489 label ownerCellI = mesh_.faceOwner()[bFaceI];
491 const point& c = mesh_.cellCentres()[ownerCellI];
493 // Typical dimension: distance from point on face to cell centre
494 scalar typDim = mag(c - bPoint);
496 return tol_*typDim*dir;
500 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
502 // Construct from components
503 Foam::meshSearch::meshSearch(const polyMesh& mesh, const bool faceDecomp)
506 faceDecomp_(faceDecomp)
510 // Construct with a custom bounding box
511 Foam::meshSearch::meshSearch
513 const polyMesh& mesh,
514 const treeBoundBox& bb,
515 const bool faceDecomp
519 faceDecomp_(faceDecomp)
521 overallBbPtr_.reset(new treeBoundBox(bb));
525 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
527 Foam::meshSearch::~meshSearch()
533 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
535 const Foam::indexedOctree<Foam::treeDataFace>& Foam::meshSearch::boundaryTree()
538 if (!boundaryTreePtr_.valid())
544 if (!overallBbPtr_.valid())
546 Random rndGen(261782);
549 new treeBoundBox(mesh_.points())
552 treeBoundBox& overallBb = overallBbPtr_();
553 // Extend slightly and make 3D
554 overallBb = overallBb.extend(rndGen, 1E-4);
555 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
556 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
559 // all boundary faces (not just walls)
560 labelList bndFaces(mesh_.nFaces()-mesh_.nInternalFaces());
563 bndFaces[i] = mesh_.nInternalFaces() + i;
566 boundaryTreePtr_.reset
568 new indexedOctree<treeDataFace>
570 treeDataFace // all information needed to search faces
572 false, // do not cache bb
574 bndFaces // boundary faces only
576 overallBbPtr_(), // overall search domain
584 return boundaryTreePtr_();
588 const Foam::indexedOctree<Foam::treeDataPolyMeshCell>&
589 Foam::meshSearch::cellTree() const
591 if (!cellTreePtr_.valid())
597 if (!overallBbPtr_.valid())
599 Random rndGen(261782);
602 new treeBoundBox(mesh_.points())
605 treeBoundBox& overallBb = overallBbPtr_();
606 // Extend slightly and make 3D
607 overallBb = overallBb.extend(rndGen, 1E-4);
608 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
609 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
614 new indexedOctree<treeDataPolyMeshCell>
618 false, // not cache bb
629 return cellTreePtr_();
633 // Is the point in the cell
634 // Works by checking if there is a face inbetween the point and the cell
636 // Check for internal uses proper face decomposition or just average normal.
637 bool Foam::meshSearch::pointInCell(const point& p, label cellI) const
641 const point& ctr = mesh_.cellCentres()[cellI];
644 scalar magDir = mag(dir);
646 // Check if any faces are hit by ray from cell centre to p.
647 // If none -> p is in cell.
648 const labelList& cFaces = mesh_.cells()[cellI];
650 // Make sure half_ray does not pick up any faces on the wrong
652 scalar oldTol = intersection::setPlanarTol(0.0);
656 label faceI = cFaces[i];
658 pointHit inter = mesh_.faces()[faceI].ray
663 intersection::HALF_RAY,
669 scalar dist = inter.distance();
673 // Valid hit. Hit face so point is not in cell.
674 intersection::setPlanarTol(oldTol);
681 intersection::setPlanarTol(oldTol);
683 // No face inbetween point and cell centre so point is inside.
688 const labelList& f = mesh_.cells()[cellI];
689 const labelList& owner = mesh_.faceOwner();
690 const vectorField& cf = mesh_.faceCentres();
691 const vectorField& Sf = mesh_.faceAreas();
695 label nFace = f[facei];
696 vector proj = p - cf[nFace];
697 vector normal = Sf[nFace];
698 if (owner[nFace] == cellI)
700 if ((normal & proj) > 0)
707 if ((normal & proj) < 0)
719 Foam::label Foam::meshSearch::findNearestCell
721 const point& location,
722 const label seedCellI,
723 const bool useTreeSearch
730 return findNearestCellTree(location);
734 return findNearestCellLinear(location);
739 return findNearestCellWalk(location, seedCellI);
744 Foam::label Foam::meshSearch::findNearestFace
746 const point& location,
747 const label seedFaceI,
748 const bool useTreeSearch
755 return findNearestFaceTree(location);
759 return findNearestFaceLinear(location);
764 return findNearestFaceWalk(location, seedFaceI);
769 Foam::label Foam::meshSearch::findCell
771 const point& location,
772 const label seedCellI,
773 const bool useTreeSearch
776 // Find the nearest cell centre to this location
781 return cellTree().findInside(location);
785 return findCellLinear(location);
790 return findCellWalk(location, seedCellI);
795 Foam::label Foam::meshSearch::findNearestBoundaryFace
797 const point& location,
798 const label seedFaceI,
799 const bool useTreeSearch
806 const indexedOctree<treeDataFace>& tree = boundaryTree();
808 pointIndexHit info = boundaryTree().findNearest
811 magSqr(tree.bb().max()-tree.bb().min())
816 info = boundaryTree().findNearest
823 return tree.shapes().faceLabels()[info.index()];
827 scalar minDist = GREAT;
833 label faceI = mesh_.nInternalFaces();
834 faceI < mesh_.nFaces();
838 const face& f = mesh_.faces()[faceI];
847 if (curHit.distance() < minDist)
849 minDist = curHit.distance();
858 return findNearestBoundaryFaceWalk(location, seedFaceI);
863 Foam::pointIndexHit Foam::meshSearch::intersection
869 pointIndexHit curHit = boundaryTree().findLine(pStart, pEnd);
873 // Change index into octreeData into face label
874 curHit.setIndex(boundaryTree().shapes().faceLabels()[curHit.index()]);
880 Foam::List<Foam::pointIndexHit> Foam::meshSearch::intersections
886 DynamicList<pointIndexHit> hits;
888 vector edgeVec = pEnd - pStart;
889 edgeVec /= mag(edgeVec);
896 bHit = intersection(pt, pEnd);
902 const vector& area = mesh_.faceAreas()[bHit.index()];
904 scalar typDim = Foam::sqrt(mag(area));
906 if ((mag(bHit.hitPoint() - pEnd)/typDim) < SMALL)
911 // Restart from hitPoint shifted a little bit in the direction
912 // of the destination
916 + offset(bHit.hitPoint(), bHit.index(), edgeVec);
919 } while (bHit.hit());
928 bool Foam::meshSearch::isInside(const point& p) const
931 boundaryTree().getVolumeType(p)
932 == indexedOctree<treeDataFace>::INSIDE;
936 // Delete all storage
937 void Foam::meshSearch::clearOut()
939 boundaryTreePtr_.clear();
940 cellTreePtr_.clear();
941 overallBbPtr_.clear();
945 void Foam::meshSearch::correct()
951 // ************************************************************************* //