1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "searchableBox.H"
28 #include "addToRunTimeSelectionTable.H"
29 #include "SortableList.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 defineTypeNameAndDebug(searchableBox, 0);
37 addToRunTimeSelectionTable(searchableSurface, searchableBox, dict);
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 void Foam::searchableBox::projectOntoCoordPlane
52 info.rawPoint()[dir] = planePt[dir];
54 if (planePt[dir] == min()[dir])
58 else if (planePt[dir] == max()[dir])
60 info.setIndex(dir*2+1);
64 FatalErrorIn("searchableBox::projectOntoCoordPlane(..)")
65 << "Point on plane " << planePt
66 << " is not on coordinate " << min()[dir]
67 << " nor " << max()[dir] << abort(FatalError);
72 // Returns miss or hit with face (0..5) and region(always 0)
73 Foam::pointIndexHit Foam::searchableBox::findNearest
77 const scalar nearestDistSqr
80 // Point can be inside or outside. For every component direction can be
81 // left of min, right of max or inbetween.
82 // - outside points: project first one x plane (either min().x()
83 // or max().x()), then onto y plane and finally z. You should be left
84 // with intersection point
85 // - inside point: find nearest side (compare to mid point). Project onto
88 // The face is set to the last projected face.
91 // Outside point projected onto cube. Assume faces 0..5.
92 pointIndexHit info(true, sample, -1);
95 // (for internal points) per direction what nearest cube side is
98 for (direction dir = 0; dir < vector::nComponents; dir++)
100 if (info.rawPoint()[dir] < min()[dir])
102 projectOntoCoordPlane(dir, min(), info);
105 else if (info.rawPoint()[dir] > max()[dir])
107 projectOntoCoordPlane(dir, max(), info);
110 else if (info.rawPoint()[dir] > bbMid[dir])
112 near[dir] = max()[dir];
116 near[dir] = min()[dir];
121 // For outside points the info will be correct now. Handle inside points
122 // using the three near distances. Project onto the nearest plane.
125 vector dist(cmptMag(info.rawPoint() - near));
127 if (dist.x() < dist.y())
129 if (dist.x() < dist.z())
131 // Project onto x plane
132 projectOntoCoordPlane(vector::X, near, info);
136 projectOntoCoordPlane(vector::Z, near, info);
141 if (dist.y() < dist.z())
143 projectOntoCoordPlane(vector::Y, near, info);
147 projectOntoCoordPlane(vector::Z, near, info);
153 // Check if outside. Optimisation: could do some checks on distance already
154 // on components above
155 if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
165 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
167 Foam::searchableBox::searchableBox
170 const treeBoundBox& bb
173 searchableSurface(io),
178 Foam::searchableBox::searchableBox
181 const dictionary& dict
184 searchableSurface(io),
185 treeBoundBox(dict.lookup("min"), dict.lookup("max"))
189 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
191 Foam::searchableBox::~searchableBox()
195 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
197 const Foam::wordList& Foam::searchableBox::regions() const
199 if (regions_.size() == 0)
202 regions_[0] = "region0";
208 Foam::pointIndexHit Foam::searchableBox::findNearest
211 const scalar nearestDistSqr
214 return findNearest(mid(), sample, nearestDistSqr);
218 Foam::pointIndexHit Foam::searchableBox::findNearestOnEdge
221 const scalar nearestDistSqr
224 const point bbMid(mid());
226 // Outside point projected onto cube. Assume faces 0..5.
227 pointIndexHit info(true, sample, -1);
228 bool outside = false;
230 // (for internal points) per direction what nearest cube side is
233 for (direction dir = 0; dir < vector::nComponents; dir++)
235 if (info.rawPoint()[dir] < min()[dir])
237 projectOntoCoordPlane(dir, min(), info);
240 else if (info.rawPoint()[dir] > max()[dir])
242 projectOntoCoordPlane(dir, max(), info);
245 else if (info.rawPoint()[dir] > bbMid[dir])
247 near[dir] = max()[dir];
251 near[dir] = min()[dir];
256 // For outside points the info will be correct now. Handle inside points
257 // using the three near distances. Project onto the nearest two planes.
260 // Get the per-component distance to nearest wall
261 vector dist(cmptMag(info.rawPoint() - near));
263 SortableList<scalar> sortedDist(3);
264 sortedDist[0] = dist[0];
265 sortedDist[1] = dist[1];
266 sortedDist[2] = dist[2];
269 // Project onto nearest
270 projectOntoCoordPlane(sortedDist.indices()[0], near, info);
271 // Project onto second nearest
272 projectOntoCoordPlane(sortedDist.indices()[1], near, info);
276 // Check if outside. Optimisation: could do some checks on distance already
277 // on components above
278 if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
288 Foam::pointIndexHit Foam::searchableBox::findNearest
290 const linePointRef& ln,
291 treeBoundBox& tightest,
297 "searchableBox::findNearest"
298 "(const linePointRef&, treeBoundBox&, point&)"
300 return pointIndexHit();
304 Foam::pointIndexHit Foam::searchableBox::findLine
310 pointIndexHit info(false, start, -1);
314 if (posBits(start) == 0)
316 if (posBits(end) == 0)
318 // Both start and end inside.
323 // end is outside. Clip to bounding box.
324 foundInter = intersects(end, start, info.rawPoint());
329 // start is outside. Clip to bounding box.
330 foundInter = intersects(start, end, info.rawPoint());
339 for (direction dir = 0; dir < vector::nComponents; dir++)
341 if (info.rawPoint()[dir] == min()[dir])
343 info.setIndex(2*dir);
346 else if (info.rawPoint()[dir] == max()[dir])
348 info.setIndex(2*dir+1);
353 if (info.index() == -1)
355 FatalErrorIn("searchableBox::findLine(const point&, const point&)")
356 << "point " << info.rawPoint()
357 << " on segment " << start << end
358 << " should be on face of " << *this
359 << " but it isn't." << abort(FatalError);
367 Foam::pointIndexHit Foam::searchableBox::findLineAny
373 return findLine(start, end);
377 void Foam::searchableBox::findNearest
379 const pointField& samples,
380 const scalarField& nearestDistSqr,
381 List<pointIndexHit>& info
384 info.setSize(samples.size());
386 const point bbMid(mid());
390 info[i] = findNearest(bbMid, samples[i], nearestDistSqr[i]);
395 void Foam::searchableBox::findLine
397 const pointField& start,
398 const pointField& end,
399 List<pointIndexHit>& info
402 info.setSize(start.size());
406 info[i] = findLine(start[i], end[i]);
411 void Foam::searchableBox::findLineAny
413 const pointField& start,
414 const pointField& end,
415 List<pointIndexHit>& info
418 info.setSize(start.size());
422 info[i] = findLineAny(start[i], end[i]);
427 void Foam::searchableBox::findLineAll
429 const pointField& start,
430 const pointField& end,
431 List<List<pointIndexHit> >& info
434 info.setSize(start.size());
437 DynamicList<pointIndexHit, 1, 1> hits;
440 // To find all intersections we add a small vector to the last intersection
441 // This is chosen such that
442 // - it is significant (SMALL is smallest representative relative tolerance;
443 // we need something bigger since we're doing calculations)
444 // - if the start-end vector is zero we still progress
445 const vectorField dirVec(end-start);
446 const scalarField magSqrDirVec(magSqr(dirVec));
447 const vectorField smallVec
449 Foam::sqrt(SMALL)*dirVec
450 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
453 forAll(start, pointI)
455 // See if any intersection between pt and end
456 pointIndexHit inter = findLine(start[pointI], end[pointI]);
463 point pt = inter.hitPoint() + smallVec[pointI];
465 while (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
467 // See if any intersection between pt and end
468 pointIndexHit inter = findLine(pt, end[pointI]);
470 // Check for not hit or hit same face as before (can happen
471 // if vector along surface of face)
475 || (inter.index() == hits[hits.size()-1].index())
482 pt = inter.hitPoint() + smallVec[pointI];
486 info[pointI].transfer(hits);
491 info[pointI].clear();
497 void Foam::searchableBox::getRegion
499 const List<pointIndexHit>& info,
503 region.setSize(info.size());
508 void Foam::searchableBox::getNormal
510 const List<pointIndexHit>& info,
514 normal.setSize(info.size());
515 normal = vector::zero;
521 normal[i] = treeBoundBox::faceNormals[info[i].index()];
531 void Foam::searchableBox::getVolumeType
533 const pointField& points,
534 List<volumeType>& volType
537 volType.setSize(points.size());
540 forAll(points, pointI)
542 const point& pt = points[pointI];
544 for (direction dir = 0; dir < vector::nComponents; dir++)
546 if (pt[dir] < min()[dir] || pt[dir] > max()[dir])
548 volType[pointI] = OUTSIDE;
556 // ************************************************************************* //