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 "searchableBox.H"
27 #include "addToRunTimeSelectionTable.H"
28 #include "SortableList.H"
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 defineTypeNameAndDebug(searchableBox, 0);
35 addToRunTimeSelectionTable(searchableSurface, searchableBox, dict);
39 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
41 void Foam::searchableBox::projectOntoCoordPlane
49 info.rawPoint()[dir] = planePt[dir];
51 if (planePt[dir] == min()[dir])
55 else if (planePt[dir] == max()[dir])
57 info.setIndex(dir*2+1);
61 FatalErrorIn("searchableBox::projectOntoCoordPlane(..)")
62 << "Point on plane " << planePt
63 << " is not on coordinate " << min()[dir]
64 << " nor " << max()[dir] << abort(FatalError);
69 // Returns miss or hit with face (0..5) and region(always 0)
70 Foam::pointIndexHit Foam::searchableBox::findNearest
74 const scalar nearestDistSqr
77 // Point can be inside or outside. For every component direction can be
78 // left of min, right of max or inbetween.
79 // - outside points: project first one x plane (either min().x()
80 // or max().x()), then onto y plane and finally z. You should be left
81 // with intersection point
82 // - inside point: find nearest side (compare to mid point). Project onto
85 // The face is set to the last projected face.
88 // Outside point projected onto cube. Assume faces 0..5.
89 pointIndexHit info(true, sample, -1);
92 // (for internal points) per direction what nearest cube side is
95 for (direction dir = 0; dir < vector::nComponents; dir++)
97 if (info.rawPoint()[dir] < min()[dir])
99 projectOntoCoordPlane(dir, min(), info);
102 else if (info.rawPoint()[dir] > max()[dir])
104 projectOntoCoordPlane(dir, max(), info);
107 else if (info.rawPoint()[dir] > bbMid[dir])
109 near[dir] = max()[dir];
113 near[dir] = min()[dir];
118 // For outside points the info will be correct now. Handle inside points
119 // using the three near distances. Project onto the nearest plane.
122 vector dist(cmptMag(info.rawPoint() - near));
124 if (dist.x() < dist.y())
126 if (dist.x() < dist.z())
128 // Project onto x plane
129 projectOntoCoordPlane(vector::X, near, info);
133 projectOntoCoordPlane(vector::Z, near, info);
138 if (dist.y() < dist.z())
140 projectOntoCoordPlane(vector::Y, near, info);
144 projectOntoCoordPlane(vector::Z, near, info);
150 // Check if outside. Optimisation: could do some checks on distance already
151 // on components above
152 if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
162 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
164 Foam::searchableBox::searchableBox
167 const treeBoundBox& bb
170 searchableSurface(io),
173 if (!contains(midpoint()))
177 "Foam::searchableBox::searchableBox\n"
179 " const IOobject& io,\n"
180 " const treeBoundBox& bb\n"
182 ) << "Illegal bounding box specification : "
183 << static_cast<const treeBoundBox>(*this) << exit(FatalError);
188 Foam::searchableBox::searchableBox
191 const dictionary& dict
194 searchableSurface(io),
195 treeBoundBox(dict.lookup("min"), dict.lookup("max"))
197 if (!contains(midpoint()))
201 "Foam::searchableBox::searchableBox\n"
203 " const IOobject& io,\n"
204 " const treeBoundBox& bb\n"
206 ) << "Illegal bounding box specification : "
207 << static_cast<const treeBoundBox>(*this) << exit(FatalError);
212 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
214 Foam::searchableBox::~searchableBox()
218 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
220 const Foam::wordList& Foam::searchableBox::regions() const
222 if (regions_.empty())
225 regions_[0] = "region0";
231 Foam::pointField Foam::searchableBox::coordinates() const
235 const pointField pts(treeBoundBox::points());
236 const faceList& fcs = treeBoundBox::faces;
240 ctrs[i] = fcs[i].centre(pts);
246 Foam::pointIndexHit Foam::searchableBox::findNearest
249 const scalar nearestDistSqr
252 return findNearest(midpoint(), sample, nearestDistSqr);
256 Foam::pointIndexHit Foam::searchableBox::findNearestOnEdge
259 const scalar nearestDistSqr
262 const point bbMid(midpoint());
264 // Outside point projected onto cube. Assume faces 0..5.
265 pointIndexHit info(true, sample, -1);
266 bool outside = false;
268 // (for internal points) per direction what nearest cube side is
271 for (direction dir = 0; dir < vector::nComponents; dir++)
273 if (info.rawPoint()[dir] < min()[dir])
275 projectOntoCoordPlane(dir, min(), info);
278 else if (info.rawPoint()[dir] > max()[dir])
280 projectOntoCoordPlane(dir, max(), info);
283 else if (info.rawPoint()[dir] > bbMid[dir])
285 near[dir] = max()[dir];
289 near[dir] = min()[dir];
294 // For outside points the info will be correct now. Handle inside points
295 // using the three near distances. Project onto the nearest two planes.
298 // Get the per-component distance to nearest wall
299 vector dist(cmptMag(info.rawPoint() - near));
301 SortableList<scalar> sortedDist(3);
302 sortedDist[0] = dist[0];
303 sortedDist[1] = dist[1];
304 sortedDist[2] = dist[2];
307 // Project onto nearest
308 projectOntoCoordPlane(sortedDist.indices()[0], near, info);
309 // Project onto second nearest
310 projectOntoCoordPlane(sortedDist.indices()[1], near, info);
314 // Check if outside. Optimisation: could do some checks on distance already
315 // on components above
316 if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
326 Foam::pointIndexHit Foam::searchableBox::findNearest
328 const linePointRef& ln,
329 treeBoundBox& tightest,
335 "searchableBox::findNearest"
336 "(const linePointRef&, treeBoundBox&, point&)"
338 return pointIndexHit();
342 Foam::pointIndexHit Foam::searchableBox::findLine
348 pointIndexHit info(false, start, -1);
352 if (posBits(start) == 0)
354 if (posBits(end) == 0)
356 // Both start and end inside.
361 // end is outside. Clip to bounding box.
362 foundInter = intersects(end, start, info.rawPoint());
367 // start is outside. Clip to bounding box.
368 foundInter = intersects(start, end, info.rawPoint());
377 for (direction dir = 0; dir < vector::nComponents; dir++)
379 if (info.rawPoint()[dir] == min()[dir])
381 info.setIndex(2*dir);
384 else if (info.rawPoint()[dir] == max()[dir])
386 info.setIndex(2*dir+1);
391 if (info.index() == -1)
393 FatalErrorIn("searchableBox::findLine(const point&, const point&)")
394 << "point " << info.rawPoint()
395 << " on segment " << start << end
396 << " should be on face of " << *this
397 << " but it isn't." << abort(FatalError);
405 Foam::pointIndexHit Foam::searchableBox::findLineAny
411 return findLine(start, end);
415 void Foam::searchableBox::findNearest
417 const pointField& samples,
418 const scalarField& nearestDistSqr,
419 List<pointIndexHit>& info
422 info.setSize(samples.size());
424 const point bbMid(midpoint());
428 info[i] = findNearest(bbMid, samples[i], nearestDistSqr[i]);
433 void Foam::searchableBox::findLine
435 const pointField& start,
436 const pointField& end,
437 List<pointIndexHit>& info
440 info.setSize(start.size());
444 info[i] = findLine(start[i], end[i]);
449 void Foam::searchableBox::findLineAny
451 const pointField& start,
452 const pointField& end,
453 List<pointIndexHit>& info
456 info.setSize(start.size());
460 info[i] = findLineAny(start[i], end[i]);
465 void Foam::searchableBox::findLineAll
467 const pointField& start,
468 const pointField& end,
469 List<List<pointIndexHit> >& info
472 info.setSize(start.size());
475 DynamicList<pointIndexHit, 1, 1> hits;
478 // To find all intersections we add a small vector to the last intersection
479 // This is chosen such that
480 // - it is significant (SMALL is smallest representative relative tolerance;
481 // we need something bigger since we're doing calculations)
482 // - if the start-end vector is zero we still progress
483 const vectorField dirVec(end-start);
484 const scalarField magSqrDirVec(magSqr(dirVec));
485 const vectorField smallVec
487 Foam::sqrt(SMALL)*dirVec
488 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
491 forAll(start, pointI)
493 // See if any intersection between pt and end
494 pointIndexHit inter = findLine(start[pointI], end[pointI]);
501 point pt = inter.hitPoint() + smallVec[pointI];
503 while (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
505 // See if any intersection between pt and end
506 pointIndexHit inter = findLine(pt, end[pointI]);
508 // Check for not hit or hit same face as before (can happen
509 // if vector along surface of face)
513 || (inter.index() == hits.last().index())
520 pt = inter.hitPoint() + smallVec[pointI];
523 info[pointI].transfer(hits);
527 info[pointI].clear();
533 void Foam::searchableBox::getRegion
535 const List<pointIndexHit>& info,
539 region.setSize(info.size());
544 void Foam::searchableBox::getNormal
546 const List<pointIndexHit>& info,
550 normal.setSize(info.size());
551 normal = vector::zero;
557 normal[i] = treeBoundBox::faceNormals[info[i].index()];
567 void Foam::searchableBox::getVolumeType
569 const pointField& points,
570 List<volumeType>& volType
573 volType.setSize(points.size());
576 forAll(points, pointI)
578 const point& pt = points[pointI];
580 for (direction dir = 0; dir < vector::nComponents; dir++)
582 if (pt[dir] < min()[dir] || pt[dir] > max()[dir])
584 volType[pointI] = OUTSIDE;
592 // ************************************************************************* //