1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
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 * * * * * * * * * * * * * //
35 defineTypeNameAndDebug(searchableBox, 0);
36 addToRunTimeSelectionTable(searchableSurface, searchableBox, dict);
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 void Foam::searchableBox::projectOntoCoordPlane
50 info.rawPoint()[dir] = planePt[dir];
52 if (planePt[dir] == min()[dir])
56 else if (planePt[dir] == max()[dir])
58 info.setIndex(dir*2+1);
62 FatalErrorIn("searchableBox::projectOntoCoordPlane(..)")
63 << "Point on plane " << planePt
64 << " is not on coordinate " << min()[dir]
65 << " nor " << max()[dir] << abort(FatalError);
70 // Returns miss or hit with face (0..5) and region(always 0)
71 Foam::pointIndexHit Foam::searchableBox::findNearest
75 const scalar nearestDistSqr
78 // Point can be inside or outside. For every component direction can be
79 // left of min, right of max or inbetween.
80 // - outside points: project first one x plane (either min().x()
81 // or max().x()), then onto y plane and finally z. You should be left
82 // with intersection point
83 // - inside point: find nearest side (compare to mid point). Project onto
86 // The face is set to the last projected face.
89 // Outside point projected onto cube. Assume faces 0..5.
90 pointIndexHit info(true, sample, -1);
93 // (for internal points) per direction what nearest cube side is
96 for (direction dir = 0; dir < vector::nComponents; dir++)
98 if (info.rawPoint()[dir] < min()[dir])
100 projectOntoCoordPlane(dir, min(), info);
103 else if (info.rawPoint()[dir] > max()[dir])
105 projectOntoCoordPlane(dir, max(), info);
108 else if (info.rawPoint()[dir] > bbMid[dir])
110 near[dir] = max()[dir];
114 near[dir] = min()[dir];
119 // For outside points the info will be correct now. Handle inside points
120 // using the three near distances. Project onto the nearest plane.
123 vector dist(cmptMag(info.rawPoint() - near));
125 if (dist.x() < dist.y())
127 if (dist.x() < dist.z())
129 // Project onto x plane
130 projectOntoCoordPlane(vector::X, near, info);
134 projectOntoCoordPlane(vector::Z, near, info);
139 if (dist.y() < dist.z())
141 projectOntoCoordPlane(vector::Y, near, info);
145 projectOntoCoordPlane(vector::Z, near, info);
151 // Check if outside. Optimisation: could do some checks on distance already
152 // on components above
153 if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
163 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
165 Foam::searchableBox::searchableBox
168 const treeBoundBox& bb
171 searchableSurface(io),
174 if (!contains(midpoint()))
178 "Foam::searchableBox::searchableBox\n"
180 " const IOobject& io,\n"
181 " const treeBoundBox& bb\n"
183 ) << "Illegal bounding box specification : "
184 << static_cast<const treeBoundBox>(*this) << exit(FatalError);
189 Foam::searchableBox::searchableBox
192 const dictionary& dict
195 searchableSurface(io),
196 treeBoundBox(dict.lookup("min"), dict.lookup("max"))
198 if (!contains(midpoint()))
202 "Foam::searchableBox::searchableBox\n"
204 " const IOobject& io,\n"
205 " const treeBoundBox& bb\n"
207 ) << "Illegal bounding box specification : "
208 << static_cast<const treeBoundBox>(*this) << exit(FatalError);
213 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
215 Foam::searchableBox::~searchableBox()
219 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
221 const Foam::wordList& Foam::searchableBox::regions() const
223 if (regions_.empty())
226 regions_[0] = "region0";
232 Foam::pointField Foam::searchableBox::coordinates() const
236 const pointField pts = treeBoundBox::points();
237 const faceList& fcs = treeBoundBox::faces;
241 ctrs[i] = fcs[i].centre(pts);
247 Foam::pointIndexHit Foam::searchableBox::findNearest
250 const scalar nearestDistSqr
253 return findNearest(midpoint(), sample, nearestDistSqr);
257 Foam::pointIndexHit Foam::searchableBox::findNearestOnEdge
260 const scalar nearestDistSqr
263 const point bbMid(midpoint());
265 // Outside point projected onto cube. Assume faces 0..5.
266 pointIndexHit info(true, sample, -1);
267 bool outside = false;
269 // (for internal points) per direction what nearest cube side is
272 for (direction dir = 0; dir < vector::nComponents; dir++)
274 if (info.rawPoint()[dir] < min()[dir])
276 projectOntoCoordPlane(dir, min(), info);
279 else if (info.rawPoint()[dir] > max()[dir])
281 projectOntoCoordPlane(dir, max(), info);
284 else if (info.rawPoint()[dir] > bbMid[dir])
286 near[dir] = max()[dir];
290 near[dir] = min()[dir];
295 // For outside points the info will be correct now. Handle inside points
296 // using the three near distances. Project onto the nearest two planes.
299 // Get the per-component distance to nearest wall
300 vector dist(cmptMag(info.rawPoint() - near));
302 SortableList<scalar> sortedDist(3);
303 sortedDist[0] = dist[0];
304 sortedDist[1] = dist[1];
305 sortedDist[2] = dist[2];
308 // Project onto nearest
309 projectOntoCoordPlane(sortedDist.indices()[0], near, info);
310 // Project onto second nearest
311 projectOntoCoordPlane(sortedDist.indices()[1], near, info);
315 // Check if outside. Optimisation: could do some checks on distance already
316 // on components above
317 if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
327 Foam::pointIndexHit Foam::searchableBox::findNearest
329 const linePointRef& ln,
330 treeBoundBox& tightest,
336 "searchableBox::findNearest"
337 "(const linePointRef&, treeBoundBox&, point&)"
339 return pointIndexHit();
343 Foam::pointIndexHit Foam::searchableBox::findLine
349 pointIndexHit info(false, start, -1);
353 if (posBits(start) == 0)
355 if (posBits(end) == 0)
357 // Both start and end inside.
362 // end is outside. Clip to bounding box.
363 foundInter = intersects(end, start, info.rawPoint());
368 // start is outside. Clip to bounding box.
369 foundInter = intersects(start, end, info.rawPoint());
378 for (direction dir = 0; dir < vector::nComponents; dir++)
380 if (info.rawPoint()[dir] == min()[dir])
382 info.setIndex(2*dir);
385 else if (info.rawPoint()[dir] == max()[dir])
387 info.setIndex(2*dir+1);
392 if (info.index() == -1)
394 FatalErrorIn("searchableBox::findLine(const point&, const point&)")
395 << "point " << info.rawPoint()
396 << " on segment " << start << end
397 << " should be on face of " << *this
398 << " but it isn't." << abort(FatalError);
406 Foam::pointIndexHit Foam::searchableBox::findLineAny
412 return findLine(start, end);
416 void Foam::searchableBox::findNearest
418 const pointField& samples,
419 const scalarField& nearestDistSqr,
420 List<pointIndexHit>& info
423 info.setSize(samples.size());
425 const point bbMid(midpoint());
429 info[i] = findNearest(bbMid, samples[i], nearestDistSqr[i]);
434 void Foam::searchableBox::findLine
436 const pointField& start,
437 const pointField& end,
438 List<pointIndexHit>& info
441 info.setSize(start.size());
445 info[i] = findLine(start[i], end[i]);
450 void Foam::searchableBox::findLineAny
452 const pointField& start,
453 const pointField& end,
454 List<pointIndexHit>& info
457 info.setSize(start.size());
461 info[i] = findLineAny(start[i], end[i]);
466 void Foam::searchableBox::findLineAll
468 const pointField& start,
469 const pointField& end,
470 List<List<pointIndexHit> >& info
473 info.setSize(start.size());
476 DynamicList<pointIndexHit, 1, 1> hits;
479 // To find all intersections we add a small vector to the last intersection
480 // This is chosen such that
481 // - it is significant (SMALL is smallest representative relative tolerance;
482 // we need something bigger since we're doing calculations)
483 // - if the start-end vector is zero we still progress
484 const vectorField dirVec(end-start);
485 const scalarField magSqrDirVec(magSqr(dirVec));
486 const vectorField smallVec
488 Foam::sqrt(SMALL)*dirVec
489 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
492 forAll(start, pointI)
494 // See if any intersection between pt and end
495 pointIndexHit inter = findLine(start[pointI], end[pointI]);
502 point pt = inter.hitPoint() + smallVec[pointI];
504 while (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
506 // See if any intersection between pt and end
507 pointIndexHit inter = findLine(pt, end[pointI]);
509 // Check for not hit or hit same face as before (can happen
510 // if vector along surface of face)
514 || (inter.index() == hits[hits.size()-1].index())
521 pt = inter.hitPoint() + smallVec[pointI];
524 info[pointI].transfer(hits);
528 info[pointI].clear();
534 void Foam::searchableBox::getRegion
536 const List<pointIndexHit>& info,
540 region.setSize(info.size());
545 void Foam::searchableBox::getNormal
547 const List<pointIndexHit>& info,
551 normal.setSize(info.size());
552 normal = vector::zero;
558 normal[i] = treeBoundBox::faceNormals[info[i].index()];
568 void Foam::searchableBox::getVolumeType
570 const pointField& points,
571 List<volumeType>& volType
574 volType.setSize(points.size());
577 forAll(points, pointI)
579 const point& pt = points[pointI];
581 for (direction dir = 0; dir < vector::nComponents; dir++)
583 if (pt[dir] < min()[dir] || pt[dir] > max()[dir])
585 volType[pointI] = OUTSIDE;
593 // ************************************************************************* //